PHP unlink()处理异常


PHP unlink() handling the exception

嗯,我一直在想我是否能正确处理unlink()函数。我不希望unlink()函数抛出一些讨厌的错误,如果它无法解除文件的链接(可能是由于文件未找到)。

我试过像

try { 
    unlink("secret/secret.txt"); 
} catch(Exception $e) { 
    print "whoops!"; 
    //or even leaving it empty so nothing is displayed
} 

但它不起作用。我不是PHP专家。我搜索并发现这个异常处理代码在网络的某个地方。但在我的学生时代,Java也是如此。所以它应该是有效的。我不知道代码有什么问题。

或者我可以直接使用if..else语句,比如

if(unlink($file)){
  //leaving here empty must ensure that nothing is displayed
}else{
  //leaving here empty must ensure that nothing is displayed
}

但是这段代码也不起作用。我哪里出错了?还有什么其他的正确处理方法吗?

可以通过错误报告(PHP)(生产和开发环境)来隐藏错误吗?

注意:这可能不再工作了。请看Brian的评论

如果你只想抑制错误,你可以这样做:

@unlink('your_file_name');

通常,在PHP中,@会抑制任何错误。

更好的方法是最小化错误概率。您说错误可能是由不存在的文件引起的。如果我是你,我会这样做:

if(file_exists('your_file_name')){
    unlink('your_file_name');
}else{
    echo 'file not found';
}

祝你好运:)

unlink不抛出异常,在生成错误。正确的方法是在尝试对其调用unlink之前检查该文件是否存在。如果您只是担心没有错误输出,那么您应该关闭display_errors,无论如何您都应该在生产环境中这样做。然后他们就会被记录下来。

不要抑制@的错误,这是不可取的。

你能更详细地描述一下@

我不确定你到底是什么意思。但是文档在这里。至于你为什么不想用它…这是因为你永远不会知道代码不工作或有问题。即使代码从功能的角度来看仍然可以工作,它仍然存在一个问题,这个问题可能会在某些时候使其他东西完全无法工作。如果您从未出现过错误,那么您可能会浪费大量的调试时间。

更改日志级别或禁用错误显示是可以的,但你绝对不想完全抑制它们。

这个方法可能看起来很奇怪,但我相信这是最简单的方法,它解释了"竞争条件"。

  • mkdir-race-condition
  • file_put_contents-race-condition

is_file

if(is_file($file) && @unlink($file)){
    // delete success
} else if (is_file ($file)) {
    // unlink failed.
    // you would have got an error if it wasn't suppressed
} else {
  // file doesn't exist
}

为什么?

首先,is_file是检查文件是否存在的正确方法,而不是file_exists。file_exists检查目录和文件,因此可能会返回具有相同文件名的目录的TRUE,你不能使用unlink删除目录,这样做会抛出错误。

在取消链接之前检查文件是否存在(is_file)是删除文件的正确/最佳方法。

if(is_file($file) && unlink($file)){

但这不是一个万无一失的方法,因为在is_file检查和取消链接之间的小窗口中删除文件是很常见的。当一个缓存方法使用文件系统时,我已经经历过好几次了。

但这是最好的方法。

所以你可以做正确的一切,仍然得到一个错误!

好吧,至少错误告诉你如果它失败....实际上你可以在没有错误

的情况下判断它是否失败

断开

成功返回TRUE,失败返回FALSE

如果你已经正确地编码了,并且可以区分成功和失败,那么是抑制错误,它对你和你的代码都没有好处。

无论错误是否被抑制,这是我能想到的防止错误发生的最好方法。通过减少检查和删除之间的时间,您将减少抛出错误的可能性。

EDIT: updated link URLs

您可以使用is_writable来测试您是否有适当的权限来修改或删除一个文件

http://php.net/manual/en/function.is-writable.php

try {
  if(!is_writable($file))
      throw new Exception('File not writable');
  unlink($file);
}
catch(Exception $e) { /* do what you want */ }

根据我的经验,在调用unlink()之前调用file_exists()并不工作,即使clearstatcache()在调用file_exists()之前调用

PHP版本和操作系统有很多组合,我发现唯一有效的方法(即避免在错误情况下显示警告消息)是创建我自己的函数silent_unlink():

function silent_unlink( $filename )
{
  $old_er = error_reporting();
  error_reporting( $old_er & ~E_WARNING );
  $result = unlink( $filename );
  error_reporting( $old_er );
  return $result;
}

禁用调用unlink()时的警告错误报告,并恢复之前的error_reporting()状态。

将unlink()错误处理为try catch

即使is_file()file_exists()将检查文件是否存在,也有可能文件正在被一些应用程序使用,这将阻止删除和unlink()将显示"资源不可用"错误

所以在尝试了很多方法之后,比如:is_resource(), is_writable(), stream_get_meta_data()…当"删除"不存在存在但被某些应用程序

使用时,我达到了处理错误的唯一最佳方法
function delete_file($pFilename)
{
    if ( file_exists($pFilename) ) { 
        //  Added by muhammad.begawala@gmail.com
        //  '@' will stop displaying "Resource Unavailable" error because of file is open some where.
        //  'unlink($pFilename) !== true' will check if file is deleted successfully.
        //  Throwing exception so that we can handle error easily instead of displaying to users.
        if( @unlink($pFilename) !== true )
            throw new Exception('Could not delete file: ' . $pFilename . ' Please close all applications that are using it.');
    }   
    return true;
}

=== USAGE ===

try {
    if( delete_file('hello_world.xlsx') === true )
        echo 'File Deleted';
}
catch (Exception $e) {
    echo $e->getMessage(); // will print Exception message defined above.
}

使用PHP_Exceptionizerhttps://github.com/DmitryKoterov/php_exceptionizer/blob/master/lib/PHP/Exceptionizer.php

$exceptionizer = new PHP_Exceptionizer(E_ALL);
try {
        unlink($file)
    }  catch (E_WARNING $e) {
        return false;
    }
if (file_exists($file) && is_writable($file)) {
    return  unlink($file);
}

错误抑制运算符据说是昂贵的,它有隐藏意外错误的潜在缺点,而且它所解决的问题几乎总是有更好的解决方案。

在这种情况下,我们已经做了一个重要的I/O操作(因此增加的处理时间可能不是什么大问题),我们调用了一个单独的内置函数(它限制了错误屏蔽问题),并且没有办法防止触发警告。如果我们能够捕获警告消息,也许我们就有了@的合法用例:

$success = @unlink($path);
$errorInfo = error_get_last();
if ($success === false) {
    $error = $errorInfo['message'] ?? 'unlink() failed';
    throw new 'RuntimeException("Failed to delete file $path: $error");
}