Sto cercando di pensare al modo più veloce per implementare una funzione file_exists senza maiuscole e minuscole in PHP. La mia migliore scommessa per enumerare il file nella directory e fare un confronto strtolower() con strtolower() fino a trovare una corrispondenza?PHP Case Insensitive Version of file_exists()
risposta
Ho utilizzato la sorgente dai commenti per creare questa funzione. Restituisce il file di percorso completo se trovato, FALSE se non lo è.
Non funziona senza distinzione tra maiuscole e minuscole nei nomi di directory nel nome file.
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;
}
Non sarebbe bello restituire SEMPRE un nome file completo? È strano trovare a volte un percorso booleano e talvolta utile quando viene trovata una corrispondenza. –
cosa vorresti restituire se il file non esiste? O_o – Jonathan
Penso che la funzione 'fileExists' dovrebbe restituire' true', se il file esiste :) –
In Unix i nomi dei file sono case sensitive, quindi non sarà possibile eseguire un controllo di esistenza senza distinzione tra maiuscole e minuscole senza elencare il contenuto della directory.
Per un'implementazione PHP pura, sì. C'è un esempio in the comments for the file_exists
function.
L'altra opzione sarebbe quella di eseguire lo script su un file system senza distinzione tra maiuscole e minuscole.
Grazie! Finito usando questo nella mia risposta. –
Il tuo approccio funziona.
In alternativa è possibile utilizzare glob
per ottenere l'elenco di tutti i file e le directory nella presente directory di lavoro in un array, utilizzare array_map
per applicare strtolower
a ciascun elemento e quindi utilizzare in_array
per verificare se il file (dopo l'applicazione strtolower
) esiste nell'array .
Ho riscontrato lo stesso problema durante la migrazione da IIS ad Apache. Di seguito è il pezzo che ho montato. Restituisce il percorso corretto come stringa o 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();
}
ho migliorato la funzione John Himmelman
s' e venire con questo:
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;
}
ho sintonizzato la funzione un po' lil più. Immagino che questo meglio per l'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;
}
Dopo aver trovato questa pagina da un google rapido ho usato Kirk
's soluzione, tuttavia è lento se lo si chiama più volte sulla stessa directory o in una directory che ha molti file in . Ciò è dovuto ad esso loop su tutti i file ogni volta, così ho ottimizzato un po ':
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)]);
}
ho lasciato cadere la bandiera per verificare la presenza tra maiuscole e minuscole, come presumo che ci basta usare file_exists
se didn' Ho bisogno di questo comportamento, quindi la bandiera sembrava ridondante. Mi aspetto anche che se stai facendo qualcosa oltre a uno script banale, vorresti trasformarlo in una classe per avere più controllo sulla memorizzazione nella cache dell'elenco di directory, ad es. resettandolo, ma questo va oltre lo scopo di ciò di cui avevo bisogno e dovrebbe essere banale da fare se ne hai bisogno.
Questa domanda è vecchia di alcuni anni ma è collegata a duplicati, quindi ecco un metodo semplice.
Restituisce false
se il $filename
in ogni caso non si trova nel $path
o il nome del file effettivo del primo file restituito da glob()
se è stato trovato in ogni caso:
$result = current(preg_grep("/$filename$/i", glob("$path/*")));
Rimuovere il current()
di restituire tutto file corrispondenti. Questo è importante su file system sensibili al maiuscolo/minuscolo come IMAGE.jpg
e image.JPG
possono esistere entrambi.
La mia soluzione sintonizzati, indipendente dal sistema operativo, case-insensitive realpath()
alternativa, che copre tutto il percorso, chiamato 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));
}
di ricerca il nome del file con il glob [nN][aA][mM][eE]
motivo sembra essere la soluzione più veloce
Le altre risposte potrebbero consumare molta risorse su file system di grandi dimensioni (un gran numero di file da cercare). Potrebbe essere utile creare una tabella temporanea di tutti i nomi di file (percorso completo se necessario). Quindi fai una ricerca di condizioni simili a quella tabella per ottenere qualunque sia il caso reale.
SELECT actual_file_name
FROM TABLE_NAME
WHERE actual_file_name LIKE 'filename_i_want'
//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);
}
Proprio imbattuto in questo oggi, ma non come una delle risposte qui, così ho pensato che vorrei aggiungere la mia soluzione (utilizzando SPL e l'iteratore 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;
}
il modo in cui sto usando è in questo modo:
$filepath = 'path/to/file.php';
if(false !== ($filepath = _file_exists($filepath))){
//do something with $filepath
}
in questo modo si utilizzerà il costruita in un primo momento, se questo fallisce userà l'ins uno competitivo e assegnare l'involucro corretto alla variabile $filepath
.
- 1. PHP case-insensitive explode()
- 2. Case-insensitive switch-case
- 3. KeyedCollection String Case Insensitive
- 4. Case-insensitive find_or_create_by_whatever
- 5. Javascript contiene case insensitive
- 6. case-insensitive espressioni regolari
- 7. NSMutableArray ordinamento - case insensitive
- 8. Case-insensitive sostituzione PowerShell
- 9. Type.GetType case insensitive - WinRT
- 10. Entity Framework - case insensitive Contiene?
- 11. ricerca case-insensitive di MySQL?
- 12. case sensitive su Mac per file_exists()?
- 13. PHP Phar - file_exists() problema
- 14. Can NSFetchRequest propertiesToGroupBy essere case insensitive?
- 15. Case-insensitive di ricerca di matrice
- 16. Case-insensitive sorta ordinamento in NHibernate
- 17. Vim: case-insensitive ex modalità di autocompletamento
- 18. lista di ordinamento case insensitive utilizzando operator.attrgetter
- 19. django-orm case-insensitive order by
- 20. Mongo DB ordinamento Con case insensitive
- 21. Come aggiungere un'opzione case-insensitive di Array.indexOf
- 22. Django di query case-insensitive partita
- 23. is_file o file_exists in PHP
- 24. caratteri speciali nel problema "file_exists" (php)
- 25. PHP file_exists() restituisce false su alcuni file
- 26. PHP file_exists con accenti restituisce false
- 27. Come confrontare le stringhe con case insensitive e l'accento insensibile
- 28. Come faccio a rendere Apache case insensitive usando .htaccess?
- 29. Usando sed per cancellare una case insensitive linea abbinato
- 30. Ordina case insensitive nelle ultime versioni di Notepad ++
la cosa è, file_exists IS senza distinzione tra maiuscole e minuscole – Dwza
-1 - questo ha bisogno di chiarimenti. È per un file system sensibile al maiuscolo/minuscolo. In caso contrario, la domanda è senza senso, poiché 'file_esistenze()' di PHP non fa distinzione tra maiuscole e minuscole per i file su file system senza distinzione tra maiuscole e minuscole. – danorton