0

This code works fine (but I am concerned it will fail with large input files). Example one reads the whole file and does not loop, example 2 reads 3k chunks and loops until 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);

While this code produces a corrupt image :

 $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);
4

1 回答 1

1

While 3072 is evenly divisible by 4, making the boundaries line up correctly, you're taking some characters off of the front of it, making it not aligned correctly. In addition, the base64 spec says to have a newline every 64 characters, which may offset the alignment and break parsing too.

My solution below maintains a buffer of characters to decode, and only takes chunks of n*4 characters at a time. As a test, I read in 21 bytes at a time, and it seems to work. One caveat, the number of bytes at a time ought to be more than the characters to expect to take off the front of the string (to the comma).

$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);
于 2013-05-09T18:06:49.657 回答