【问题标题】:Crazy PHP fopen / fwrite / file_put_contents / move_uploaded_file bug with binary mode writing on CentOS Linux Adding 0x0D to every 0x0A在 CentOS Linux 上使用二进制模式写入的疯狂 PHP fopen / fwrite / file_put_contents / move_uploaded_file bug 添加 0x0D 到每个 0x0A
【发布时间】:2020-09-20 11:34:34
【问题描述】:

无论我在 fopen mode 标志中设置什么设置,该文件似乎都会将 0x0D 添加到我保存的二进制文件中。

它不仅影响fopen/fwrite.. 还影响file_put_contents

file_get_contents 一开始我以为是问题所在.. 但事实证明这个工作正常.. 因为当我使用 bin2hex() 转储文件时,结果很好。

起初我将这个错误归咎于 C++ 中的std::string。但事实证明它甚至与 C++ 没有任何关系,但它实际上是 PHP 的错误,或者可能只有 CentOS linux 和我还没有找到将我的文件存储为二进制文件的解决方案。我能做的最好的事情是可以工作的十六进制字符串转储文件。

看看我的代码和截图。

$target_file = "/privatefiles/" . basename($_FILES["a"]["name"]);
$fileTypeExtension = strtolower(pathinfo($target_file,PATHINFO_EXTENSION));

//Check file extension.
if($fileTypeExtension != "dll" && $fileTypeExtension != "exe" ) die("ER");

// Check file size
if ($_FILES["a"]["size"] > 10*(1024*1024)) //10 MB cap
  die("ER");

//To decode a base64 encoded file (this was a quickfix to fix binary file encoding in C++ part).
$fileContent = file_get_contents($_FILES['a']['tmp_name']);
$fileContent = base64_decode($fileContent);

//fail
$fh = fopen("wtf1.bin", "wb");
fwrite($fh, $fileContent, strlen($fileContent));
fclose($fh);

//fail (exact result as top)
$fh = fopen("wtf2.bin", "wb");
$fileContent = bin2hex($fileContent);
for($i=0;$i<strlen($fileContent);$i+=2)
    fwrite($fh, chr(hexdec(substr($fileContent,$i,2))));
fclose($fh);

//good result.. but not binary
$fh = fopen("wtf3.bin", "w");
$fileContent = bin2hex(base64_decode(file_get_contents($_FILES['a']['tmp_name'])));
fwrite($fh, $fileContent);
fclose($fh);

//good result but not binary
file_put_contents($target_file, $fileContent); //good bin2hex.

//fail same as the top 2 fail's.
file_put_contents($target_file."_", file_get_contents($_FILES['a']['tmp_name'])); //bad same as wtf1.bin or wtf2.bin


这是我的屏幕截图(证明运行上面的代码所发生的事情),并使用 C++ 应用程序启动文件上传(无法出错,因为一开始我使用原始二进制模式发送......然后在这个 0x0D 0x0A 错误之后我将其更改为 base64 编码以解决传输问题.. 结果证明这甚至不是问题,但实际上我相信是 PHP 问题..

这是我上传的原始二进制文件(未更改)(如您所见,我在 0x0A 0x40 处停止以向您展示错误)。

这是相同偏移量的 wtf1.bin(只是一个简单的 1 行 base64_decode 到文件)。

这里是 wtf2.bin(我尝试使用 bin2hex 来解决这个问题,它可以很好地转储它)在相同的偏移量。

这是 wtf3.bin (bin2hex),它在相同的偏移量下效果很好。 (0x846 / 2 = 0x423)(确认相同的偏移量!)

即使是这个简单的上传脚本,也会上传带有 0xA,0xD 的损坏文件

<!DOCTYPE html>
<html>
<head>
  <title>Upload your files</title>
</head>
<body>
  <form enctype="multipart/form-data" action="test.php" method="POST">
    <p>Upload your file</p>
    <input type="file" name="uploaded_file"></input><br />
    <input type="submit" value="Upload"></input>
  </form>
</body>
</html>
<?php
  if(!empty($_FILES['uploaded_file']))
  {
    $path = basename( $_FILES['uploaded_file']['name']);
    print_r($_FILES);
    $size = filesize($_FILES['uploaded_file']['tmp_name']);
    echo "<br>size uploaded = " . $size . "<br>";
    if(move_uploaded_file($_FILES['uploaded_file']['tmp_name'], $path)) {
      echo "The file ".  basename( $_FILES['uploaded_file']['name']). 
      " has been uploaded<br>";
      echo "path = " . $path . "<br>";
      echo "size stored = " . filesize($path);
    } else{
        echo "There was an error uploading the file, please try again!";
    }
  }
?>

当我以二进制格式上传这些字节时会发生错误

BC 09 00 00 83 C4 04 BA E8 57 40 00 8D 64 24 00 8A 08 88 0A 40 42 84 C9

我回到服务器

BC 09 00 00 83 C4 04 BA E8 57 40 00 8D 64 24 00 8A 08 88 0D 0A 40 42 84 C9

【问题讨论】:

  • 在您的 PHP 表单中的任何其他内容之前 - 您可以检查 $_FILES['uploaded_file'] 的大小吗?来自filesize()$_FILES 中的size 属性。如果大小与您的本地文件相同 - 那么问题是不是网络服务器。
  • 那么您究竟在哪里/如何查看文件内容,并查看那些额外的回车符?您是在 服务器上检查它们 - 还是先将它们下载回客户端?
  • @CBroe 我正在使用 SSH FTP (SFTP) 下载它们并在同一个编辑器中查看它们,该编辑器以完美的十六进制模式显示原始文件..,
  • @IVO GELOV i.imgur.com/ybqRtLb.pngi.imgur.com/5tXohiE.png 你是对的,驱动器上的文件大小看起来不错,但是当我在编辑器中打开时,它显示为 25 字节而不是 24 .. 很奇怪...会不会一直是我的编辑。原文:i.imgur.com/n1vFmAm.png 下载:i.imgur.com/5cmsz9R.png 我想我的问题不是编辑器而是 SFTP 客户端(WinSCP)有这个问题。
  • 你确定你是在 FTP “二进制”模式下重新下载的吗? (许多 FTP 客户端都有“ASCII 模式”,它们会尝试在不同操作系统之间翻译行尾。)

标签: php fopen fwrite line-endings file-put-contents


【解决方案1】:

感谢 CBroe 和 IVO GELOV,问题出在我的 FTP/SFTP 客户端 WinSCP 中。我附上了一个屏幕截图,您需要关闭该设置,这样就不会发生此问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-01-17
    • 2020-08-14
    • 2017-03-20
    • 2011-07-29
    • 2011-09-18
    • 2021-05-20
    • 2014-04-25
    相关资源
    最近更新 更多