从PHP写入图像文件时出现错误

4

我正在尝试从二进制大对象(Blob)向图像文件写入内容。

 if($_POST['logoFilename'] != 'undefined'){
  $logoFile = fopen($_POST['logoFilename'], 'w') or die ("Cannot create ".$_POST['logoFilename']);

  fwrite($logoFile, $_POST['logoImage']);

  fclose($logoFile);
}

在前面的代码片段中,$_POST['logoImage']是一个BLOB。该文件被正确地写入到根目录,但是该文件无法打开。在ubuntu 11.04上,我收到以下错误信息:
Error interpreting JPEG image file (Not a JPEG file: starts with 0x64 0x61).

如果我创建一个img并将其src设置为blob,BLOB会正确显示。

以下是第一个BLOB代码片段:

data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEBLAEsAAD/2wBDAAgGBgcGBQgHBwcJCQ

$_POST['logoImage'] 怎么会是 BLOB 类型的?如果是通过 POST 上传的,文件应该出现在 $_FILES 中而不是 $_POST - Michael Berkowski
这是通过ajax而不是表单提交的$_POST。 - GAgnew
4个回答

10

您的“Blob”实际上是一个Data URI

data:[<MIME-type>][;charset=<encoding>][;base64],<data>

由于你只需要解码后的数据部分,所以你需要执行以下操作:

file_put_contents(
    'image.jpg',
    base64_decode( 
        str_replace('data:image/jpeg;base64,', '', $blob)
    )
);

但是由于PHP本身支持data://流,你也可以这样做(感谢@NikiC)

file_put_contents('image.jpg', file_get_contents($blob));

如果上述方法不起作用,您可以尝试使用GDlib:

imagejpg(
    imagecreatefromstring(
        base64_decode( 
            str_replace('data:image/jpeg;base64,', '', $blob)
        )
    ), 
    'image.jpg'
);

@Greg 嗯,确保图像在传输过程中没有损坏。$blog内容是否以==结尾? - Gordon
它以“/9k=”结尾,然而当在img对象中通过Javascript正确渲染时,也是以同样的方式结尾。 - GAgnew
@Greg 这是机密信息吗?还是你可以把数据URI放在http://pastebin.com上?我想试试看是否能得到相同的结果。 - Gordon
最后需要注意的是,真正的问题在于我必须将所有空格替换为“+”号。 - GAgnew

0

如果是文件上传控件,$_POST 不会包含信息。您需要查找 处理文件上传$_FILES。(更具体地说,move_uploaded_file

鉴于最新更新,请尝试以下操作:

  // 
  // Export a image blob to a file using either the specific image name
  // @blob     : The actual image blob
  // @fileName : Can be the explicit name (with an extension) or this can be
  //             just a generic file name and the extension (based on data
  //             type) will be appended automatically. This can also include
  //             path information.
  // Exmaples:
  //   storeBlob('data:image/png;base64,...', 'myimage');      ::  saves as myimage.png
  //   storeBlob('data:image/jpg;base64,...', 'img/new.jpg');  ::  saves as img/new.jpg
  function storeBlob($blob, $fileName)
  {
    $blobRE = '/^data:((\w+)\/(\w+));base64,(.*)$/';
    if (preg_match($blobRE, $blob, $m))
    {
      $imageName = (preg_match('/\.\w{2,4}$/', $fileName) ? $fileName : sprintf('%s.%s', $fileName, $m[3]));

      return file_put_contents($imageName,base64_decode($m[4]));
    }
    return false; // error
  }

1
同意。除非这些数据来自于一个不寻常的客户端(如Flash应用程序,或者是在另一台服务器上运行的服务器端代码通过Web服务调用此内容),否则这似乎非常奇怪。使用普通的Web浏览器无法将用户文件系统中的数据传递到POST变量中。 - timdev
你的知识可能需要更新一下。我正在发送一个_BLOB_(它只是一串文本..(或二进制,取决于你如何表示它))。我可以传输任意数量的文本,我不认为XMLHTTPRequest会改变这些数据。 - GAgnew
好的。太糟糕了。首先让我教你如何做,然后也许你可以帮我解决真正的问题,而不是告诉我我已经在做的事情是不可能的。 - GAgnew
@Greg:在你开始开玩笑之前,请在你的PHP页面上尝试使用var_dump($_FILES),然后告诉我我有多离谱。 - Brad Christie
你离谱了。var_dump($_FILES) 输出一个空数组。 - GAgnew
显示剩余6条评论

0

这个函数将会把数据 URI 保存到文件中:

function saveDataUri($blob, $filename = null) 
{

    // generate unique name basing on content
    if (empty($filename)) {
        $filename = md5($blob);
    }

    // parse data URI
    $semiPos = strpos($blob, ';', 5);
    $comaPos = strpos($blob, ',', 5);
    $mime = substr($blob, 5, $semiPos - 5);
    $data = substr($blob, $comaPos + 1);

    $isEncoded = strpos(substr($blob, $semiPos, $comaPos), 'base64');

    if ($isEncoded) {
        $data = base64_decode($data);
    }


    // save image data to file
    switch ($mime) {
           case 'image/png':
                $ext = 'png';
            break;
           case 'image/gif':
                $ext = 'gif';
                break;
           case 'image/jpg':
           case 'image/jpeg':
           default:
                $ext = 'jpg';
                break;  
    }

    $outFile = $filename . '.' . $ext;
    $funcName = 'image' . $ext;
    $result = $funcName(imagecreatefromstring($data), $outFile);

    if ($result) {

        return $outFile;
    }

    return $result;
}

在您的情况下使用:

// some_validation($_POST);
$filename = saveDataUri($_POST['logoImage']);
echo '<img src="' . $filename . '" alt="' . $filename . '" />';

0

如果它真的是一个二进制大对象(blob),你可能想尝试将第二个参数设置为"wb",作为你的fopen()调用。

编辑:你也可以考虑使用file_put_contents(),它是二进制安全的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接