11

为了简短起见,我编写了一个访问控制系统。

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

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

所以简单来说,我需要glob()在 PHP 上重新创建匹配功能。

示例代码:

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成一个正则表达式而不是 use preg_match(),还有其他方法吗?

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

4

5 回答 5

17

使用fnmatch(),这似乎可以解决问题。

于 2012-12-17T12:21:53.267 回答
5

转换为正则表达式对我来说似乎是最好的解决方案。您需要做的就是转换*.*?和。然而,这并不像看起来那么简单,因为就你做事的顺序而言,这是一个先有鸡还是先有蛋的问题。.preg_quote

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

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);

}

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

看到它工作

于 2012-12-17T12:23:15.520 回答
5

PHP 中已经有一个函数,自 PHP 4.3.0 起就包含在内。

fnmatch()检查传递的字符串是否匹配给定的 shell 通配符模式。

于 2013-03-11T08:34:24.903 回答
3

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

http://php.net/manual/en/function.glob.php

<?php   
function match_wildcard( $wildcard_pattern, $haystack ) {
   $regex = str_replace(
     array("\*", "\?"), // wildcard chars
     array('.*','.'),   // regexp chars
     preg_quote($wildcard_pattern)
   );

   return preg_match('/^'.$regex.'$/is', $haystack);
}

$test = "foobar and blob\netc.";
var_dump(
    match_wildcard('foo*', $test),      // TRUE
    match_wildcard('bar*', $test),      // FALSE
    match_wildcard('*bar*', $test),     // TRUE
    match_wildcard('**blob**', $test),  // TRUE
    match_wildcard('*a?d*', $test),     // TRUE
    match_wildcard('*etc**', $test)     // TRUE
);
?>
于 2012-12-17T12:27:34.907 回答
0

我认为这应该适用于将 glob-patterns 转换为 regex-patterns:

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';
}

如果要防止匹配目录名称,则可能要使用[^\\/]*for 。**

于 2016-02-10T00:05:05.843 回答