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

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

Ответы [ 14 ]

24 голосов
/ 19 октября 2010

Я использовал источник из комментариев для создания этой функции. Возвращает файл полного пути, если найден, FALSE, если нет.

Не работает без учета регистра для имен каталогов в имени файла.

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;
}
7 голосов
/ 03 ноября 2015

Этому вопросу несколько лет, но он связан с несколькими как дубликаты, так что вот простой метод.

Возвращает false, если $filename в любом случае не найден в $path или фактическое имя файла первого файла, возвращенное glob(), если оно было найдено в любом случае:

$result = current(preg_grep("/".preg_quote($filename)."/i", glob("$path/*")));
  • Получить все файлы по пути glob
  • Grep для $filename в любом случае i без учета регистра
  • current возвращает первое имя файла из массива

Удалите current(), чтобы вернуть все соответствующиефайлы.Это важно для чувствительных к регистру файловых систем, так как IMAGE.jpg и image.JPG могут существовать.

2 голосов
/ 19 октября 2010

Ваш подход работает.
В качестве альтернативы вы можете использовать glob, чтобы получить список всех файлов и каталогов в текущем рабочем каталоге в массиве, используйте array_map, чтобы применить strtolower к каждому элементу, а затем использовать in_array чтобы проверить, существует ли ваш файл (после применения strtolower) в массиве.

2 голосов
/ 19 октября 2010

В именах файлов Unix учитывается регистр, поэтому вы не сможете выполнить проверку существования без учета регистра, не перечислив содержимое каталога.

1 голос
/ 03 февраля 2014

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

function fileExists( $fileName, $fullpath = false, $caseInsensitive = false ) 
{
    // Presets
    $status         = false;
    $directoryName  = dirname( $fileName );
    $fileArray      = glob( $directoryName . '/*', GLOB_NOSORT );
    $i              = ( $caseInsensitive ) ? "i" : "";

    // Stringcheck
    if ( preg_match( "/\\\|\//", $fileName) ) // Check if \ is in the string
    {
        $array    = preg_split("/\\\|\//", $fileName);
        $fileName = $array[ count( $array ) -1 ];
    }

    // Compare String
    foreach ( $fileArray  AS $file )
    {
        if(preg_match("/{$fileName}/{$i}", $file))
        {
            $output = "{$directoryName}/{$fileName}";
            $status = true;
            break;
        }
    }

    // Show full path
    if( $fullpath && $status )
        $status = $output;

    // Return the result [true/false/fullpath (only if result isn't false)]
    return $status;
}
1 голос
/ 21 апреля 2011

Я столкнулся с той же проблемой, когда мы мигрировали из IIS в apache. Ниже кусок, который я взбил. Возвращает либо правильный путь в виде строки, либо false.

function resolve_path($path)
{
    $is_absolute_path = substr($path, 0, 1) == '/';
    $resolved_path = $is_absolute_path ? '/' : './';
    $path_parts = explode('/', strtolower($path));

    foreach ($path_parts as $part)
    {
        if (!empty($part))
        {
            $files = scandir($resolved_path);

            $match_found = FALSE;

            foreach ($files as $file)
            {
                if (strtolower($file) == $part)
                {
                    $match_found = TRUE;

                    $resolved_path .= $file . '/';
                }
            }

            if (!$match_found)
            {
                return FALSE;
            }
        }
    }

    if (!is_dir($resolved_path) && !is_file($resolved_path))
    {
        $resolved_path = substr($resolved_path, 0, strlen($resolved_path) - 1);
    }

    $resolved_path = $is_absolute_path ? $resolved_path : substr($resolved_path, 2, strlen($resolved_path));

    return $resolved_path;
}

$relative_path = substr($_SERVER['REQUEST_URI'], 1, strlen($_SERVER['REQUEST_URI']));
$resolved_path = resolve_path($relative_path);

if ($resolved_path)
{
    header('Location: http://' . $_SERVER['SERVER_NAME'] . '/' . $resolved_path);
    die();
}
0 голосов
/ 13 июня 2019

Ответ AbraCadaver с рейтингом +7 неверен, у меня недостаточно репутации, чтобы комментировать под ним, поэтому вот правильное решение, основанное на его ответе:

$result = count(preg_grep('/\/'.preg_quote($filename)."$/i", glob("$path/*")));

AbraCadaver ответ неверный, потому что он возвращает true, если вы проверяете файл foo.jpg и такие файлы, как anytext_foo.jpg существуют.

0 голосов
/ 24 октября 2016

Просто наткнулся на это сегодня, но мне здесь не понравились ответы, поэтому я решил добавить свое решение (используя SPL и итератор регулярных выражений)

function _file_exists( $pathname ){
    if(file_exists($pathname)) return $pathname;

    try{
        $path = dirname( $pathname );
        $file = basename( $pathname );

        $Dir = new \FilesystemIterator( $path, \FilesystemIterator::UNIX_PATHS );
        $regX = new \RegexIterator($Dir, '/(.+\/'.preg_quote( $file ).')$/i', \RegexIterator::MATCH);

        foreach ( $regX as $p ) return $p->getPathname();

    }catch (\UnexpectedValueException $e ){
        //invalid path
    }
    return false;
}

Способ, которым я используюэто выглядит так:

 $filepath = 'path/to/file.php';

 if( false !== ( $filepath = _file_exists( $filepath ))){
      //do something with $filepath
 }

Таким образом, он сначала будет использовать встроенную единицу, в случае неудачи он будет использовать нечувствительный и назначит правильный регистр переменной $filepath.

0 голосов
/ 26 июля 2016
//will resolve & print the real filename
$path = "CaseInsensitiveFiLENAME.eXt";
$dir  = "nameOfDirectory";

if ($handle = opendir($dir)) {
 while (false !== ($entry = readdir($handle))) {
     if (strtolower($path) == strtolower($entry)){
       echo $entry ;
    }}
    closedir($handle);
}
0 голосов
/ 29 февраля 2016

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

SELECT actual_file_name
FROM TABLE_NAME
WHERE actual_file_name LIKE 'filename_i_want'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...