2

我尝试构建 RegExp 来验证(preg_match)以下两个规则的一些路径字符串:

  1. 路径必须仅包含给定范围内的符号[a-zA-z0-9-_\///\.]
  2. 路径将不包含向上目录序列“..”

这是一个正确的路径示例:/user/temp

和坏的:/../user

UPD: /user/temp.../foo 也是正确的(感谢Laurence Gonsalves

4

1 回答 1

2

考虑一下:

$right_path = '/user/temp';
$wrong_path = '/../user';
$almost_wrong_path = 'foo/abc../bar';
$almost_right_path = 'foo/../bar';

$pattern = '#^(?!.*[\\/]\.{2}[\\/])(?!\.{2}[\\/])[-\w.\\/]+$#';
var_dump(preg_match($pattern, $right_path)); // 1
var_dump(preg_match($pattern, $wrong_path)); // 0
var_dump(preg_match($pattern, $almost_wrong_path)); // 1
var_dump(preg_match($pattern, $almost_right_path)); // 0

我实际上分三个步骤构建了这个模式:

1) 给出的第一条规则说,字符串中只允许使用的符号是0-9, a-zA-Z, _(下划线), -(hyphen), .(dot) 和斜线 (/\)。前三个位置可以用快捷方式 ( \w) 表示,其他位置需要字符类:

[-\w.\\/]

这里注意两点:1)连字符应该是字符类中的第一个或最后一个符号(否则它被视为用于定义范围的元字符);2)点和正斜杠都还没有转义(反斜杠被转义了;它太强大了,不能单独使用,即使在[...]子表达式中也是如此)。

2) 现在我们必须确保模式确实覆盖了整个字符串。我们用所谓的锚点来做 -^​​ 用于字符串的开头,$用于结尾。而且,不要忘记我们的字符串可能包含一个或多个允许的符号(这用量词表示+)。所以模式变成了这样:

^[-\w.\\/]+$

3)最后一件事——我们也必须防止使用../and ..\(如果序列开始字符串,则在/or之前\- 或不使用)。..[/\\]

表达此规则的最简单方法是使用所谓的“否定前瞻”测试。它写在 (?!...) 子表达式中,并且(在这种情况下)描述了以下想法:'确保零个或多个符号的序列后面没有“斜线-两个点-斜线”序列':

^(?!.*[\\/]\.{2}[\\/])(?!\.{2}[\\/])[-\w.\\/]+$

最后一件事实际上是将模式放入preg_match函数中:当我们/在正则表达式中使用符号时,我们可以选择另一组分隔符。在我的示例中,我选择了“#”:

$pattern = '#^(?!.*[\\/]\.{2}[\\/])(?!\.{2}[\\/])[-\w.\\/]+$#';

看?这真的很容易。) 你只需要从小事做起,逐步发展。

于 2012-11-06T22:29:26.320 回答