]> git.joonet.de Git - adminer.git/commitdiff
Compile: Add tests for php_shrink
authorJakub Vrana <jakub@vrana.cz>
Wed, 12 Mar 2025 22:05:50 +0000 (23:05 +0100)
committerJakub Vrana <jakub@vrana.cz>
Wed, 12 Mar 2025 22:15:22 +0000 (23:15 +0100)
compile.php
php_shrink.inc.php [new file with mode: 0644]
tests/php_shrink.php [new file with mode: 0644]

index b56c676f7dc9befa8ce750a1bc2b827e0bdeee59..0dcfc0f042ba7412ab1afe3650234a4d092b63e2 100755 (executable)
@@ -2,12 +2,9 @@
 <?php
 include __DIR__ . "/adminer/include/version.inc.php";
 include __DIR__ . "/adminer/include/errors.inc.php";
+include __DIR__ . "/php_shrink.inc.php";
 include __DIR__ . "/externals/JsShrink/jsShrink.php";
 
-function add_apo_slashes($s) {
-       return addcslashes($s, "\\'");
-}
-
 function add_quo_slashes($s) {
        $return = $s;
        $return = addcslashes($return, "\n\r\$\"\\");
@@ -212,127 +209,6 @@ if (!$translations) {
 ';
 }
 
-function short_identifier($number, $chars) {
-       $return = '';
-       while ($number >= 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 (file)
index 0000000..f129a25
--- /dev/null
@@ -0,0 +1,132 @@
+<?php
+
+// based on http://latrine.dgx.cz/jak-zredukovat-php-skripty
+function php_shrink($input) {
+       $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;
+                       }
+                       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 (file)
index 0000000..5ec303e
--- /dev/null
@@ -0,0 +1,23 @@
+<?php
+include __DIR__ . "/../adminer/include/errors.inc.php";
+include __DIR__ . "/../php_shrink.inc.php";
+
+function check($code, $expected) {
+       $shrinked = php_shrink("<?php\n$code");
+       if ("<?php\n" . str_replace(" ", "\n", $expected) . "" != $shrinked) {
+               $backtrace = reset(debug_backtrace());
+               echo "$backtrace[file]:$backtrace[line]:" . str_replace("\n", " ", substr($shrinked, 6)) . "\n";
+       }
+}
+
+check('$ab = 1;', '$a=1;');
+check('function f($ab, $cd = 1) { return $ab; }', 'function f($a,$b=1){return$a;}');
+check('class C { var $ab = 1; }', 'class C{var$ab=1;}');
+check('class C { public $ab = 1; }', 'class C{var$ab=1;}');
+check('class C { protected $ab = 1; }', 'class C{protected$ab=1;}');
+check('class C { private $ab = 1; }', 'class C{private$ab=1;}');
+check('class C { private $ab = 1; }', 'class C{private$ab=1;}');
+check('class C { private function f($ab) { return $ab; }}', 'class C{private function f($a){return$a;}}');
+check('class C { public function f($ab) { return $ab; }}', 'class C{function f($a){return$a;}}');
+check('class C { private static $ab; }', 'class C{private static$ab;}');
+check('new \stdClass;', 'new \stdClass;');