php-compressor をちゃんと動くようにする
PHP ソースコードの難読化ツール php-compressor がたまにうまく動かないので修正した。
php-compressor の紹介と、ほかのツールとの比較はこちら。
問題点
クラス内で関数定義以降に変数定義があると、その変数名まで短縮されてしまう。
<?php class Hoge { private function oops() {} public $pub = 'public'; protected $pro = 'protected'; private $pri = 'private'; private static $sta = 'static'; public function piyo() { static $lst = 'static in function'; $local = 'local'; $this->pub; $this->pro; $this->pri; self::$static; $local; $lst; } } -> class Hoge{private function oops(){}var$F='public';protected$E='protected';private$D='private';private static$C='static';function piyo(){static$A='static in function';$B='local';$this->pub;$this->pro;$this->pri;self::$static;$B;$A;}}
問題となる書きかたはあまりいい書きかたではないが、コードが動かなくなるよりいい。
解決策
is_class_scope() の判定に問題があるので、このロジックを変更する。compressor.php の shrink_var_names() を次のように書き換えればよい。
private function shrink_var_names() { $stat = array(); $indices = array(); $is_class_scope = false; $class_scope_level = 0; for($i = 0; $i < count($this->tokens); $i++) { list($type, $text) = $this->tokens[$i]; if ($type === T_CLASS) { $is_class_scope = true; continue; } if ($is_class_scope) { if ($text === '{' || $text === '(') { $class_scope_level++; } else if ($text === '}' || $text === ')') { $class_scope_level--; if ($class_scope_level === 0) { $is_class_scope = false; } } } if($type != T_VARIABLE) continue; if(isset(self::$RESERVED_VARS[$text])) continue; if($i > 0) { $prev_type = $this->tokens[$i - 1][0]; if($prev_type == T_DOUBLE_COLON) continue; if($class_scope_level === 1) continue; } $indices[] = $i; if(!isset($stat[$text])) $stat[$text] = 0; $stat[$text]++; } arsort($stat); $aliases = array(); $i = 0; foreach(array_keys($stat) as $name) { $aliases[$name] = $this->encode_id($i); $i++; } unset($stat); foreach($indices as $index) { $name = $this->tokens[$index][1]; $this->tokens[$index][1] = '$' . $aliases[$name]; } }