2

所以....我正在编写一个小函数,它返回文件是否已被写入,以及不写入的原因....类似于:

array (
    'success' => false,               // easy, by checking function result
    'reason' => 'Permission denied'   // how am I supposed to find this???
)

也许我遗漏了一些东西,但我似乎无法找到一种方法来捕获保存文件失败时的任何错误消息

我的第一个想法是使用输出缓冲来捕获错误,但它超出了范围,容易出错并且是一个巨大的 hack(即,不同类型的错误可能会干扰)。

通常,这对于 OOP 风格的异常处理来说是一项很好的工作,exceptfile_put_contentsf*函数不会抛出任何异常。

似乎SplFileObject可以完成这项工作……但有一个例外;它是一个基于行的类,不适合读取二进制文件

有什么建议么?

PS:叫我懒惰,但我不相信我的代码应该检查所有异常情况(写权限、无法访问的驱动器、错误的路径等)。

4

2 回答 2

2

您提出的建议在表面上听起来是正确的,有一个总体 API,它将执行将文件写入文件系统的基本操作。然而,我认为 PHP 开发人员让我们自己来组合一个满足我们应用程序需求的 API,因为他们确实为我们提供了自己做的基本组件。

下面是File::write我用于文件写入操作的方法片段:

$fileInfo = new SplFileInfo($fileUri);

if (!is_dir($fileInfo->getPath())) {
    // I have some proprietary stuff here but you get the idea        
}

$file = new SplFileObject($fileUri, $mode);

if (!$file->flock(LOCK_EX | LOCK_NB)) {
    throw new Exception(sprintf('Unable to obtain lock on file: (%s)', $fileUri));
} 

elseif (!$file->fwrite($content)) {
    throw new Exception(sprintf('Unable to write content to file: (%s)... to (%s)', substr($content,0,25), $fileUri));
}

elseif (!$file->flock(LOCK_UN)) {
    throw new Exception(sprintf('Unable to remove lock on file: (%s)', $fileUri));
}

elseif (!@chmod($fileUri, $filePerms)) {
    throw new Exception(sprintf('Unable to chmod: (%s) to (%s)', $fileUri, $filePerms));
}

这些只是您可以测试的边缘案例的几个示例,如果您需要测试“驱动器是否已连接”,您可以调用is_writable。因此,您只需将其添加到检查列表中,并以对您的应用程序有意义的消息进行响应。

然后,如果您想记录所述错误,只需将调用代码包装在 try/catch 块中:

try {
    File::write($fileUri);
} catch (Exception $e) {
    error_log($e->getMessage);
}
于 2012-05-02T00:19:17.490 回答
1

更新

@hakre 刚刚给了我一个好主意。与我的系统不一致的是默认的FS实现。

解决它的一种方法是取消注册file://协议的默认流包装器并注册我自己的,这实际上会引发异常。有了这些,我可以同时自由地使用file_put_contents()和捕获异常。

哦,我还可以确保自定义流包装器也是原子的(通过强制锁定)。


到目前为止,这是我想出的。当然,它需要真正的 FS 检查(驱动器/路径存在、权限等)。

    /**
     * Save file to source DSN.
     * @return boolean True on success, false on failure (see last_error for details). 
     */
    public function save(){
        $file = fopen($this->source, 'wb');
        if(!$file){
            $this->_last_error = 'Could not open file stream';
            return false;
        }
        if(!flock($file, LOCK_EX)){
            $this->_last_error = 'Could not lock file for writing';
            return false;
        }
        if(!ftruncate($file, 0)){
            $this->_last_error = 'Could not clear file';
            return false;
        }
        if(fwrite($file, $this->contents)===null){
            $this->_last_error = 'Could not write to file';
            return false;
        }
        if(!fflush($file)){
            $this->_last_error = 'Could not flush to file';
            return false;
        }
        if(!flock($file, LOCK_UN)){
            $this->_last_error = 'Could not unlock file';
            return false;
        }
        if(!fclose($file)){
            $this->_last_error = 'Could not close file';
            return false;
        }
        return true;
    }

非常冗长,并且与我想要的完全不同。通过 FS 检查,这可能会增加很多。

如果一开始就正确编码,那么所有这些代码都可以实现,这是一种耻辱file_get_contents()

于 2012-05-02T00:31:11.167 回答