疯狂 PHP fopen / fwrite / file_put_contents / move_uploaded_file 在 CentOS 上使用二进制模式写入的错误 Linux 将 0x0D 添加到每个 0x0A

Crazy PHP fopen / fwrite / file_put_contents / move_uploaded_file bug with binary mode writing on CentOS Linux Adding 0x0D to every 0x0A

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

它不仅影响 fopen/fwrite.. 而且 file_put_contents.

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

起初我将此错误归咎于 C++ 中的 std::string。但事实证明它甚至与 C++ 没有任何关系,但它实际上是 PHP 的错误或者可能只有 CentOS linux 而我还没有找到一个解决方案来以二进制形式存储我的文件..我能做的最好的是 hexstring 转储文件,它可以工作..

看我的代码和截图。

$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(只是一个简单的 base64_decode 的 1 行文件)。

这是相同偏移量的 wtf2.bin(我尝试使用 bin2hex 解决此问题的一些 hackery,它很好地转储了它)。

这里是 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

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