PHP全局样式匹配

PHP全局样式匹配,php,path,pattern-matching,glob,Php,Path,Pattern Matching,Glob,简而言之,我写了一个访问控制系统 该系统的要求之一是通过将规范化/规范化路径与模式匹配来检查是否可以访问该路径 首先想到的是PREG,问题是,这些模式是基于文件的,即类似于glob()所接受的模式。基本上,它只是包含?(匹配一个任意字符)或*(匹配任何字符)的模式 因此,简单地说,我需要在PHP上重新创建glob()的匹配功能 示例代码: function path_matches($path, $pattern){ // ... ? } path_matches('path/inde

简而言之,我写了一个访问控制系统

该系统的要求之一是通过将规范化/规范化路径与模式匹配来检查是否可以访问该路径

首先想到的是PREG,问题是,这些模式是基于文件的,即类似于
glob()
所接受的模式。基本上,它只是包含
(匹配一个任意字符)或
*
(匹配任何字符)的模式

因此,简单地说,我需要在PHP上重新创建
glob()
的匹配功能

示例代码:

function path_matches($path, $pattern){
    // ... ?
}

path_matches('path/index.php', 'path/*');        // true
path_matches('path2/', 'path/*');                // false
path_matches('path2/test.php', 'path2/*.php');   // true
一个可能的解决方案是将
$pattern
转换为正则表达式,而不是使用
preg_match()
,但是还有其他方法吗


NB:我不能使用正则表达式的原因是模式将由非程序员编写。

使用,这似乎起到了作用。

转换为正则表达式似乎是我的最佳解决方案。您只需将
*
转换为
*
转换为
preg
。然而,这并不像看上去那么简单,因为从你做事的顺序来看,这是一个鸡和蛋的问题

我不喜欢这个解决方案,但它是我能想到的最好的:使用正则表达式生成正则表达式

function path_matches($path, $pattern, $ignoreCase = FALSE) {

  $expr = preg_replace_callback('/[\\\\^$.[\\]|()?*+{}\\-\\/]/', function($matches) {
    switch ($matches[0]) {
      case '*':
        return '.*';
      case '?':
        return '.';
      default:
        return '\\'.$matches[0];
    }
  }, $pattern);

  $expr = '/'.$expr.'/';
  if ($ignoreCase) {
    $expr .= 'i';
  }

  return (bool) preg_match($expr, $path);

}
编辑添加了区分大小写选项


来自glob()的PHP文档。我认为preg_match是最好的解决方案


PHP中已经有一个函数,从PHP4.3.0开始就包含了它

检查传递的字符串是否与给定的shell通配符模式匹配


我认为这应该可以将glob模式转换为regex模式:

function glob2regex($globPatt) {
    return '/'.preg_replace_callback('/./u', function($m) {
        switch($m[0]) {
            case '*': return '.*';
            case '?': return '.';
        }
        return preg_quote($m[0],'/');
    }, $globPatt).'\z/AsS';
}

如果要防止
*
与目录名匹配,您可能需要将
[^\\/]*
用于
*

如果在php中已经存在glob(),为什么要重新创建它?嗯,请把问题再读一遍
glob()
使用实际路径,我需要重新创建其模式匹配功能。我不知道如何在我的案例中使用
glob()
(在不存在的路径上)。我不好,请看我的答案:)这会起作用,但我需要一个能在所有系统上工作的,而不仅仅是POSIX+1尝试一下。此功能在Windows上可用,因为5.3是的,我考虑了
str_replace()
方法,但我仍然无法确定它在所有情况下是否安全。您还需要将
preg_match()
的返回值强制转换为bool,但这是一个次要考虑因素。这就是preg_引号的作用。它将使整个字符串正则表达式安全。然后它就变成了*和?又不安全了。所以,是的,它做你想做的,不能被滥用。不,我知道,我不喜欢的是
\*
\?
的后续替换,特别是因为主题字符串/模式字符串可能合法地包含反斜杠。另外,我刚刚注意到,您没有指定分隔符
/
。我认为Dave的担心是合理的。如果有更明确的方法,我更喜欢这个方法,而不是更复杂的正则表达式。你总是可以用类似[a-zA-Z0-9\]的东西来改变*我认为这应该是万无一失的。谢谢Dave,“看到它工作”链接指向一个只显示PHP错误的页面。这真的很好。但是,它不能正常工作。例如,*.js被转换为“/.*\\.js/”。这看起来是对的,但可能不是。生成的正则表达式将与abc.jsx匹配,这可能不是用户想要的。更糟糕的是,生成的正则表达式将匹配abc/def.js。您是否需要在生成的正则表达式周围添加
^
$
?glob通常锚定在开头和结尾,而regex在默认情况下不是。
function glob2regex($globPatt) {
    return '/'.preg_replace_callback('/./u', function($m) {
        switch($m[0]) {
            case '*': return '.*';
            case '?': return '.';
        }
        return preg_quote($m[0],'/');
    }, $globPatt).'\z/AsS';
}