【问题标题】:PHP unlink() handling the exceptionPHP unlink() 处理异常
【发布时间】:2013-02-25 10:16:21
【问题描述】:

好吧,我一直想知道我是否可以正确处理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)(生产和开发环境)操作来隐藏错误吗??

【问题讨论】:

  • 异常在 PHP 中并不通用。只有一些 API 实现了它们,unlink() 如果无法删除文件,将返回 FALSE。 if/else 是正确的方法。
  • 也许先测试file_exists,然后再喂给unlink
  • 测试文件是否存在,它实际上是一个文件,并且您有权删除它。我不喜欢使用 @ 来抑制错误,但我更不喜欢错误。 if ( is_file( $uri ) && is_writable( $uri ) ) { @unlink( $uri ); }

标签: php exception-handling unlink


【解决方案1】:

注意:这可能不再有效。查看布赖恩的评论

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

@unlink('your_file_name');

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

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

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

祝你好运:)

【讨论】:

  • 确实会抑制任何错误...这不是一件好事...-1
  • 查看我编辑的答案。此外,问题只是关于抑制错误。 “可以通过错误报告(PHP)(生产和开发环境)操作来隐藏错误吗?”
  • 是的,除非建议 @ 是个坏主意。你宁愿正确地编码而不是隐藏错误。
  • 问题是存在竞争条件,当调用file_exists 时文件可能存在,但随后另一个进程在调用unlink 函数之前删除了该文件。所以使用@ 可能是最好的选择。
  • 我对cmets中的人的建议,调试时找到@替换为/*@*/
【解决方案2】:

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

不要使用@ 抑制错误,这很少可取。

你能更详细地描述@

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

可以更改日志级别或禁用错误显示,但您永远不想完全抑制它们。

【讨论】:

  • 是的,非常感谢,您的回答也帮助我了解了@ 的概念。你能更详细地描述@ 吗?
  • 对于高流量站点,if (file_exists($path)) unlink($path); 仍然会抛出错误,因为另一个进程在检查/取消链接之间删除了文件。
  • 检查文件是否存在的问题是,如果另一个进程正在使用该文件,警告仍然会显示。
  • 你仍然可以使用@,但是你需要在之后检查错误和FALSE返回值。
【解决方案3】:

这种方法可能看起来很奇怪,但我相信它是最万无一失的,它考虑了“竞争条件”。

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 的目录,这样做会引发错误。

unlink 之前检查文件是否存在(is_file) 是删除文件的正确/最佳方式。

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

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

但这是最好的方法。

所以你可以做所有正确的事情,但仍然会出错!

好吧,至少错误会告诉您它是否失败....实际上您可以判断它是否在没有错误的情况下失败

unlink

成功返回TRUE,失败返回FALSE

如果您已正确编码并且可以区分成功和失败unlink 然后YES 抑制错误,它不会使您或您的代码受益。

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

编辑:更新的链接网址

【讨论】:

  • 不需要使用is_file两次。更直接:if (is_file($file) { if (@unlink($file)) { ...success... } else { ...unlink failed...} } else { ...file doesn't exist... }
  • @ToolmakerSteve 通常,你是对的,但在这种情况下,我认为额外的检查是必要的,因为这个答案和其他答案中提到了竞争条件。如果 unlink() 失败,可能是因为文件在第一次检查时确实存在,但在调用 unlink() 之前在短窗口中被删除。因此,有必要再次调用 is_file() 来询问即使在 unlink() 失败后,该文件是否仍然存在,这将让我们知道该文件是否不存在,或者是否存在应该引起更多关注的错误。
  • @ChrisMorbitzer - 我明白你的意思。如果您不需要/不想区分“失败但文件消失”(意味着它在您尝试删除它时消失了)和“文件不存在”,那么答案中的代码很好。而我建议的代码会说“取消链接失败”,即使现在已经消失了——这样说可能不太好。最好仔细注释代码,解释为什么要这样做。 OTOH,如果想记录竞争条件的发生,那么可以将第二个 is_file 添加到我的版本中,在 ...unlink failed... 分支中。
【解决方案4】:

您可以使用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 */ }

【讨论】:

  • 虽然这是个好主意,但 is_writable() 只告诉您文件本身是否可写。在 Linux(我想可能是 Windows)上,您需要对包含文件的实际文件夹的写入权限才能将其删除,而不是文件本身。事实上,在 Linux 上,只要您对文件夹具有写入权限,您就可以愉快地删除您无法写入的文件(不确定 Windows)。
【解决方案5】:

我的经验表明,在调用 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 上加上“@”本质上不一样吗?您是否遇到过“@”没有抑制错误的情况? OTOH,我看到调用这样的自定义函数的一个好处是,它可以很容易地进行自定义日志记录,或者在开发过程中设置断点。但是对于生产,为什么不将方法的主体设为一行:return @unlink( $filename );
  • 不,@ 不适合我。它适用于其余功能,但不适用于 unlink。上次我检查它对我不起作用时,我在 Apache 2.4 Windows 上使用 PHP 5.4。如前所述,我尝试了很多东西(使用 @ 是我的第一个选择)并且提到的功能是它工作的唯一方式。在每台经过测试的服务器上。
【解决方案6】:

通过 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;
}

=== 用法 ===

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

【讨论】:

    【解决方案7】:

    使用 PHP_Exceptionizer https://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;
        }
    

    【讨论】:

      【解决方案8】:
      if (file_exists($file) && is_writable($file)) {
          return  unlink($file);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-02-29
        • 2016-03-07
        • 2023-04-02
        • 1970-01-01
        • 1970-01-01
        • 2012-09-15
        • 2011-04-03
        相关资源
        最近更新 更多