Created
July 11, 2019 04:37
-
-
Save dogeow/abc67955bed34bfcfa90aaf3d221c975 to your computer and use it in GitHub Desktop.
PHP转换 JavaScript 中规则为 String(!![])+(1+[])
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* | |
JavaScript 表达式,如下: | |
String((((![]+!![])+(!![]-!+[]+[]))/(!+[]-![]+!![]-!+[]+!![]-[]-![]-[])))+(((![]+!![])+(!![]-!+[]+[]))/(!+[]-![]+!![]-!+[]+!![]-[]-![]-[])) | |
结构是:String(...)+(...),为字符串拼接,所以我们要依次获取左右两边的表达式,然后替换「[]」之类的为数字进行运算 | |
注意:偶尔 (...) 里面的也是字符串拼接,所以需要判断。比如 1+[] 的结果就是字符串 "1" | |
*/ | |
// HTML 源码里面的 JavaScript 代码片段 | |
$html = 'String((((![]+!![])+(!![]-!+[]+[]))/(!+[]-![]+!![]-!+[]+!![]-[]-![]-[])))+(((![]+!![])+(!![]-!+[]+[]))/(!+[]-![]+!![]-!+[]+!![]-[]-![]-[]))'; | |
if (preg_match('/String(.*)/', $html, $match)) { | |
$string = $match[1]; // 去掉 String | |
} | |
// 拆分 「String(...)+(...)」 | |
$pos = getPos($string, 0); | |
$a = substr($string, 0, $pos + 1); | |
$b = substr($string, $pos + 2); | |
// 删掉「String()」的「()」 | |
$a = substr($a, 1, -1); | |
resolve($a); // 解析器 | |
cal($a); // 解析器迭代完后,计算被拆分表达式左右两边的结果 | |
$a = eval("return $a[0]$a[2]$a[1];"); // 两边表达式运算 | |
resolve($b); | |
cal($b); | |
$b = eval("return $b[0]$b[2]$b[1];"); | |
echo $a . $b; | |
/** | |
* 加减乘除、拼接 | |
* 计算完,替换数组为结果 | |
* | |
* @param $array array 表达式解析完后的数组 | |
*/ | |
function cal(&$array) | |
{ | |
if (is_array($array)) { | |
foreach ($array as $key => &$v) { | |
cal($v); | |
if (is_array($v)) { | |
$a = toNumber(serialize($v[0])); | |
$b = toNumber(serialize($v[1])); | |
$array[0] = $a . $b; | |
} | |
} | |
} else { | |
if (!in_array($array, ['/', '*', '-', '+'])) { | |
$array = toNumber(serialize($array)); | |
} | |
} | |
} | |
/** | |
* 表达式解析 | |
* 遇到字符串拼接的才会拆分,不是的话,直接 eval() 计算结果 | |
* 拆分的话,替换字符串为数组存储起来 | |
* | |
* @param $array String 表达式,比如「(!![]+![])」 | |
*/ | |
function resolve(&$array) | |
{ | |
// 第一次 | |
if (!is_array($array)) { | |
$pos = getPos($array); | |
$array = array( | |
substr($array, 1, $pos), | |
substr($array, $pos + 2, -1), | |
$array[$pos + 1] | |
); | |
resolve($array); | |
} else { | |
if (strpos($array[0], ']+[]') !== false) { | |
$pos = getPos($array[0]); | |
if ($pos) { | |
$array[0] = array( | |
substr($array[0], 1, $pos), | |
substr($array[0], $pos + 2, -1), | |
$array[0][$pos + 1] | |
); | |
resolve($array[0]); // 迭代 | |
} | |
} | |
if (strpos($array[1], ']+[]') !== false) { | |
$pos = getPos($array[1]); | |
if ($pos) { | |
$array[1] = array( | |
substr($array[1], 1, $pos), | |
substr($array[1], $pos + 2, -1), | |
$array[1][$pos + 1] | |
); | |
resolve($array[1]); // 迭代 | |
} | |
} | |
} | |
} | |
/** | |
* 转换为字符串并运算结果 | |
* 「!![]」 转换为 「1」等等,然后加减乘除 | |
* | |
* @param string $string JavaScript 表达式 | |
* @return int | |
*/ | |
function toNumber($string) | |
{ | |
$string = unserialize($string); | |
$string = str_replace('!![]', 1, $string); | |
$string = str_replace('!-[]', 1, $string); | |
$string = str_replace('!+[]', 1, $string); | |
$string = str_replace('![]', 0, $string); | |
$string = str_replace('+[]', null, $string); | |
$string = str_replace('-[]', '-0', $string); | |
return eval("return {$string};"); | |
} | |
/** | |
* 获取「()」的最后位置 | |
* | |
* @param string $string JavaScript 表达式 | |
* @param int $sub 拆分表达式的话,需要减 1;不拆分不用。 | |
* @return int | |
*/ | |
function getPos($string, $sub = 1) | |
{ | |
$pos = null; | |
$array = str_split($string); | |
if ($array[1] !== '(') { // 拆分到开头只剩下一个 「(」 不再拆分 | |
return null; | |
} | |
// 开头连续几个「(」 | |
$total = charContinuousCount($array, '('); | |
// 几个「(」需要几个「)」来匹配,如果是拆分表达式,最外层右边的「)」的不用匹配,所以减 1 | |
$remaining = $total - $sub; | |
foreach ($array as $key => $v) { | |
// 从不是「(」的开始算 | |
if ($key < $total) { | |
continue; | |
} | |
if ($v === ')') { | |
$remaining--; | |
if ($remaining === 0) { | |
$pos = $key; | |
break; | |
} | |
} elseif ($v === '(') { | |
$remaining++; | |
} | |
} | |
return $pos; | |
} | |
/** | |
* 字符连续几个 | |
* | |
* @param $array | |
* @param string $char 需要判定的字符 | |
* @return int | |
*/ | |
function charContinuousCount($array, $char) | |
{ | |
$total = 0; | |
foreach ($array as $v) { | |
if ($v === $char) { | |
$total++; | |
} else { | |
break; | |
} | |
} | |
return $total; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment