preg_replace la cale avec le support d'évaluation
C'est très déconseillé. Mais si vous n'êtes pas un programmeur, ou si vous préférez vraiment un code terrible, vous pouvez utiliser un substitut preg_replace
pour conserver votre /e
le drapeau fonctionne temporairement .
/**
* 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
);
}
En fait, il suffit d'inclure cette fonction dans votre base de données, et d'éditer preg_replace
à preg_replace_eval
partout où le /e
a été utilisé.
Avantages et inconvénients :
- Vraiment juste testé avec quelques échantillons de Stack Overflow.
- Ne prend en charge que les cas simples (appels de fonction, pas de recherche de variable).
- Contient quelques restrictions et avis supplémentaires.
- Produira des erreurs disloquées et moins compréhensibles pour les échecs d'expression.
- Cependant, il s'agit toujours d'une solution temporaire utilisable et qui ne complique pas une transition correcte vers le système de gestion des déchets.
preg_replace_callback
.
- Et le commentaire sur la licence a pour but de dissuader les gens d'en faire un usage abusif ou de la diffuser trop loin.
Générateur de codes de remplacement
Maintenant, c'est un peu redondant. Mais cela pourrait aider les utilisateurs qui sont toujours dépassés par la restructuration manuelle de leur code pour preg_replace_callback
. Bien que cela prenne effectivement plus de temps, un générateur de code a moins de difficultés à étendre le champ d'action de la /e
chaîne de remplacement dans une expression. Il s'agit d'une conversion très banale, mais qui est probablement suffisante pour les exemples les plus courants.
Pour utiliser cette fonction, modifiez n'importe quel preg_replace
l'appel en preg_replace_eval_replacement
et l'exécuter une fois . Cela permettra imprimer le selon preg_replace_callback
pour être utilisé à sa place.
/**
* 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";
}
Gardez à l'esprit que le simple copier-coller est pas la programmation. Vous devrez adapter le code généré à vos noms de variables d'entrée/sortie réels, ou à votre contexte d'utilisation.
- Plus précisément, le
$OUTPUT =
L'affectation devra être supprimée si le précédent preg_replace
a été utilisé dans un if
.
- Il est toutefois préférable de conserver les variables temporaires ou la structure de bloc de code multiligne.
Et l'expression de remplacement peut exiger davantage d'améliorations de la lisibilité ou de remaniements.
- Par exemple
stripslashes()
devient souvent redondant dans les expressions littérales.
- Les recherches à portée variable nécessitent un
use
o global
pour/au sein du callback.
- Citations irrégulières
"-$1-$2"
les références de capture se retrouveront syntaxiquement brisées par la transformation simple en "-$m[1]-$m[2]
.
La sortie du code n'est qu'un point de départ. Et oui, cela aurait été plus utile en tant qu'outil en ligne. Cette approche de réécriture du code (éditer, exécuter, éditer, éditer) n'est pas très pratique. Pourtant, elle pourrait être plus accessible à ceux qui sont habitués à un codage centré sur les tâches (plus d'étapes, plus de découvertes). Cette alternative pourrait donc freiner un peu plus les questions dupliquées.