2017-07-23 140 views
2

我發現PHP函數basename()以及pathinfo()具有多字節utf-8名稱的奇怪行爲。 它們刪除所有非拉丁字符,直到第一個拉丁字符或標點符號。但是,之後,後續的非拉丁字符將被保留。帶有多字節UTF-8文件名的PHP basename()和pathinfo()

basename("àxà"); // returns "xà", I would expect "àxà" or just "x" instead 
pathinfo("àyà/àxà", PATHINFO_BASENAME); // returns "xà", same as above 

但奇怪的PATHINFO的目錄名稱部分()工作正常:

pathinfo("àyà/àxà", PATHINFO_DIRNAME); // returns "àyà" 

PHP文件警告說,basename()pathinfo()功能區域設置知道,但這並不pathinfo(..., PATHINFO_BASENAME)pathinfo(..., PATHINFO_DIRNAME)之間證明不一致,更不用說相同的非拉丁字符被丟棄或被接受,這取決於它們相對於拉丁字符的位置。

這聽起來像一個PHP的錯誤。

由於「基本名稱」檢查對於避免directoy遍歷的安全問題非常重要,是否有任何可靠的基本名稱過濾器可以與unicode輸入一起正常工作?

回答

2

我發現改變語言環境可以修復一切。

雖然Apache默認情況下以「C」語言環境運行,但默認情況下,cli腳本以utf-8語言環境運行,例如「en_US.UTF-8」(或者在我的情況下爲「it_IT.UTF-8」) 。在這些情況下,問題不會發生。

因此,Apache的解決方法是在調用這些函數之前將語言環境從「C」更改爲「C.UTF-8」。

setlocale(LC_ALL,'C.UTF-8'); 
basename("àxà"); // now returns "àxà", which is correct 
pathinfo("àyà/àxà", PATHINFO_BASENAME); // now returns "àxà", which is correct 

甚至更​​好,如果你想備份當前的區域,恢復它曾經做過:

$lc = new LocaleManager(); 
$lc->doBackup(); 
$lc->fixLocale(); 
basename("àxà/àyà"); 
$lc->doRestore(); 


class LocaleManager 
{ 
    /** @var array */ 
    private $backup; 


    public function doBackup() 
    { 
     $this->backup = array(); 
     $localeSettings = setlocale(LC_ALL, 0); 
     if (strpos($localeSettings, ";") === false) 
     { 
      $this->backup["LC_ALL"] = $localeSettings; 
     } 
     // If any of the locales differs, then setlocale() returns all the locales separated by semicolon 
     // Eg: LC_CTYPE=it_IT.UTF-8;LC_NUMERIC=C;LC_TIME=C;... 
     else 
     { 
      $locales = explode(";", $localeSettings); 
      foreach ($locales as $locale) 
      { 
       list ($key, $value) = explode("=", $locale); 
       $this->backup[$key] = $value; 
      } 
     } 
    } 


    public function doRestore() 
    { 
     foreach ($this->backup as $key => $value) 
     { 
      setlocale(constant($key), $value); 
     } 
    } 


    public function fixLocale() 
    { 
     setlocale(LC_ALL, "C.UTF-8"); 
    } 
}