PHP регистронезависимая версия file_exists () - PullRequest
17 голосов
/ 19 октября 2010

Я пытаюсь придумать самый быстрый способ реализации нечувствительной к регистру функции file_exists в PHP.Мой лучший выбор - перечислить файл в каталоге и выполнять сравнение strtolower () с strtolower (), пока не будет найдено совпадение?

Ответы [ 14 ]

0 голосов
/ 03 ноября 2015

Мое настроенное решение, не зависит от ОС, без учета регистра realpath() альтернатива, охватывающая весь путь с именем realpathi():

/**
 * Case-insensitive realpath()
 * @param string $path
 * @return string|false
 */
function realpathi($path)
{
    $me = __METHOD__;

    $path = rtrim(preg_replace('#[/\\\\]+#', DIRECTORY_SEPARATOR, $path), DIRECTORY_SEPARATOR);
    $realPath = realpath($path);
    if ($realPath !== false) {
        return $realPath;
    }

    $dir = dirname($path);
    if ($dir === $path) {
        return false;
    }
    $dir = $me($dir);
    if ($dir === false) {
        return false;
    }

    $search = strtolower(basename($path));
    $pattern = '';
    for ($pos = 0; $pos < strlen($search); $pos++) {
        $pattern .= sprintf('[%s%s]', $search[$pos], strtoupper($search[$pos]));
    }
    return current(glob($dir . DIRECTORY_SEPARATOR . $pattern));
}

поиск имени файла с шаблоном glob [nN][aA][mM][eE] кажется более быстрым решением

0 голосов
/ 11 июня 2015

Найдя эту страницу из быстрого гугла, я использовал решение Kirk, однако оно медленное, если вы вызываете его несколько раз в одном и том же каталоге или в каталоге, в котором много файлов. Это связано с цикличностью по всем файлам каждый раз, так что я немного его оптимизировал:

function fileExists($fileName) {
    static $dirList = [];
    if(file_exists($fileName)) {
        return true;
    }
    $directoryName = dirname($fileName);
    if (!isset($dirList[$directoryName])) {
        $fileArray = glob($directoryName . '/*', GLOB_NOSORT);
        $dirListEntry = [];
        foreach ($fileArray as $file) {
            $dirListEntry[strtolower($file)] = true;
        }
        $dirList[$directoryName] = $dirListEntry;
    }
    return isset($dirList[$directoryName][strtolower($fileName)]);
}

Я сбросил флаг, чтобы проверить нечувствительность к регистру, так как я предполагаю, что вы просто используете file_exists, если вам не нужно это поведение, поэтому флаг показался излишним. Я также ожидаю, что если вы делаете что-то, кроме тривиального сценария, вы захотите превратить это в класс, чтобы получить больший контроль над кэшированием списка каталогов, например, сбросить его, но это выходит за рамки того, что мне нужно, и это должно быть тривиально, если вам это нужно.

0 голосов
/ 07 сентября 2013

Я улучшил функцию John Himmelman и получил следующее:suppose that i have a catch system \iMVC\kernel\caching\fileCache

function resolve_path($path)
{
    # check if string is valid
    if(!strlen($path)) return FALSE;
    # a primary check
    if(file_exists($path)) return $path;
    # create a cache signiture
    $cache_sig = __METHOD__."@$path";
    # open the cache file
    $fc = new \iMVC\kernel\caching\fileCache(__CLASS__);
    # check cache file and validate it
    if($fc->isCached($cache_sig) && file_exists($fc->retrieve($cache_sig)))
    {
        # it was a HIT!
        return $fc->retrieve($cache_sig);
    }
    # if it is ab
    $is_absolute_path = ($path[0] == DIRECTORY_SEPARATOR);
    # depart the path
    $path_parts = array_filter(explode(DIRECTORY_SEPARATOR, strtolower($path)));
    # normalizing array's parts
    $path_parts = count($path_parts)? array_chunk($path_parts, count($path_parts)) : array();
    $path_parts = count($path_parts[0])?$path_parts[0]:array();
    # UNIX fs style
    $resolved_path = $is_absolute_path ? DIRECTORY_SEPARATOR : ".";
    # WINNT fs style
    if(string::Contains($path_parts[0], ":"))
    {
        $is_absolute_path = 1;
        $resolved_path = $is_absolute_path ? "" : ".".DIRECTORY_SEPARATOR;
    }
    # do a BFS in subdirz
    foreach ($path_parts as $part)
    {
        if (!empty($part))
        {
            $target_path = $resolved_path.DIRECTORY_SEPARATOR.$part;
            if(file_exists($target_path))
            {
                $resolved_path = $target_path;
                continue;
            }
            $files = scandir($resolved_path);

            $match_found = FALSE;

            foreach ($files as $file)
            {   
                if (strtolower($file) == $part)
                {
                    $match_found = TRUE;
                    $resolved_path = $resolved_path.DIRECTORY_SEPARATOR.$file;
                    break;
                }
            }
            if (!$match_found)
            {
                return FALSE;
            }
        }
    }
    # cache the result
    $fc->store($target_path, $resolved_path);
    # retrun the resolved path
    return $resolved_path;
}
0 голосов
/ 19 октября 2010

Для чистой реализации PHP, да. В есть комментарии для функции file_exists .

.

Другой вариант - запустить скрипт в нечувствительной к регистру файловой системе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...