【问题标题】:'unlink', Permission denied error when executing function [exec]'unlink',执行函数 [exec] 时权限被拒绝错误
【发布时间】:2018-05-11 11:08:09
【问题描述】:

这是文件test1.php

 <?php    
    set_time_limit(0);
    for($i= 1;$i<5000 ;$i++){

        $comm_sjis = "echo 'test'";
        $result = exec($comm_sjis);

    }
    unset($result);
    echo 'ok';

这是文件test2.php

<?php

set_time_limit(0);

function write_txt($str)
{
    $filepath = 'E:/temp/test.xml';
    if (($fp = @fopen($filepath, "a")) === false) {
        return;
    }

    if (!flock($fp, LOCK_EX)) {
        @fclose($fp);
        return;
    }

    if (fwrite($fp, $str . "\n") === false) {
        @flock($fp, LOCK_UN);
        @fclose($fp);
        return;
    }

    if (!fflush($fp)) {
        @flock($fp, LOCK_UN);
        @fclose($fp);
        return;
    }

    if (!flock($fp, LOCK_UN)) {
        @fclose($fp);
        return;
    }

    if (!fclose($fp)) {
        return;
    }
}

for($i= 1;$i<100 ;$i++){

    write_txt('test');  
    unlink('E:/temp/test.xml');
}
echo 'ok';

如果我在运行 test1.php 的同时运行文件 test2.php,则会出现错误:

警告:unlink(E:/temp/test.xml): Permission denied in C:\xampp\htdocs\test2.php on line 45

当我只运行test2.php,没有test1.php时,不会出现这个错误。 为什么 unlink 在我执行函数时会给出 Permission denied 错误?

我在 Windows 7 上使用 XAMPP 3.2 与 php 5.6。

【问题讨论】:

  • 这是因为您的 XML 文件或文件夹需要取消链接该文件的权限test.xml
  • test1 和 test2 似乎彼此不匹配。 test1 是做什么用的,你在哪里创建 test.xml?
  • @Nawin:如果不运行文件test1.php,只运行文件test2.php,就可以了。
  • @Forbs : write_txt('test');创建 test.xml
  • 好的,首先,根据命令,您将连接它们,然后调用 exec 命令。比如说,每 5 次迭代你就会调用 exec。其次,有更好的方法可以在不使用 @ 的情况下避免错误和/或警告,这是非常不鼓励的。在您的情况下,您可以使用 php.net/manual/pt_BR/function.is-resource.php 检查资源是否有效,而不是仅仅将其静音。

标签: php


【解决方案1】:

我通过将 PHP 版本升级到 7.1.12 解决了这个问题

【讨论】:

    【解决方案2】:

    您正在消除fopen 中的错误,这意味着如果文件在任何时候无法打开(例如,可能是因为在 XAMPP 中达到了内存限制),您将无法知道在您的脚本中(您可以在日志中查看它)。

    来自PHP Manual

    bool unlink ( string $filename [, resource $context ] )

    删除文件名。类似于 Unix C unlink() 函数。一个 失败时会产生 E_WARNING 级别的错误。

    unlink 删除文件。这意味着如果您的文件无法使用fopen 打开,并且您还没有创建它,那么它很可能不存在。尝试unlink 一个不存在的文件会导致错误。

    一个简单的解决方案是同时消除 unlink 上的错误。

    @unlink('E:/temp/test.xml');
    

    这样,如果您的函数无法写入文件,它将优雅地失败。另一种选择是在尝试取消链接之前检查文件是否存在。

    $file = 'E:/temp/test.xml';
    if (file_exists($file)) {
        error_log(‘could not write file’);
        unlink($file);
    }
    

    在这种情况下,我最喜欢的选择可能是使用Exceptions。当您无法打开或无法解锁文件时,抛出Exception。在尝试unlink 之前,您可以抓住它、记录问题并打破循环。

    这应该可以帮助您调试正在发生的事情。

    示例: 命名空间测试;

    class FileException extends \Exception { }
    class UnlockFailedException extends FileException { }
    
    function write_txt($str)
    {
        $filepath = 'E:/temp/test.xml';
        if (($fp = @fopen($filepath, "a")) === false) {
            throw new FileException('Could not open file');
        }
    
        if (!flock($fp, LOCK_EX)) {
            @fclose($fp);
            return;
        }
    
        if (fwrite($fp, $str . "\n") === false) {
            @flock($fp, LOCK_UN);
            @fclose($fp);
            return;
        }
    
        if (!fflush($fp)) {
            @flock($fp, LOCK_UN);
            @fclose($fp);
            return;
        }
    
        if (!flock($fp, LOCK_UN)) {
            @fclose($fp);
            throw new UnlockFailedException('Unable to unlock file.');
        }
        /** 
         * This doesn't do anything
         * if (!fclose($fp)) {
         *     return;
         * }
         */
        fclose($fp);
    }
    

    然后:

    $msg = 'ok';
    for($i= 1;$i<100 ;$i++){
        try {
            write_txt('test');  
            unlink('E:/temp/test.xml');
        } catch (FileException $e) {
            error_log($e->getMessage());
            $msg = 'errors detected';
        }
    }
    echo $msg;
    

    通过添加异常处理,你可以自己调试这种行为,找到问题的根源。

    最后几点说明:

    我运行 Linux,因此在 Windows 7 XAMPP 机器上测试这种行为并不容易。但是,我怀疑这是因为系统由于 I/O 资源有限而被锁定。请注意,根据手册,Windows 会在文件上放置 madatory 锁(而在 Linux 中该锁是建议性的)。在有限资源系统上以大规模循环运行flock 和以大规模循环运行echo 可能会导致资源失败。如果您打算在生产中运行类似的东西,您不会经常遇到它,但您仍然需要考虑它。异常处理和错误记录可以确保当文件不工作时,您将有足够的数据进行调试。

    假设unlink 是问题所在,这根本不是一个安全的假设。

    如上所述,取消链接或检查文件是否存在将使此错误静音。

    【讨论】:

    • 我尝试了没有静默错误的脚本,甚至在 write_txt() 函数中返回 true 或 false。没有问题。这是这家伙发现的一个奇怪的行为。该错误与锁定文件有关,如果删除所有有关锁定的指令,则不会出现该错误。请在假设只是猜测之前尝试一下。
    • 你在使用 XAMPP 吗?这有点像你在拖钓。为什么返回 true 或 false 会有所不同?我不需要彻底测试它来了解unlink 的工作原理。我正在尝试编辑问题以使其更清楚。
    • 我认为,问题是函数“exec”和“unlink”一次调用,会出错。
    • 请自行测试。我第一次阅读这个问题对我来说似乎很简单,但我决定在回答之前进行测试,我发现了这个人发现的奇怪行为。但是,他的测试代码还不够好。我提供了我的,所以你可以试试:programadorphpfreelance.com/repositorio/test_unlink-exec.zip 它包含原始文件 1.php 和 2.php 文件,但改进为不让其他错误出现。还有 2b.php 和 3.php 的内容,它们都是 2.php 的替代品,它们在里面包含一个标题注释。是的,我正在使用 XAMPP。不,我不是在拖钓。
    • 对不起,我说锁定文件是获取错误的必要条件,但不,不是。但是,正如您在尝试 3.php 时看到的那样,取消链接不足以得到错误。
    【解决方案3】:

    权限被拒绝,因为该文件正被另一个进程使用。
    在运行到unlink 之前,尝试存档fclose

    【讨论】:

    • 使用了fclose。
    • 我确定您在尝试在其他脚本中调用 fclose 方法之前取消链接文件。这样就不行了。
    • 不,事实并非如此。我理解你也许可以肯定,但我做了一个完整的测试,正如我所评论的,这家伙发现了一个奇怪的行为。
    • 这里是我从原始脚本改进的测试脚本:programadorphpfreelance.com/repositorio/test_unlink-exec.zip它们在标题处进行内容评论。
    【解决方案4】:

    试试这个

     unlink ('E://temp//test.xml');
    

    您可能会注意到您的原始代码使用// 创建但只使用/ 删除。

    【讨论】:

    • 不,'E://temp//test.xml' 被视为'E:/temp/test.xml'。
    猜你喜欢
    • 2015-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-15
    • 2017-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多