From 4a6436773fa9f98b8700df40f307281af1f87232 Mon Sep 17 00:00:00 2001 From: Jakub Vrana Date: Wed, 12 Mar 2025 23:05:50 +0100 Subject: [PATCH] Compile: Add tests for php_shrink --- compile.php | 135 +------------------------------------------ php_shrink.inc.php | 132 ++++++++++++++++++++++++++++++++++++++++++ tests/php_shrink.php | 23 ++++++++ 3 files changed, 157 insertions(+), 133 deletions(-) create mode 100644 php_shrink.inc.php create mode 100644 tests/php_shrink.php diff --git a/compile.php b/compile.php index b56c676f..0dcfc0f0 100755 --- a/compile.php +++ b/compile.php @@ -2,12 +2,9 @@ = 0) { - $return .= $chars[$number % strlen($chars)]; - $number = floor($number / strlen($chars)) - 1; - } - return $return; -} - -// based on http://latrine.dgx.cz/jak-zredukovat-php-skripty -function php_shrink($input) { - global $VERSION; - $special_variables = array_flip(array('$this', '$GLOBALS', '$_GET', '$_POST', '$_FILES', '$_COOKIE', '$_SESSION', '$_SERVER', '$http_response_header', '$php_errormsg')); - $short_variables = array(); - $shortening = true; - $tokens = token_get_all($input); - - // remove unnecessary { } - //! change also `while () { if () {;} }` to `while () if () ;` but be careful about `if () { if () { } } else { } - $shorten = 0; - $opening = -1; - foreach ($tokens as $i => $token) { - if (in_array($token[0], array(T_IF, T_ELSE, T_ELSEIF, T_WHILE, T_DO, T_FOR, T_FOREACH), true)) { - $shorten = ($token[0] == T_FOR ? 4 : 2); - $opening = -1; - } elseif (in_array($token[0], array(T_SWITCH, T_FUNCTION, T_CLASS, T_CLOSE_TAG), true)) { - $shorten = 0; - } elseif ($token === ';') { - $shorten--; - } elseif ($token === '{') { - if ($opening < 0) { - $opening = $i; - } elseif ($shorten > 1) { - $shorten = 0; - } - } elseif ($token === '}' && $opening >= 0 && $shorten == 1) { - unset($tokens[$opening]); - unset($tokens[$i]); - $shorten = 0; - $opening = -1; - } - } - $tokens = array_values($tokens); - - foreach ($tokens as $i => $token) { - if ($token[0] === T_VARIABLE && !isset($special_variables[$token[1]])) { - $short_variables[$token[1]]++; - } - } - - arsort($short_variables); - $chars = implode(range('a', 'z')) . '_' . implode(range('A', 'Z')); - // preserve variable names between versions if possible - $short_variables2 = array_splice($short_variables, strlen($chars)); - ksort($short_variables); - ksort($short_variables2); - $short_variables += $short_variables2; - foreach (array_keys($short_variables) as $number => $key) { - $short_variables[$key] = short_identifier($number, $chars); // could use also numbers and \x7f-\xff - } - - $set = array_flip(preg_split('//', '!"#$%&\'()*+,-./:;<=>?@[]^`{|}')); - $space = ''; - $output = ''; - $in_echo = false; - $doc_comment = false; // include only first /** - for (reset($tokens); list($i, $token) = each($tokens);) { - if (!is_array($token)) { - $token = array(0, $token); - } - if ( - $tokens[$i+2][0] === T_CLOSE_TAG && $tokens[$i+3][0] === T_INLINE_HTML && $tokens[$i+4][0] === T_OPEN_TAG - && strlen(add_apo_slashes($tokens[$i+3][1])) < strlen($tokens[$i+3][1]) + 3 - ) { - $tokens[$i+2] = array(T_ECHO, 'echo'); - $tokens[$i+3] = array(T_CONSTANT_ENCAPSED_STRING, "'" . add_apo_slashes($tokens[$i+3][1]) . "'"); - $tokens[$i+4] = array(0, ';'); - } - if ($token[0] == T_COMMENT || $token[0] == T_WHITESPACE || ($token[0] == T_DOC_COMMENT && $doc_comment)) { - $space = "\n"; - } else { - if ($token[0] == T_DOC_COMMENT) { - $doc_comment = true; - $token[1] = substr_replace($token[1], "* @version $VERSION\n", -2, 0); - } - if ($token[0] == T_VAR || $token[0] == T_PUBLIC || $token[0] == T_PROTECTED || $token[0] == T_PRIVATE) { - if ($token[0] == T_PUBLIC && $tokens[$i+2][1][0] == '$') { - $token[1] = 'var'; - } - $shortening = false; - } elseif (!$shortening) { - if ($token[1] == ';' || $token[0] == T_FUNCTION) { - $shortening = true; - } - } elseif ($token[0] == T_ECHO) { - $in_echo = true; - } elseif ($token[1] == ';' && $in_echo) { - if ($tokens[$i+1][0] === T_WHITESPACE && $tokens[$i+2][0] === T_ECHO) { - next($tokens); - $i++; - } - if ($tokens[$i+1][0] === T_ECHO) { - // join two consecutive echos - next($tokens); - $token[1] = ','; // '.' would conflict with "a".1+2 and would use more memory //! remove ',' and "," but not $var"," - } else { - $in_echo = false; - } - } elseif ($token[0] === T_VARIABLE && !isset($special_variables[$token[1]])) { - $token[1] = '$' . $short_variables[$token[1]]; - } - if (isset($set[substr($output, -1)]) || isset($set[$token[1][0]])) { - $space = ''; - } - $output .= $space . $token[1]; - $space = ''; - } - } - return $output; -} - function minify_css($file) { return lzw_compress(preg_replace('~\s*([:;{},])\s*~', '\1', preg_replace('~/\*.*\*/~sU', '', $file))); } @@ -359,14 +235,6 @@ function compile_file($match) { return '"' . add_quo_slashes($file) . '"'; } -if (!function_exists("each")) { - function each(&$arr) { - $key = key($arr); - next($arr); - return $key === null ? false : array($key, $arr[$key]); - } -} - function min_version() { return true; } @@ -414,6 +282,7 @@ include __DIR__ . "/adminer/include/driver.inc.php"; $features = array("check", "call" => "routine", "dump", "event", "privileges", "procedure" => "routine", "processlist", "routine", "scheme", "sequence", "status", "trigger", "type", "user" => "privileges", "variables", "view"); $lang_ids = array(); // global variable simplifies usage in a callback function $file = file_get_contents(__DIR__ . "/$project/index.php"); +$file = preg_replace('~\*/~', "* @version $VERSION\n*/", $file, 1); if ($driver) { $_GET[$driver] = true; // to load the driver include_once __DIR__ . $driver_path; diff --git a/php_shrink.inc.php b/php_shrink.inc.php new file mode 100644 index 00000000..f129a250 --- /dev/null +++ b/php_shrink.inc.php @@ -0,0 +1,132 @@ + $token) { + if (in_array($token[0], array(T_IF, T_ELSE, T_ELSEIF, T_WHILE, T_DO, T_FOR, T_FOREACH), true)) { + $shorten = ($token[0] == T_FOR ? 4 : 2); + $opening = -1; + } elseif (in_array($token[0], array(T_SWITCH, T_FUNCTION, T_CLASS, T_CLOSE_TAG), true)) { + $shorten = 0; + } elseif ($token === ';') { + $shorten--; + } elseif ($token === '{') { + if ($opening < 0) { + $opening = $i; + } elseif ($shorten > 1) { + $shorten = 0; + } + } elseif ($token === '}' && $opening >= 0 && $shorten == 1) { + unset($tokens[$opening]); + unset($tokens[$i]); + $shorten = 0; + $opening = -1; + } + } + $tokens = array_values($tokens); + + foreach ($tokens as $i => $token) { + if ($token[0] === T_VARIABLE && !isset($special_variables[$token[1]])) { + $short_variables[$token[1]]++; + } + } + + arsort($short_variables); + $chars = implode(range('a', 'z')) . '_' . implode(range('A', 'Z')); + // preserve variable names between versions if possible + $short_variables2 = array_splice($short_variables, strlen($chars)); + ksort($short_variables); + ksort($short_variables2); + $short_variables += $short_variables2; + foreach (array_keys($short_variables) as $number => $key) { + $short_variables[$key] = short_identifier($number, $chars); // could use also numbers and \x7f-\xff + } + + $set = array_flip(preg_split('//', '!"#$%&\'()*+,-./:;<=>?@[]^`{|}')); + $space = ''; + $output = ''; + $in_echo = false; + $doc_comment = false; // include only first /** + for (reset($tokens); list($i, $token) = each($tokens);) { + if (!is_array($token)) { + $token = array(0, $token); + } + if ( + $tokens[$i+2][0] === T_CLOSE_TAG && $tokens[$i+3][0] === T_INLINE_HTML && $tokens[$i+4][0] === T_OPEN_TAG + && strlen(add_apo_slashes($tokens[$i+3][1])) < strlen($tokens[$i+3][1]) + 3 + ) { + $tokens[$i+2] = array(T_ECHO, 'echo'); + $tokens[$i+3] = array(T_CONSTANT_ENCAPSED_STRING, "'" . add_apo_slashes($tokens[$i+3][1]) . "'"); + $tokens[$i+4] = array(0, ';'); + } + if ($token[0] == T_COMMENT || $token[0] == T_WHITESPACE || ($token[0] == T_DOC_COMMENT && $doc_comment)) { + $space = "\n"; + } else { + if ($token[0] == T_DOC_COMMENT) { + $doc_comment = true; + } + if ($token[0] == T_VAR || $token[0] == T_PUBLIC || $token[0] == T_PROTECTED || $token[0] == T_PRIVATE) { + if ($token[0] == T_PUBLIC && $tokens[$i+2][1][0] == '$') { + $token[1] = 'var'; + } + $shortening = false; + } elseif (!$shortening) { + if ($token[1] == ';' || $token[0] == T_FUNCTION) { + $shortening = true; + } + } elseif ($token[0] == T_ECHO) { + $in_echo = true; + } elseif ($token[1] == ';' && $in_echo) { + if ($tokens[$i+1][0] === T_WHITESPACE && $tokens[$i+2][0] === T_ECHO) { + next($tokens); + $i++; + } + if ($tokens[$i+1][0] === T_ECHO) { + // join two consecutive echos + next($tokens); + $token[1] = ','; // '.' would conflict with "a".1+2 and would use more memory //! remove ',' and "," but not $var"," + } else { + $in_echo = false; + } + } elseif ($token[0] === T_VARIABLE && !isset($special_variables[$token[1]])) { + $token[1] = '$' . $short_variables[$token[1]]; + } + if (isset($set[substr($output, -1)]) || isset($set[$token[1][0]])) { + $space = ''; + } + $output .= $space . $token[1]; + $space = ''; + } + } + return $output; +} + +function short_identifier($number, $chars) { + $return = ''; + while ($number >= 0) { + $return .= $chars[$number % strlen($chars)]; + $number = floor($number / strlen($chars)) - 1; + } + return $return; +} + +function add_apo_slashes($s) { + return addcslashes($s, "\\'"); +} + +if (!function_exists("each")) { + function each(&$arr) { + $key = key($arr); + next($arr); + return $key === null ? false : array($key, $arr[$key]); + } +} diff --git a/tests/php_shrink.php b/tests/php_shrink.php new file mode 100644 index 00000000..5ec303e1 --- /dev/null +++ b/tests/php_shrink.php @@ -0,0 +1,23 @@ +