2017-05-13 23 views
-1

說我想知道傳遞給fopen的字符串是表示文件路徑還是有效包裝(例如"/home/user/example.txt" vs "php://input")。這是爲了創建一個從php://input中的內容創建一個tmp文件,以解決PHP wrappersfseek ing限制。如何確定一個字符串是否指向PHP中的有效文件或包裝?

如下圖所示,file_exists作品的文件,但不能用於包裝的URI:

var_dump(file_exists("php://input")); 
var_dump(file_exists("./exists.txt")); 
var_dump(file_exists("./non_existent.txt")); 
var_dump(file_exists("php://garbage")); 

bool(false) 
bool(true) 
bool(false) 
bool(false) 

只有一個返回true是文件。我發現stream_get_wrappers(),但我想避免太複雜的檢查(如使用字符串比較來嘗試檢測包裝)。

使用stream_get_meta_data似乎也起作用,但它需要首先調用fopen,這會阻塞錯誤日誌。

var_dump(stream_get_meta_data(fopen("php://input","r+"))); 
var_dump(stream_get_meta_data(fopen("./exists.txt","r+"))); 
var_dump(stream_get_meta_data(fopen("./non_existent.txt","r+"))); 
var_dump(stream_get_meta_data(fopen("php://garbage","r+"))); 

產生

array(9) { 
    ["timed_out"]=> 
    bool(false) 
    ["blocked"]=> 
    bool(true) 
    ["eof"]=> 
    bool(false) 
    ["wrapper_type"]=> 
    string(3) "PHP" 
    ["stream_type"]=> 
    string(5) "Input" 
    ["mode"]=> 
    string(2) "rb" 
    ["unread_bytes"]=> 
    int(0) 
    ["seekable"]=> 
    bool(true) 
    ["uri"]=> 
    string(11) "php://input" 
} 
array(9) { 
    ["timed_out"]=> 
    bool(false) 
    ["blocked"]=> 
    bool(true) 
    ["eof"]=> 
    bool(false) 
    ["wrapper_type"]=> 
    string(9) "plainfile" 
    ["stream_type"]=> 
    string(5) "STDIO" 
    ["mode"]=> 
    string(2) "r+" 
    ["unread_bytes"]=> 
    int(0) 
    ["seekable"]=> 
    bool(true) 
    ["uri"]=> 
    string(10) "./exists.txt" 
} 
NULL 
NULL 

我可以使用由stream_get_meta_data返回的數組的wrapper_type,但它仍然會噴涌到垃圾如果日誌文件或包裝URI不存在,我想避免。

什麼是最好的方法來檢測是否我的輸入字符串(要傳遞給fopen)包含了現有文件或有效的PHP包裝,或既無一個有效的文件路徑?

更新:我找到了解決問題的解決方法,其代價是額外的fopen調用。我已經在下面回答了這個問題。

+0

似乎並沒有成爲一個東西,至少不是在PHP 7.0,也不是官方文檔: 'PHP -R '的var_dump(function_exists( 「is_stream」));'' '布爾(假) ' –

+0

感謝downvote沒有任何解釋:(先前的研究有多少證據需要顯示在這裏? –

回答

1

更新

我是能夠解決這樣的:

class example { 

    var $file; 

    function open($path) { 
     $testHandle = fopen($path,"rb"); 
       if(!$testHandle) { 
         error_log("Error parsing file: could not open $path"); 
         return false; 
      } 

     $wrapperType = stream_get_meta_data($testHandle)["wrapper_type"]; 
     if ($wrapperType != "plainfile") { 
       $this->file = tmpfile(); 
       fwrite($this->file,file_get_contents($path)); 
       fclose($testHandle); 
     } else { 
       $this->file = $testHandle; 
     } 

    } 

} 

如果通過$path(如php://input)不是直接打開的文件,它會創建一個臨時文件(與tmpfile())並將流的內容寫入該臨時文件,之後關閉$testHandle。但是,如果它是一個從文件系統中打開的文件(例如/path/to/file),它將簡單地將$ this-> file設置爲$ testHandle。

這確保了我一直使用文件句柄;它應該適合我,因爲我正在閱讀的文件都不會超過兆字節左右。不過,我仍然希望能夠放棄額外的打電話。

相關問題