我有一个包含大量文件的服务器文件夹,使用 guid 值随机命名(示例文件:
c3c1a48e-a798-41bd-bd70-66ffdc619963.jpg
)。
我需要对该文件夹进行不区分大小写的搜索,因为可能存在同一文件名的大写(或混合大小写)版本。 (我无法将现有文件转换为全部小写文件名。)
这个问题的答案 file_exists() 的 PHP 不区分大小写版本 提供了一个函数(如下所示),它将整个文件夹“通配”到一个数组中,然后对数组中的每个项目进行 foreach 搜索。
这似乎有点慢/效率低下,尤其是在搜索包含许多(数千个)文件的文件夹时。
是否有更有效的方法来进行不区分大小写的文件名搜索?或者使用 foreach 循环 - 如下面的代码所示 - “足够高效”?
(这是上面问题推荐的代码)
function fileExists($fileName, $caseSensitive = true) {
if(file_exists($fileName)) {
return $fileName;
}
if($caseSensitive) return false;
// Handle case insensitive requests
$directoryName = dirname($fileName);
$fileArray = glob($directoryName . '/*', GLOB_NOSORT);
$fileNameLowerCase = strtolower($fileName);
foreach($fileArray as $file) {
if(strtolower($file) == $fileNameLowerCase) {
return $file;
}
}
return false;
}
我无法发表评论,尽管这可以回答你的问题:不。就你目前的状态而言,看起来你必须使用这种逻辑。 -但是- 您可以创建逻辑来获取那些具有大写字母的文件,并在文件夹中使用
copy($filename,strtolower($filename))
将它们变为小写,然后删除具有大写字母的旧文件名。 。然后,在将来添加更多文件时,strtolower($new_file_name)
,然后再将文件添加到系统中。我同意你的观点,但这种逻辑确实看起来很慢,尤其是对于数千个文件。
这与您所说的无法重命名/转换文件名相矛盾,尽管一旦您这样做,这将是您唯一一次必须重命名它们。
有时我想创建一个不区分大小写的自动加载器,所以我在这里使用了示例: https://www.php-fig.org/psr/psr-4/examples/ ...并对其进行了一些修改。
我添加了一个为
glob()
创建图案的方法。它创建一个模式,其中每个字符都以大写和小写形式存在,只要它在相同的情况下有所不同,那么就不需要额外的模式,因此点和斜线没有大写或小写版本。 path/file.php 看起来像 [pP][aA][tT][hH]/[fF][iI][lL][eE].[pP][hH][pP].
它并不完美,因为在某些情况下,utf8 中不止一个替代字符,因此,如果小写和大写与给定的字符不同,它还会将其添加到可能的字符的模式中,但只是这个而不是所有替代方案。
/**
* Convert path and filename to a case insensitive pattern for glob().
*
* @param string $path
* @return string
*/
private function createCaseInsensitivePattern(string $path) {
$chars = mb_str_split($path);
$pattern = '';
foreach ($chars as $char) {
$lower = mb_strtolower($char);
$upper = mb_strtoupper($char);
if ($char == $lower && $char == $upper) {
$pattern .= $char;
} else {
$pattern .= '['.$lower.$upper.($char != $lower && $char != $upper?$char:'').']';
}
$pattern .= $char == '/' || $char == '\\' ? $char:('');
}
return $pattern;
}
然后我用 else 情况扩展了
requireFile()
方法。
因此,如果未在正确的情况下找到文件,则它只需调用 createCaseInsensitivePattern()
方法并对结果执行 glob()
操作。如果没有任何东西适合,那么它只是返回 false。
/**
* If a file exists, require it from the file system.
*
* @param string $file The file to require.
* @return bool True if the file exists, false if not.
*/
protected function requireFile(string $file)
{
if (file_exists($file)) {
require $file;
return true;
} else {
$filePattern = $this->createCaseInsensitivePattern($file);
$possibleFiles = glob($filePattern);
foreach ($possibleFiles as $currentFile) {
if (file_exists($currentFile)) {
require $currentFile;
return true;
}
}
}
return false;
}
如果您只想执行 file_exists,只需删除以
require
开头的两行。