19
janvier
2012
Minifier (compresser) du code PHP 5.3+
janvier
2012
Bonjour,
J’ai eu à développer un outil qui se charge de minifier le code source d’un ou plusieurs fichiers.
Je vous propose une source PHP qui se charge de ce travail.
CODE SOURCE DE LA CLASSE
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | class PhpMinifier { /** * List of tokens that can be written without sourrounding spaces * @var array array([] => token) */ static private $noSpaces = array( T_AND_EQUAL, // &= T_ARRAY_CAST, // (array) T_BOOLEAN_AND, // && T_BOOLEAN_OR, // || T_BOOL_CAST, // (bool), (boolean) T_CASE, // case T_CLOSE_TAG, /* ?> */ T_CONCAT_EQUAL, // .= T_CONSTANT_ENCAPSED_STRING, // 'string' T_DEC, // -- (one exception, see below) T_DIV_EQUAL, // /= T_DNUMBER, // float number T_DOLLAR_OPEN_CURLY_BRACES, // ${ T_DOUBLE_ARROW, // => T_DOUBLE_CAST, // (real), (double), (float) T_DOUBLE_COLON, // :: T_INC, // ++ (one exception, see below) T_INCLUDE, // include T_INCLUDE_ONCE, // include_once T_INT_CAST, // (int), (integer) T_IS_EQUAL, // == T_IS_GREATER_OR_EQUAL, // >= T_IS_IDENTICAL, // === T_IS_NOT_EQUAL, // != or T_IS_NOT_IDENTICAL, // !== T_IS_SMALLER_OR_EQUAL, // T_OPEN_TAG_WITH_ECHO, // <?= ou <%= T_OR_EQUAL, // |= T_PAAMAYIM_NEKUDOTAYIM, // :: T_PLUS_EQUAL, // += T_REQUIRE, // require T_REQUIRE_ONCE, // require_once T_SL, // << T_SL_EQUAL, // <> T_SR_EQUAL, // >>= T_STRING_CAST, // (string) T_UNSET_CAST, // (unset) T_XOR_EQUAL // ^= ); /** * Minify PHP source code of files in the $paths argument * and store the minified code in the $outputFile argument * @param array $paths Array([] => path) * @param string $outputFile */ static function minify(array $paths, $outputFile) { $openTag = FALSE; $code = ''; foreach($paths as $path) { if (is_file($path)) { $min = self::compress($path, TRUE); if (strlen($min['code'])) { if ($openTag) { if ( ! $min['openTag']) { $code .= '?>'; $openTag = FALSE; } } else { if ($min['openTag']) { $code .= ''; } file_put_contents($outputFile, $code); } /** * @param string $path * @param bool $removeOpenCloseTags * @return array Array(openTag => bool, code => string) */ static private function compress($path, $removeOpenCloseTags = TRUE) { $src = php_strip_whitespace($path); $code = ''; $openFound = FALSE; if(empty($src)) { return array('openTag' => $openFound, 'code' => $code); } $tokens = token_get_all($src); $nb = count($tokens); $nextToken = NULL; $prevToken = NULL; $prevIsSymbol = FALSE; $prevSymbol = NULL; for($i = 0; $i < $nb; ++$i) { $token = $tokens[$i]; // symbols if ( ! is_array($token)) { $code .= $token; $prevIsSymbol = TRUE; $prevSymbol = $token; continue; } // use of named variables instead of array $token list($index, $value) = $token; if ($removeOpenCloseTags) { // ignore open token at the begining if (($i === 0) && ($index === T_OPEN_TAG)) { $openFound = TRUE; continue; } // ignore close token at the end else if (($i === $nb-1) && ($index === T_CLOSE_TAG)) { continue; } } // HEREDOC/NOWDOC syntax: go to the end of the block without compression because of some special render if ($index === T_START_HEREDOC) { $code .= $value; while(++$i < $nb) { if (is_array($tokens[$i])) { $code .= $tokens[$i][1]; if ($tokens[$i][0] === T_END_HEREDOC) { $code .= ";"; ++$i; break; } } else { $code .= $tokens[$i]; } } } // SPACE between two keywords else if ($index === T_WHITESPACE) { if ($i === 1) { continue; // sometimes space at the begining } if ($i) { $prevToken = $tokens[$i-1]; // used below } if ($i minified: $a+++$b -> error: must keep space: $a+ ++$b // case: $a - --$b => minified: $a---$b -> error: must keep space: $a- --$b if ($prevIsSymbol && is_array($nextToken)) { if (($nextToken[0] === T_INC) && ($prevSymbol === '+') || ($nextToken[0] === T_DEC) && ($prevSymbol === '-')) { $code .= $value; $prevIsSymbol = FALSE; $prevSymbol = NULL; } continue; } // if the nextToken is a symbol or is in the array of "no surrounding spaces" tags // -> ignore the current token (T_WHITSPACE) else if (( ! is_array($nextToken)) || (in_array($nextToken[0], self::$noSpaces))) { continue; } else if (is_array($nextToken)) { // special user case: compression of "else if" to "elseif" if (($nextToken[0] === T_IF) && is_array($prevToken) && ($prevToken[0] === T_ELSE)) { continue; } if (($nextToken[0] === T_VARIABLE) && (is_array($prevToken) && in_array($prevToken[0], array(T_PUBLIC, T_PROTECTED, T_PRIVATE, T_VAR, T_CASE, T_AS, T_RETURN, T_STATIC, T_ARRAY)))) { continue; } } } $code .= $value; } // if the current token is in the array of "no surrounding spaces" tags // -> keep the current token and ignore the next only if it corresponds to T_WHITESPACE else if (in_array($index, self::$noSpaces)) { $code .= $value; if ($i $openFound, 'code' => $code); } } ?> |
ton code marche pas (enfin incomplet :/)
Changement de licence en LGPLv3 en lieu et place de la précédente GPLv3