我们在应用程序中遇到一些问题,人们将图像粘贴到我们的富文本WYSIWYG中,此时它们作为base64编码的字符串存在。例如:
<img src="data:image/png;base64,iVBORw..." />
提交表单已经提交并处理得很好,但是当我们的应用程序生成包含多个图像的页面时,它会导致PHP达到其内存限制,以及膨胀的页面源等。
我所做的是编写一些代码添加到我们的表单处理器中以提取嵌入的图像,将它们写入文件,然后将URL放在src
属性中。问题是,处理图像内存使用量时,峰值是数据大小的4倍,这可能会破坏表单处理器。
<?php
function profile($label) {
printf("%10s %11d %11d\n", $label, memory_get_usage(), memory_get_peak_usage());
}
function handleEmbedded(&$src) {
$dom = new DOMDocument;
$dom->loadHTML($src);
profile('domload');
$images = $dom->getElementsByTagName('img');
profile('getimgs');
foreach ($images as $image) {
if( strpos($image->getAttribute('src'), 'data:') === 0 ) {
$image->setAttribute('src', saneImage($image->getAttribute('src')));
}
}
profile('presave');
$src = $dom->saveHTML();
profile('postsave');
}
function saneImage($data) {
$type = explode('/', substr($data, 5, strpos($data, ';')-5))[1];
$filename = generateFilename('./', 'data_', $type);
//file_put_contents($filename, base64_decode(substr($data, strpos($data, ';')+8)));
$fh = fopen($filename, 'w');
stream_filter_append($fh, 'convert.base64-decode');
fwrite($fh, substr($data, strpos($data, ';')+8));
fclose($fh);
profile('filesaved');
return $filename;
}
function generateFilename($dir, $prefix, $suffix) {
$dir = preg_replace('@/$@', '', $dir);
do {
$filename = sprintf("%s/%s%s.%s", $dir, $prefix, md5(mt_rand()), $suffix);
} while( file_exists($filename) );
return "foo.$suffix";
return $filename;
}
profile('start');
$src = file_get_contents('derp.txt');
profile('load');
handleEmbedded($src);
profile('end');
start 236296 243048
load 1306264 1325312
domload 1306640 2378768
getimgs 1306880 2378768
filesaved 2371080 4501168
presave 1307264 4501168
postsave 244152 4501168
end 243480 4501168
正如您所看到的,尽管尝试使用流过滤器来削减字节,但在保存文件时内存使用量仍会跳入4MB范围。我认为在后台发生了一些缓冲,如果我只是在文件之间进行转录,我会将数据分成块,但我不知道在这种情况下这是否可行/可取。
我可以在任何地方削减内存使用量吗?
file_put_contents()
并且将handleEmbedded()
更改为不通过引用传递具有相同的内存使用量。derp.txt
包含一段HTML,其中包含一个base64编码的图像。:I
答案 0 :(得分:0)
向诺伯特道歉,在我的心理障碍中打洞:
function saneImage($data) {
$type = explode('/', substr($data, 5, strpos($data, ';')-5))[1];
$filename = generateFilename('./', 'data_', $type);
writefile($filename, $data);
profile('filesaved');
return $filename;
}
function writefile($filename, $data) {
$fh = fopen($filename, 'w');
stream_filter_append($fh, 'convert.base64-decode');
$chunksize=12*1024;
$offset = strpos($data, ';')+8;
for( $i=0; $chunk=substr($data,($chunksize*$i)+$offset,$chunksize); $i++ ) {
fwrite($fh, $chunk);
}
fclose($fh);
}
输出:
start 237952 244672
load 1307920 1327000
domload 1308296 2380664
getimgs 1308536 2380664
filesaved 2372712 2400592
presave 1308944 2400592
postsave 245832 2400592
end 245160 2400592