我使用preg_replace,我想在替换字符串中包含一个url。我怎么引用那个字符串?看来preg_quote仅适用于搜索模式。
$replace = '\1'.addslashes($url).'\3'.addslashes($title).'\4';
答案 0 :(得分:4)
addslashes
还不够preg_quote
逃避太多请参阅this demo。
正如Mario所说,你可以使用addcslashes($str, "\\$")
。
答案 1 :(得分:0)
不幸的是,没有通用的方法可以做到这一点,但在大多数情况下addslashes
就足够了。
为了最大限度地提高安全性,您可以使用${1}
语法。 E.g。
$replace = '${1}'.addslashes($url).'${3}'.addslashes($title).'${4}';
如果你真的想要完全防弹,请使用preg_replace_callback()
的回调替换功能。从回调函数返回的字符串完全按原样使用,因此您不必担心将替换语法与普通文本混合使用。
preg_replace_callback()
的示例:
class URLReplacer {
public $pattern = '/my regex/';
public $url;
public $title;
function __construct($url, $title) {
$this->url = $url;
$this->title = $title;
}
function _callback($matches) {
return $matches[1].$url.$matches[3].$title.$matches[4];
}
function replace($subject) {
return preg_replace_callback($this->pattern, array($this, '_callback'), $subject);
}
}
$repl = new URLReplacer($url, $title);
$replaced = $repl->replace($subject);
答案 2 :(得分:0)
你没有提供一个例子,所以我自己编译了一个。我提出的工作解决方案是使用一个简单的回调函数:
$url = 'http://example.com/';
$title = 'Make it Complex \4';
$subject = 'Call \\4 " $me an url';
$pattern = '/(.*)an()( )(url)/';
$replace = function($m) use ($url, $title)
{
return "$m[1]$url$m[3]$title$m[4]";
};
$result = preg_replace_callback($pattern, $replace, $subject);
结果:
Call \4 " $me http://example.com/ Make it Complex \4url
回调函数是一个所谓的anonymous function Docs,可以很容易地编辑代码。
如果你经常需要这个,你可以把它放到你自己的功能中,可能是为了让它更具可重复性。您甚至可以到目前为止创建自己的模式来替换子组匹配和变量。例如,{\1}
代表子模式1匹配,{$2}
代表第二个变量。将其包含在它自己的功能中:
$patternf = function()
{
$values = func_get_args();
$mask = $values ? array_shift($values) : NULL;
return function($matches) use ($mask, $values)
{
$parts = preg_split('/({[\\\\\\$][0-9]{1,3}})/', $mask, 0, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
foreach($parts as &$part)
if (preg_match('/^{([\\\\\\$])([0-9]{1,3})}$/', $part, $p))
$part = $p[1] == '\\' ? $matches[(int)$p[2]] : $values[$p[2]-1];
return implode('', $parts);
};
};
可以让您更换更方便:
$replace = $patternf('{\1}{$1}{\3}{$2}{\4}', $url, $title);
$result = preg_replace_callback($pattern, $replace, $subject);
Demo。将其包含在它自己的功能中:
function preg_replace_subst($pattern, $replace, $subject)
{
$values = func_get_args();
$pattern = array_shift($values);
$mask = array_shift($values);
$subject = array_shift($values);
$callback = function($matches) use ($mask, $values)
{
$parts = preg_split('/({[\\\\\\$][0-9]{1,3}})/', $mask, 0, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
foreach($parts as &$part)
if (preg_match('/^{([\\\\\\$])([0-9]{1,3})}$/', $part, $p))
$part = $p[1] == '\\' ? $matches[(int)$p[2]] : $values[$p[2]-1];
return implode('', $parts);
};
return preg_replace_callback($pattern, $callback, $subject);
}
会给它一个简单的界面:
$url = 'http://example.com/';
$title = 'Make it Complex \4';
$subject = 'Call \\4 " $me an url';
$pattern = '/(.*)an()( )(url)/';
$replace = '{\1}{$1}{\3}{$2}{\4}';
$result = preg_replace_subst($pattern, $replace, $subject, $url, $title);
但是对于许多替换变量,应该可以将它们作为数组传递,否则它会变得有点冗长。
e
修饰符与preg_replace
一起使用(以及为什么它不起作用)使用e
修饰符时,匹配将替换为替换字符串,然后进行评估。由于其他变量没有被转义,匹配确实会干扰PHP变量替换,这很危险:
$url = 'http://example.com/';
$title = 'Make it Complex \4';
$subject = 'Call me an url.';
$pattern = '/(.*)an()( )(url)/e';
$replace = '"$1{$url}$3{$title}$4"';
$result = preg_replace($pattern, $replace, $subject);
输出:
Call me http://example.com/ Make it Complex \4url.
如上所述,第一个e
- 修饰符示例已被破坏,因为$
不会在$subject
中转义,因此PHP会查找未设置的变量。那也很危险。我提出了一个变体,它解决了这个问题,但它不能处理主题中的双引号:
$url = 'http://example.com/';
$title = 'Make it Complex \4';
$subject = 'Call \\4 " $me an url';
$pattern = '/(.*)an()( )(url)/e';
$replace = "'\$1'.\$url.'\$3'.\$title.'$4'";
输出:
Call \4 \" $me http://example.com/ Make it Complex \4url
^ problem, not in input.
所以不是非常傻瓜,这就是为什么它需要回调函数,因为它可以获得不带引号的匹配子模式。
答案 3 :(得分:0)
为了明确一个人在$replacement
的{{1}}参数中逃避任何潜在的反向引用,请使用函数:
preg_replace()
在OP案例中:
function preg_quote_replacement($input) {
return addcslashes($input, '\\$');
}
答案 4 :(得分:0)
您可以使用具有T-Regx library的Pattern Builder。它的工作方式类似于SQL中的Prepared Statements:
Pattern::inject("\1@url\2@url\3", [
'url' => $input
]);
甚至
Pattern::prepare("\1", [$input], "\2", [$input], "\3");
// ↑ this means 'ignoring special characters'