preg_replace shim mit eval support
Dies ist sehr nicht ratsam. Aber wenn Sie kein Programmierer sind oder wirklich schrecklichen Code bevorzugen, können Sie eine Ersatzfunktion preg_replace
verwenden, um Ihre /e
Flagge vorübergehend funktionsfähig zu halten .
/**
* 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
);
}
Im Wesentlichen fügen Sie diese Funktion einfach in Ihre Codebasis ein und bearbeiten preg_replace
sie preg_replace_eval
dort , wo das /e
Flag verwendet wurde.
Vor- und Nachteile :
- Wirklich nur mit ein paar Proben von Stack Overflow getestet.
- Unterstützt nur die einfachen Fälle (Funktionsaufrufe, keine variablen Suchvorgänge).
- Enthält einige weitere Einschränkungen und Hinweise.
- Ergibt dislozierte und weniger verständliche Fehler bei Ausdrucksfehlern.
- Es ist jedoch immer noch eine brauchbare temporäre Lösung und erschwert keinen ordnungsgemäßen Übergang zu
preg_replace_callback
.
- Und der Lizenzkommentar soll die Leute nur davon abhalten, dies zu überbeanspruchen oder zu weit zu verbreiten.
Ersatzcode-Generator
Das ist jetzt etwas überflüssig. Könnte aber den Benutzern helfen, die immer noch mit der manuellen Umstrukturierung ihres Codes überfordert sind preg_replace_callback
. Während dies effektiv zeitaufwändiger ist, hat ein Codegenerator weniger Probleme, die /e
Ersatzzeichenfolge in einen Ausdruck zu erweitern. Es ist eine sehr unauffällige Konvertierung, die aber wahrscheinlich für die am weitesten verbreiteten Beispiele ausreicht.
Um diese Funktion zu verwenden, bearbeiten Sie einen unterbrochenen preg_replace
Anruf in preg_replace_eval_replacement
und führen Sie ihn einmal aus . Dies wird auszudrucken den entsprechenden preg_replace_callback
Block an seiner Stelle verwendet werden.
/**
* 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";
}
Denken Sie daran, dass das bloße Kopieren und Einfügen keine Programmierung ist. Sie müssen den generierten Code wieder an die tatsächlichen Namen der Eingabe- / Ausgabevariablen oder den Verwendungskontext anpassen.
- Insbesondere
$OUTPUT =
müsste die Zuweisung gehen, wenn der vorherige preg_replace
Anruf in einem verwendet wurde if
.
- Es ist jedoch am besten, temporäre Variablen oder die mehrzeilige Codeblockstruktur beizubehalten.
Und der Ersatzausdruck erfordert möglicherweise mehr Verbesserungen der Lesbarkeit oder Nacharbeit.
- Beispielsweise
stripslashes()
wird es in wörtlichen Ausdrücken häufig überflüssig.
- Für Suchvorgänge mit variablem Bereich ist ein
use
oder eine global
Referenz für / innerhalb des Rückrufs erforderlich .
- Ungleichmäßig in Anführungszeichen eingeschlossene
"-$1-$2"
Erfassungsreferenzen werden durch die einfache Umwandlung in syntaktisch unterbrochen "-$m[1]-$m[2]
.
Die Code-Ausgabe ist lediglich ein Ausgangspunkt. Und ja, dies wäre als Online-Tool nützlicher gewesen. Dieser Ansatz zum Umschreiben von Code (Bearbeiten, Ausführen, Bearbeiten, Bearbeiten) ist etwas unpraktisch. Könnte jedoch für diejenigen zugänglicher sein, die an aufgabenorientiertes Codieren gewöhnt sind (mehr Schritte, mehr Aufdeckungen). Diese Alternative könnte also einige weitere doppelte Fragen zügeln.