See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Moodle implementation of SCSS. 19 * 20 * @package core 21 * @copyright 2016 Frédéric Massart 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 defined('MOODLE_INTERNAL') || die(); 26 27 /** 28 * Moodle SCSS compiler class. 29 * 30 * @package core 31 * @copyright 2016 Frédéric Massart 32 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 33 */ 34 class core_scss extends \ScssPhp\ScssPhp\Compiler { 35 36 /** @var string The path to the SCSS file. */ 37 protected $scssfile; 38 /** @var array Bits of SCSS content to prepend. */ 39 protected $scssprepend = array(); 40 /** @var array Bits of SCSS content. */ 41 protected $scsscontent = array(); 42 43 /** 44 * Add variables. 45 * 46 * @param array $scss Associative array of variables and their values. 47 * @return void 48 */ 49 public function add_variables(array $variables) { 50 $this->setVariables($variables); 51 } 52 53 /** 54 * Append raw SCSS to what's to compile. 55 * 56 * @param string $scss SCSS code. 57 * @return void 58 */ 59 public function append_raw_scss($scss) { 60 $this->scsscontent[] = $scss; 61 } 62 63 /** 64 * Prepend raw SCSS to what's to compile. 65 * 66 * @param string $scss SCSS code. 67 * @return void 68 */ 69 public function prepend_raw_scss($scss) { 70 $this->scssprepend[] = $scss; 71 } 72 73 /** 74 * Set the file to compile from. 75 * 76 * The purpose of this method is to provide a way to import the 77 * content of a file without messing with the import directories. 78 * 79 * @param string $filepath The path to the file. 80 * @return void 81 */ 82 public function set_file($filepath) { 83 $this->scssfile = $filepath; 84 $this->setImportPaths([dirname($filepath)]); 85 } 86 87 /** 88 * Compiles to CSS. 89 * 90 * @return string 91 */ 92 public function to_css() { 93 $content = implode(';', $this->scssprepend); 94 if (!empty($this->scssfile)) { 95 $content .= file_get_contents($this->scssfile); 96 } 97 $content .= implode(';', $this->scsscontent); 98 return $this->compile($content); 99 } 100 101 /** 102 * Compile scss. 103 * 104 * Overrides ScssPHP's implementation, using the SassC compiler if it is available. 105 * 106 * @param string $code SCSS to compile. 107 * @param string $path Path to SCSS to compile. 108 * 109 * @return string The compiled CSS. 110 */ 111 public function compile($code, $path = null) { 112 global $CFG; 113 114 $pathtosassc = trim($CFG->pathtosassc ?? ''); 115 116 if (!empty($pathtosassc) && is_executable($pathtosassc) && !is_dir($pathtosassc)) { 117 $process = proc_open( 118 $pathtosassc . ' -I' . implode(':', $this->importPaths) . ' -s', 119 [ 120 ['pipe', 'r'], // Set the process stdin pipe to read mode. 121 ['pipe', 'w'], // Set the process stdout pipe to write mode. 122 ['pipe', 'w'] // Set the process stderr pipe to write mode. 123 ], 124 $pipes // Pipes become available in $pipes (pass by reference). 125 ); 126 if (is_resource($process)) { 127 fwrite($pipes[0], $code); // Write the raw scss to the sassc process stdin. 128 fclose($pipes[0]); 129 130 $stdout = stream_get_contents($pipes[1]); 131 $stderr = stream_get_contents($pipes[2]); 132 133 fclose($pipes[1]); 134 fclose($pipes[2]); 135 136 // The proc_close function returns the process exit status. Anything other than 0 is bad. 137 if (proc_close($process) !== 0) { 138 throw new coding_exception($stderr); 139 } 140 141 // Compiled CSS code will be available from stdout. 142 return $stdout; 143 } 144 } 145 146 return $this->compileString($code, $path)->getCss(); 147 } 148 149 /** 150 * Compile child; returns a value to halt execution 151 * 152 * @param array $child 153 * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out 154 * 155 * @return array|null 156 */ 157 protected function compileChild($child, \ScssPhp\ScssPhp\Formatter\OutputBlock $out) { 158 switch($child[0]) { 159 case \ScssPhp\ScssPhp\Type::T_SCSSPHP_IMPORT_ONCE: 160 case \ScssPhp\ScssPhp\Type::T_IMPORT: 161 list(, $rawpath) = $child; 162 $rawpath = $this->reduce($rawpath); 163 $path = $this->compileStringContent($rawpath); 164 165 // We need to find the import path relative to the directory of the currently processed file. 166 $currentdirectory = new ReflectionProperty(\ScssPhp\ScssPhp\Compiler::class, 'currentDirectory'); 167 $currentdirectory->setAccessible(true); 168 169 if ($path = $this->findImport($path, $currentdirectory->getValue($this))) { 170 if ($this->is_valid_file($path)) { 171 return parent::compileChild($child, $out); 172 } else { 173 // Sneaky stuff, don't let non scss file in. 174 debugging("Can't import scss file - " . $path, DEBUG_DEVELOPER); 175 } 176 } 177 break; 178 default: 179 return parent::compileChild($child, $out); 180 } 181 } 182 183 /** 184 * Is the given file valid for import ? 185 * 186 * @param $path 187 * @return bool 188 */ 189 protected function is_valid_file($path) { 190 global $CFG; 191 192 $realpath = realpath($path); 193 194 // Additional theme directory. 195 $addthemedirectory = core_component::get_plugin_types()['theme']; 196 $addrealroot = realpath($addthemedirectory); 197 198 // Original theme directory. 199 $themedirectory = $CFG->dirroot . "/theme"; 200 $realroot = realpath($themedirectory); 201 202 // File should end in .scss and must be in sites theme directory, else ignore it. 203 $pathvalid = $realpath !== false; 204 $pathvalid = $pathvalid && (substr($path, -5) === '.scss'); 205 $pathvalid = $pathvalid && (strpos($realpath, $realroot) === 0 || strpos($realpath, $addrealroot) === 0); 206 return $pathvalid; 207 } 208 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body