2017-05-13 38 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。

这确保了我一直使用文件句柄;它应该适合我,因为我正在阅读的文件都不会超过兆字节左右。不过,我仍然希望能够放弃额外的打电话。

相关问题