支持评估的preg_replace垫片
这是非常不可取的。但是,如果你不是程序员,或者真的更喜欢糟糕的代码,你可以使用一个替代函数来保持你的标志暂时工作。preg_replace
/e
/**
* Can be used as a stopgap shim for preg_replace() calls with /e flag.
* Is likely to fail for more complex string munging expressions. And
* very obviously won't help with local-scope variable expressions.
*
* @license: CC-BY-*.*-comment-must-be-retained
* @security: Provides `eval` support for replacement patterns. Which
* poses troubles for user-supplied input when paired with overly
* generic placeholders. This variant is only slightly stricter than
* the C implementation, but still susceptible to varexpression, quote
* breakouts and mundane exploits from unquoted capture placeholders.
* @url: https://stackoverflow.com/q/15454220
*/
function preg_replace_eval($pattern, $replacement, $subject, $limit=-1) {
# strip /e flag
$pattern = preg_replace('/(\W[a-df-z]*)e([a-df-z]*)$/i', '$1$2', $pattern);
# warn about most blatant misuses at least
if (preg_match('/\(\.[+*]/', $pattern)) {
trigger_error("preg_replace_eval(): regex contains (.*) or (.+) placeholders, which easily causes security issues for unconstrained/user input in the replacement expression. Transform your code to use preg_replace_callback() with a sane replacement callback!");
}
# run preg_replace with eval-callback
return preg_replace_callback(
$pattern,
function ($matches) use ($replacement) {
# substitute $1/$2/… with literals from $matches[]
$repl = preg_replace_callback(
'/(?<!\\\\)(?:[$]|\\\\)(\d+)/',
function ($m) use ($matches) {
if (!isset($matches[$m[1]])) { trigger_error("No capture group for '$m[0]' eval placeholder"); }
return addcslashes($matches[$m[1]], '\"\'\`\$\\\0'); # additionally escapes '$' and backticks
},
$replacement
);
# run the replacement expression
return eval("return $repl;");
},
$subject,
$limit
);
}
实质上,您只需将该函数包含在代码库中,然后编辑到使用标志的位置。preg_replace
preg_replace_eval
/e
优点和缺点:
- 实际上只是用Stack Overflow的几个样本进行了测试。
- 仅支持简单情况(函数调用,不支持变量查找)。
- 包含一些其他限制和咨询通知。
- 将产生错位和难以理解的表达式失败错误。
- 但是,仍然是一个可用的临时解决方案,并且不会使适当的过渡到 .
preg_replace_callback
- 许可证评论只是为了阻止人们过度使用或传播得太远。
替换代码生成器
现在这有点多余。但可能会帮助那些仍然不知所措的用户手动重构代码以preg_replace_callback
。虽然这实际上更耗时,但代码生成器将替换字符串扩展为表达式的麻烦较少。这是一个非常不起眼的转换,但对于最普遍的例子来说可能就足够了。/e
要使用此函数,请将任何中断的调用编辑并运行一次。这将打印出相应的块以用于其位置。preg_replace
preg_replace_eval_replacement
preg_replace_callback
/**
* Use once to generate a crude preg_replace_callback() substitution. Might often
* require additional changes in the `return …;` expression. You'll also have to
* refit the variable names for input/output obviously.
*
* >>> preg_replace_eval_replacement("/\w+/", 'strtopupper("$1")', $ignored);
*/
function preg_replace_eval_replacement($pattern, $replacement, $subjectvar="IGNORED") {
$pattern = preg_replace('/(\W[a-df-z]*)e([a-df-z]*)$/i', '$1$2', $pattern);
$replacement = preg_replace_callback('/[\'\"]?(?<!\\\\)(?:[$]|\\\\)(\d+)[\'\"]?/', function ($m) { return "\$m[{$m[1]}]"; }, $replacement);
$ve = "var_export";
$bt = debug_backtrace(0, 1)[0];
print "<pre><code>
#----------------------------------------------------
# replace preg_*() call in '$bt[file]' line $bt[line] with:
#----------------------------------------------------
\$OUTPUT_VAR = preg_replace_callback(
{$ve($pattern, TRUE)},
function (\$m) {
return {$replacement};
},
\$YOUR_INPUT_VARIABLE_GOES_HERE
)
#----------------------------------------------------
</code></pre>\n";
}
请记住,仅仅复制和粘贴不是编程。您必须根据实际的输入/输出变量名称或使用上下文调整生成的代码。
- 具体而言,如果在 中使用了上一个调用,则必须进行分配。
$OUTPUT =
preg_replace
if
- 不过,最好保留临时变量或多行代码块结构。
替换表达式可能需要更多的可读性改进或返工。
- 例如,在文字表达式中经常变得多余。
stripslashes()
- 变量范围查找需要回调中的或引用。
use
global
- 不均匀的引号括起来的捕获引用最终将被转换为 的普通转换在语法上打破。
"-$1-$2"
"-$m[1]-$m[2]
代码输出只是一个起点。是的,作为在线工具,这将更有用。这种代码重写方法(编辑,运行,编辑,编辑)有点不切实际。然而,对于那些习惯于以任务为中心的编码(更多步骤,更多未发现)的人来说,可能更平易近人。因此,这种替代方案可能会减少一些重复的问题。