2010-10-19 18 views
12

Tôi đang cố gắng nghĩ cách nhanh nhất để triển khai hàm file_exists không phân biệt dạng chữ trong PHP. Tôi có đặt cược tốt nhất để liệt kê tệp trong thư mục và thực hiện một phép so sánh strtolower() với strtolower() cho đến khi tìm thấy một kết quả phù hợp không?Phiên bản PHP không phân biệt chữ hoa chữ thường của file_exists()

+1

vấn đề là, file_exists IS phân biệt chữ hoa chữ thường – Dwza

+1

-1 - điều này cần làm rõ. Đây có phải là hệ thống tệp phân biệt chữ hoa chữ thường hay không. Nếu không, câu hỏi là vô nghĩa, vì 'file_exists()' của PHP không phân biệt dạng chữ cho các tệp trên các hệ thống tệp phân biệt chữ hoa chữ thường. – danorton

Trả lời

24

Tôi đã sử dụng nguồn từ nhận xét để tạo chức năng này. Trả về tệp đường dẫn đầy đủ nếu được tìm thấy, FALSE nếu không.

Không hoạt động không phân biệt chữ hoa chữ thường trên tên thư mục trong tên tệp.

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

Sẽ không hay khi LUÔN trả lại tên đầy đủ? Thật kỳ lạ khi đôi khi có được một con đường boolean và đôi khi là một con đường hữu ích khi tìm thấy một trận đấu. –

+4

bạn sẽ trả lại gì nếu tệp không tồn tại? O_o – Jonathan

+1

Tôi nghĩ rằng 'fileExists' chức năng nên trả về' true', nếu tập tin tồn tại :) –

3

Trong tên tệp Unix phân biệt chữ hoa chữ thường, vì vậy bạn sẽ không thể thực hiện kiểm tra sự tồn tại phân biệt chữ hoa chữ thường mà không liệt kê nội dung của thư mục.

0

Để thực hiện PHP thuần túy, có. Có một ví dụ trong the comments for the file_exists function.

Tùy chọn khác sẽ là chạy tập lệnh của bạn trên hệ thống tệp phân biệt chữ hoa chữ thường.

+0

Cảm ơn! Kết thúc bằng cách sử dụng điều này trong câu trả lời của tôi. –

2

Cách tiếp cận của bạn hoạt động.
Hoặc bạn có thể sử dụng glob để lấy danh sách tất cả các tệp và thư mục trong thư mục làm việc hiện tại trong một mảng, sử dụngđể áp dụng strtolower cho từng phần tử và sau đó sử dụng in_array để kiểm tra xem tệp của bạn (sau khi áp dụng strtolower) tồn tại trong mảng .

1

Tôi gặp sự cố tương tự khi chúng tôi di chuyển từ IIS sang apache. Dưới đây là phần tôi đánh lên. Nó trả về một trong hai đường dẫn đúng như một chuỗi hoặc sai.

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

tôi đã được cải thiện chức năng John Himmelman 's và đưa ra với điều này:
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; 
} 
1

tôi điều chỉnh chức năng hơn một chút lil. đoán này tốt hơn để sử dụng

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

Sau khi tìm thấy trang này từ một google nhanh chóng tôi đã sử dụng giải pháp Kirk 's, tuy nhiên nó là chậm nếu bạn gọi nó nhiều lần trên cùng một thư mục, hoặc trên một thư mục có nhiều file trong . Điều này là do nó Looping trên tất cả các tập tin mỗi lần, vì vậy tôi tối ưu hóa nó một chút:

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

anh đã đánh rơi lá cờ để kiểm tra các trường hợp vô hồn như tôi giả sử bạn muốn chỉ cần sử dụng file_exists nếu bạn trai tôi' t cần hành vi này, vì vậy lá cờ dường như dư thừa. Tôi cũng hy vọng rằng nếu bạn đang làm bất cứ điều gì ngoài một kịch bản tầm thường, bạn muốn biến điều này thành một lớp để kiểm soát nhiều hơn bộ đệm ẩn danh sách thư mục, ví dụ: đặt lại nó, nhưng đó là vượt ra ngoài phạm vi của những gì tôi cần và nó sẽ là tầm thường để làm gì nếu bạn cần nó.

1

Câu hỏi này là một vài năm tuổi nhưng nó được liên kết với các bản sao nên đây là một phương pháp đơn giản.

Returns false nếu $filename trong mọi trường hợp không tìm thấy trong các $path hoặc tên tập tin thực tế của các tập tin đầu tiên được trả về bởi glob() nếu nó đã được tìm thấy trong mọi trường hợp:

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

Tháo current() trả lại tất cả các tệp phù hợp. Điều này rất quan trọng đối với các hệ thống tệp phân biệt chữ hoa chữ thường là IMAGE.jpgimage.JPG đều có thể tồn tại.

0

My giải pháp điều chỉnh, hệ điều hành độc lập, case-insensitive realpath() thay thế, bao gồm cả con đường, mang tên 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)); 
} 

tìm kiếm tên tập tin với glob [nN][aA][mM][eE] mẫu dường như là giải pháp nhanh hơn

-1

Những câu trả lời khác có thể được rất nhiều nguồn lực trên hệ thống tập tin lớn (số lượng lớn các tập tin để tìm kiếm thông qua). Nó có thể hữu ích để tạo ra một bảng tạm thời của tất cả các tên tập tin (đường dẫn đầy đủ nếu cần thiết). Sau đó thực hiện tìm kiếm điều kiện giống như bảng đó để nhận được bất kỳ trường hợp thực tế nào.

SELECT actual_file_name 
FROM TABLE_NAME 
WHERE actual_file_name LIKE 'filename_i_want' 
0
//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

Chỉ cần chạy ngang qua ngày hôm nay, nhưng không giống như bất kỳ các câu trả lời ở đây, vì vậy tôi nghĩ tôi sẽ thêm giải pháp của tôi (sử dụng SPL và iterator 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; 
} 

Cách tôi đang sử dụng nó giống như vậy:

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

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

Bằng cách này, nó sẽ sử dụng được xây dựng trước, nếu không sử dụng được một cách chính xác, và gán cho vỏ thích hợp với biến số $filepath.

Các vấn đề liên quan