简体   繁体   English

PHP unlink() 处理异常

[英]PHP unlink() handling the exception

Well, I have been wondering if I can handle the unlink() function properly.好吧,我一直想知道我是否可以正确处理unlink() function。 I dont want the unlink() function to throw some nasty error if it is unable to unlink the file (may be due to the File not found).我不希望unlink() function 如果无法取消链接文件(可能是由于找不到文件)抛出一些讨厌的错误。

I tried something like我尝试了类似的东西

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

But it is not working.但它不起作用。 I am no expert in PHP.我不是 PHP 方面的专家。 I searched and found this exception handling code somewhere in the web.我在 web 的某处搜索并找到了这个异常处理代码。 But as I can remember my school days, the same was used for Java.但我记得我的学生时代,Java 也是如此。 SO it should have worked.所以它应该工作。 I dont know whats wrong with the code.我不知道代码有什么问题。

Or can I simply use a if..else statement like或者我可以简单地使用 if..else 语句,如

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

But this code isnt working either.但是这段代码也不起作用。 Where am I doing the mistake?我在哪里做错了? What are the other ways to handle it properly?还有什么其他方法可以正确处理它?

Can the errors be hidden by manipulating with the error reporting (PHP) (Production and Development environment)??可以通过使用错误报告(PHP)(生产和开发环境)来隐藏错误吗?

NOTE: This probably won't work any longer.注意:这可能不再起作用。 See Brian's comment见布赖恩的评论

If you want to only suppress the error, you can do this:如果你只想抑制错误,你可以这样做:

@unlink('your_file_name');

Generally, in PHP, @ will suppress any error.通常,在 PHP 中,@ 会抑制任何错误。

The better way is minimize the error probability.更好的方法是最小化错误概率。 You've say that one of error possibility is caused by non-exist file.您已经说过错误可能性之一是由不存在的文件引起的。 If I were you, I'll do this:如果我是你,我会这样做:

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

Good luck :)祝你好运 :)

unlink doesn't throw exceptions, in generates errors. unlink不会抛出异常,会产生错误。 The proper way to do this is check that the file exists before trying to call unlink on it.正确的方法是在尝试调用unlink之前检查文件是否存在。 If you are merely worried about not having the errors output then you should just turn off display_errors which you should always do in a production environment anyway.如果您只是担心没有错误输出,那么您应该关闭display_errors ,无论如何您应该在生产环境中始终这样做。 Then they will just be logged.然后他们将被记录。

Do not suppress errors with the @ , its rarely advisable.不要用@抑制错误,它很少是可取的。

Can you be more descriptive about @你能更详细地描述@

Im not sure what you mean exactly.我不确定你的意思是什么。 But the documentation is here .但是文档在这里 As far as why you don't want to use it... That is because then you never know that code isn't working or is problematic.至于为什么你不想使用它......那是因为你永远不知道代码不起作用或有问题。 Even if the code still works from a functional perspective it's still got an issue and that issue could potentially make something else completely not work at some point.即使从功能的角度来看代码仍然有效,它仍然存在问题,并且该问题可能会使其他某些东西在某些时候完全无法工作。 If you never have the error you'll probably waste a lot of time debugging.如果您从未遇到过错误,您可能会浪费大量时间进行调试。

Its fine to change your log level or disable the display of errors, but you never want to completely suppress them.更改日志级别或禁用错误显示很好,但您永远不想完全抑制它们。

This method may seem strange but I believe it is the most foolproof one, it accounts for "race conditions".这种方法可能看起来很奇怪,但我相信它是最万无一失的方法,它说明了“竞争条件”。

is_file 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
}

Why?为什么?

Firstly is_file is the correct method to check if a FILE exists not file_exists .首先is_file是检查 FILE 是否存在而不是file_exists的正确方法。 file_exists checks for both directories and files so may return the TRUE for a directory with the same filename, you cannot remove a directory with unlink and doing so will throw an error. file_exists检查目录和文件,因此对于具有相同文件名的目录,可能会返回TRUE ,您不能使用unlink删除目录,这样做会引发错误。

