【问题标题】:Why does PHP think it's writing to a file but it isn't?为什么 PHP 认为它正在写入文件,但事实并非如此?
【发布时间】:2020-07-10 08:19:33
【问题描述】:

我有一个带有 PHP pgm 的 HTML 表单,用于将结果写入文件。我基本上是从网上复制的。这不是火箭手术。它在具有最新 Raspbian 的 Raspberry Pi 上运行 PHP 7。 PHP pgm 报告该文件是可写的,它成功了,等等,但该文件仍然是空的。我已将权限更改为 777(用于测试),但这并没有帮助。我难住了。这是 HTML:

<!DOCTYPE html>
<html>
<head>
<title>Update</title>
</head>
<body>
<FORM NAME ="form1" METHOD ="POST" action="filewrite.php">
<INPUT TYPE = "TEXT" VALUE ="memory" NAME="memory">
<INPUT TYPE = "TEXT" VALUE ="desc"   NAME="desc">
<INPUT TYPE = "TEXT" VALUE ="comm"   NAME="comm">
<INPUT TYPE = "TEXT" VALUE ="reset"  NAME="reset">
<INPUT TYPE = "Submit" Name = "Submit1" VALUE = "Create">
</FORM>
</body>
</html>

这是 PHP(在 filewrite.php 中):

<?php
ini_set('display_errors', true);

if(isset($_POST['memory']) && isset($_POST['desc']) && isset($_POST['comm']) && isset($_POST['reset']))
{
#    $data = $_POST['memory'] . '\t' . $_POST['desc']  . '\t' . $_POST['comm']  . '\t' . $_POST['reset'] . "\n";
    $data = "testing";
    $file = "/tmp/data.txt";

var_dump($_POST);

    if (is_writable($file)) {
       echo nl2br("\n\nThe file is writable\n\n");
    } else {
       echo nl2br("The file is not writable\n\n");
    }

    touch($file);
    $ret = file_put_contents($file, $data, LOCK_EX);
    if($ret === false)
    {
        die('There was an error writing this file');
    }
    else
    {
        echo nl2br("$ret bytes written to file\n");
        echo nl2br("data = $data\n");
        echo nl2br("file = $file\n");
    }
}
else
{
   die('no post data to process');
}

?>

这是我得到的输出:

array(5) { ["memory"]=> string(4) "fred" ["desc"]=> string(6) "barney" ["comm"]=> string(5) "wilma" ["reset"]=> string(5) "betty" ["Submit1"]=> string(6) "Create" }

The file is writable

7 bytes written to file
data = testing
file = /tmp/data.txt

这是文件:

-rwxrwxrwx 1 pi pi 0 Mar 29 16:43 /tmp/data.txt

我在没有文件存在的情况下尝试了它,并且在那里有它。起初我试图将表单数据写入文件,但后来切换到只是尝试编写“测试”。我已经尝试了该文件的其他目录,但它们(如预期的那样)由于权限而失败。

编辑: 当我尝试将文件写入 /home/pi 时(我预计会失败,因为网络服务器是 www-data),我在 /var/log/apache2/error.log 中收到此错误:

[Sun Mar 29 17:04:24.648150 2020] [php7:warn] [pid 12075] [client fe80::cceb:ba3c:da1d:6b2a:53052] PHP Warning:  file_put_contents(/home/pi/data.txt): failed to open stream: Permission denied in /var/www/html/filewrite.php on line 19, referer: http://devberry-pi.local/rwupdate.html

将其设置回 /tmp/data.txt 清除了该错误(并且不会生成其他错误。)

编辑 2: 我将一个 6k 文件复制到 /tmp 以确保有足够的空间并且工作正常。我现在只写 7 个字节(“测试”),并且真的只想写

编辑 3: 全新的卡,全新的安装,同样的结果。 8^( 我认为我的下一步是使用不同的 Raspberry Pi,尽管我不确定硬件可能是什么问题。注意:我可以从命令行在 /tmp 中创建文件。

哦,新开发 -- 我创建了一个新文件夹 /home/www,将其权限设置为 777,它确实成功地在其中创建了文件。 /tmp 的权限是 drwxrwxrwt,它由 root/root 拥有。 webserver/php 用户是 www-data。我可以将其用作解决方法,但在我的书中并不理想。有没有比 /tmp 更好的地方来放置不同用户/pgms 需要访问的东西?

有什么想法吗?我应该看什么?

【问题讨论】:

  • 您好:您的 PHP 错误日志中有什么内容?
  • /var/log/apache2/error.log 中没有任何内容(除了我之前尝试各种疯狂的事情时)。是否还有其他日志文件要检查?
  • /tmp FS 已满?尝试手动将文件写入/tmp/file.txt,cat &gt; /tmp/file.txt ...
  • 我检查了 /tmp 目录 -- 我将一个 6k 文件复制到 /tmp 并且很好...我只是(当前)尝试写入 7 个字节(“测试”)。
  • 检查您的 Pi 的 SD 卡。我有一个表现出类似行为的人,结果发现卡文件系统已损坏。具体来说,似乎所有写入都在工作,但在重新启动后,根本没有写入任何更改。

标签: php raspberry-pi file-handling


【解决方案1】:

您可以使用 PHP 函数 file_put_contents 获取您希望写入的文件名和数据并将其写入文件。在您的情况下,这可能是发送的某种形式的 HTML POST 数据。在下面的解决方案中,我将值编码为 JSON,因为它很好地表示了与此类表单相关联的键/值对。这可以以适合您需要的任何其他形式完成。

我已选择将文件写入与包含表单的 PHP 文件相同的文件夹。这在生产环境中是不现实的,但它表明 PHP 可以保存文件。

如果文件的位置是问题所在,那么权限就是您应该查看的位置,因为在使用以下方法时,这应该是导致文件无法写入的唯一原因。我已在表单字段中输入值以便于测试,但占位符应保留在生产环境中并删除值。

在任何环境中都应该同时进行客户端和服务器端验证。为了简单起见,我已经删除了验证,并且它是题外话,但每个值都应该在进行任何其他操作之前进行测试和过滤。无论如何,这是合并到一个文件中的工作示例:

<?php
/**
 * Check for submission of form.
 */
$nl="<br>";
if (isset($_POST['memory']) && isset($_POST['desc']) && isset($_POST['comm']) && isset($_POST['reset'])) {
    try {
        $data = json_encode($_POST, JSON_PRETTY_PRINT);
        $file = "data.txt";
        if ( file_put_contents ($file, $data) ) {
            $msg = "File successfully saved.";
        } else {
            $msg = "Error saving file";
        }            
    } catch (Exception $e) {
        $msg = "Error saving file:" .$nl.$nl . $e->getMessage() . $nl.$nl . $e-getTrace();
    }
}
?>
<!doctype html>
<html lang="en_US">
<head>
<meta charset='utf-8'>
<title>Example: Save File</title>
</head>
<body>
<?php if (isset($msg)){ echo '< style="color:#100">'.$msg.'</p>'; } ?>
<form name="form1" method="post" enctype="multipart/form-data">
<input type="text" placeholder="memory" name="memory" value="mem">
<input type="text" placeholder="desc"   name="desc" value="something">
<input type="text" placeholder="comm"   name="comm" value="more data">
<input type="text" placeholder="reset"  name="reset" value="reset">
<input type="Submit" Name = "Submit1" value="Create">
</form>
</body>
</html>

此外,提交表单时,您应该在表单标签上设置 enctype 属性。如果您要上传文件&lt;input type="file"&gt;,则必须将其设置为multipart/form-data。这允许通过 HTTP Post 二进制发送数据。

<form enctype="multipart/form-data" action="..." id="....">

此外,正如 MDN 在其文档中指出的那样,您可以将属性添加到 &lt;input&gt;button 元素。:

“...或&lt;input&gt;&lt;button&gt; 元素的formenctype 属性。”

在所有情况下,您都应该指定表单的 enctype,包括在使用 XMLHttpRequest 的异步请求期间。

【讨论】:

    猜你喜欢
    • 2016-05-21
    • 2012-01-26
    • 1970-01-01
    • 2011-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-26
    • 2012-11-14
    相关资源
    最近更新 更多