Versão Insensível a Caso PHP de file_exists ()

Estou tentando pensar na maneira mais rápida de implementar uma function insensível a maiúsculas e minúsculas na PHP. A minha melhor opção é enumerar o arquivo no diretório e fazer uma comparação strtolower () para strtolower () até encontrar uma correspondência?

Usei a fonte dos comentários para criar esta function. Retorna o arquivo de caminho completo se encontrado, FALSO se não.

Não funciona insensivelmente em nomes de diretórios no nome do arquivo.

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

Nos nomes de arquivos do Unix são sensíveis a maiúsculas e minúsculas, então você não poderá fazer uma verificação de existência insensível a maiúsculas e minúsculas sem listar o conteúdo do diretório.

Sua abordagem funciona.
Alternativamente, você pode usar o glob para obter a lista de todos os arquivos e diretórios no atual diretório de trabalho em uma matriz, use array_map para aplicar strtolower a cada elemento e, em seguida, use in_array para verificar se o arquivo (após a aplicação strtolower ) existe na matriz.

Eu corri para o mesmo problema quando migramos do IIS para o Apache. Abaixo está a peça que eu bati. Retorna o caminho correto como uma string ou falso.

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

Eu sintonizei a function um pouco mais. acho melhor para o uso

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

Esta questão tem alguns anos, mas está ligada a duplicatas, então aqui é um método simples.

Retorna false se o $filename do $filename em qualquer caso não for encontrado no $path ou o nome do arquivo real do primeiro arquivo retornado pelo glob() se ele for encontrado em qualquer caso:

 $result = current(preg_grep("/$filename$/i", glob("$path/*"))); 

Remova o current() para retornar todos os arquivos correspondentes. Isso é importante em filesystems sensíveis a maiúsculas e minúsculas, como IMAGE.jpg e image.JPG podem existir.

Para uma implementação pura do PHP, sim. Há um exemplo nos comentários para a function file_exists .

A outra opção seria executar seu script em um sistema de arquivos insensível a maiúsculas e minúsculas.

Eu melhorei a function de John Himmelman e encontrei isso:
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; } 

Tendo encontrado esta página de um google rápido usei a solução de Kirk , no entanto, é lento se você a ligar várias vezes no mesmo diretório, ou em um diretório que tenha muitos arquivos. Isto é devido ao fato de ele fazer um loop sobre todos os arquivos cada Tempo, então o otimizei um pouco:

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

Eu soltei a bandeira para verificar a insensibilidade do caso, pois suponho que você apenas usaria file_exists se não precisasse desse comportamento, então a bandeira parecia redundante. Eu também espero que, se você estiver fazendo algo além de um script trivial, você gostaria de transformar isso em uma class para obter mais controle sobre o cache da lista de diretórios, por exemplo, redefini-lo, mas isso está além do alcance do que eu precisava e deveria seja trivial para fazer se você precisar.

Minha solução sintonizada, independente do sistema autônomo, realpath() alternativa, independente de maiúsculas e minúsculas , abrangendo caminho inteiro, chamado 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)); } 

O nome do arquivo de pesquisa com padrão glob [nN][aA][mM][eE] parece ser a solução mais rápida

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

Corri por isso hoje, mas não gostei de nenhuma das respostas aqui, então pensei que gostaria de adicionar minha solução (usando o SPL e o iterador regex)

 function _file_exists( $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; } 

A maneira como eu estou usando isso é assim:

  $filepath = 'path/to/file.php'; if( false !== ( $filepath = _file_exists( $filepath ))){ //do something with $filepath } 

Desta forma, ele usará o construído em um primeiro, se isso falhar, ele usará o insensível e atribuirá o invólucro apropriado à variável $filepath .

As outras respostas podem ser muito intensivas em resources em grandes filesystems (grande número de arquivos para pesquisar). Pode ser útil criar uma tabela temporária de todos os nomes dos arquivos (caminho completo, se necessário). Em seguida, faça uma busca de condição semelhante dessa tabela para obter qualquer que seja o caso real.

 SELECT actual_file_name FROM TABLE_NAME WHERE actual_file_name LIKE 'filename_i_want'