Checking a file exists( is_file ) before you unlink is the correct/best way to delete a file.取消链接之前检查文件是否存在( is_file )是删除文件的正确/最佳方法。

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

But it is not a foolproof method as it is common for a file to be deleted in the small window between the is_file check and the unlink .但这不是万无一失的方法,因为在is_file check 和unlink之间的小窗口中删除文件是很常见的。 I have experianced this several times when a caching method uses the filesystem.当缓存方法使用文件系统时,我已经多次体验过这种情况。

But it is best method available.但这是最好的方法。

So you can do everything right and still get an error!所以你可以做正确的一切,但仍然会出错!

Well at least the error tells you if it fails....well actually you can tell if it fails without the error好吧,至少错误会告诉你它是否失败......实际上你可以在没有错误的情况下判断它是否失败

unlink取消链接

Returns TRUE on success or FALSE on failure.成功时返回TRUE ,失败时返回FALSE

If you have coded it correctly and can differentiate between a success and failed unlink then YES suppress the error , it does not benifit you or your code.如果您对它进行了正确编码并且可以区分成功和失败的取消链接,那么YES 会抑制错误,它不会使您或您的代码受益。

Whether the error is suppressed or not, This is the best method i can think of to prevent it from happening.无论错误是否被抑制,这是我能想到的防止它发生的最好方法。 By reducing the time between the check and the delete you will reduce the likeliness of it throwing an error.通过减少检查和删除之间的时间,您将减少抛出错误的可能性。

EDIT: updated link URLs编辑:更新的链接 URL

You can use is_writable to test whether you have proper permissions to modify or delete a file.您可以使用is_writable来测试您是否具有修改或删除文件的适当权限。

http://php.net/manual/en/function.is-writable.php 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 */ }

My experience says that calling file_exists() just before calling unlink() does NOT work, even if clearstatcache() was called just before calling file_exists() .我的经验说,调用file_exists()只调用的unlink()之前工作,即使clearstatcache()函数被调用只调用file_exists()之前。

There are many combinations of PHP versions and operating systems and the only way that I have found that always works (that is, avoids showing the warning message in case of error) is making my own function silent_unlink() : 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;
}

It disables the error reporting of warnings just for calling unlink() and restores the previous error_reporting() status.它禁用仅用于调用unlink()的警告错误报告并恢复先前的error_reporting()状态。

Handling "Resource Unavailable" error by unlink() as Exception using try catch使用 try catch 通过 unlink() 作为异常处理“资源不可用”错误

Even is_file() or file_exists() will check for file is exists or not, there are chances that file is being used by some applications that will prevent deletion and unlink() will display "Resource Unavailable" error .即使is_file()file_exists()也会检查文件是否存在,有可能文件正在被某些应用程序使用,这将阻止删除,并且unlink()将显示“资源不可用”错误

So after trying many methods like: is_resource() , is_writable() , stream_get_meta_data() ...etc, I reached the only best way to handle error while "deleting" a file that is either not exists or is exists but being used by some application因此,在尝试了许多方法后,例如: 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.
}

Use PHP_Exceptionizer https://github.com/DmitryKoterov/php_exceptionizer/blob/master/lib/PHP/Exceptionizer.php使用 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;
    }
if (file_exists($file) && is_writable($file)) {
    return  unlink($file);
}

Error suppression operator is said to be costly, it has the potential drawback of hiding unexpected errors and the problem it solves almost always has better solutions.据说错误抑制算子成本很高,它具有隐藏意外错误的潜在缺点,并且它解决的问题几乎总是有更好的解决方案。

In this case, though, we're already doing a non-trivial I/O operation (thus added processing time may not be a big deal), we're calling an individual builtin function (which limits the error masking issue) and there's no way to prevent the warning from triggering.但是,在这种情况下,我们已经在进行重要的 I/O 操作(因此增加的处理时间可能不是什么大问题),我们正在调用一个单独的内置 function (它限制了错误屏蔽问题)并且有没有办法阻止警告触发。 If we're able to trap the warning message, perhaps we have a legit use case for @ :如果我们能够捕获警告消息,也许我们有一个合法的@用例:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM