base64_decode在循环中运行时会创建损坏的图像

时间:2013-05-09 17:38:04

标签: php image base64

此代码工作正常(但我担心它会因大型输入文件而失败)。示例一读取整个文件并且不循环,示例2读取3k块并循环直到EOF。

 $in = fopen("in.b64", 'r');
 $out = fopen("out.png", 'wb');
 if ((!$in) || (!$out)) die ("convert: i/o error in base64 convert");
 $first = true;
 while (!feof($in))
 {
    $b64 = fread($in,filesize($in_fn));
    // strip content tag from start of stream
    if ($first) 
    {
        $b64 = substr($b64,strpos($b64,',')+1);
        $first = false;
    }
    $bin = base64_decode($b64);
    if (!fwrite($out,$bin)) die("convert write error in base64 convert");
 }
 fclose($in);
 fclose($out);

虽然此代码会产生损坏的图像:

 $in = fopen("in.b64", 'r');
 $out = fopen("out.png", 'wb');
 if ((!$in) || (!$out)) die ("convert: i/o error in base64 convert");
 $first = true;
 while (!feof($in))
 {
    $b64 = fread($in,3072);
    // strip content tag from start of stream
    if ($first) 
    {
        $b64 = substr($b64,strpos($b64,',')+1);
        $first = false;
    }
    $bin = base64_decode($b64);
    if (!fwrite($out,$bin)) die("convert write error in base64 convert");
 }
 fclose($in);
 fclose($out);

1 个答案:

答案 0 :(得分:1)

虽然3072可以被4整除,但是边界正确排列,你会从它的前面取出一些字符,使它不能正确对齐。另外,base64规范说每64个字符都有一个换行符,这可能会偏移对齐并破坏解析。

我的解决方案维护了一个要解码的字符缓冲区,并且一次只能获取n * 4个字符的块。作为测试,我一次读取21个字节,它似乎工作。需要注意的是,一次的字节数应该大于预期从字符串前面取下的字符(逗号)。

$in = fopen("in.b64", 'r');
$out = fopen("out.txt", 'wb');
if ((!$in) || (!$out)) die ("convert: i/o error in base64 convert");
$first = true;
$buffer = '';
while (!feof($in))
{
   $b64 = preg_replace("/[\s]+/", "", fread($in,21));
   // strip content tag from start of stream
   if ($first)
   {
       $b64 = substr($b64,strpos($b64,',')+1);
       $first = false;
   }
   $buffer .= $b64;
   $length = strlen($buffer);
   $leftover = $length % 4;
   if ($leftover == 0)
   {
     $chunk = $buffer;
     $buffer = '';
   }
   else
   {
     $chunk = substr($buffer, 0, -$leftover);
     $buffer = substr($buffer, $length - $leftover);
   }

   if (!empty($chunk))
   {
     $bin = base64_decode($chunk);
     if (!fwrite($out,$bin)) die("convert write error in base64 convert");
   }
}
fclose($in);
fclose($out);