gzdeflate () et une grande quantité de données
Question
Je construis une classe pour créer des fichiers ZIP en PHP. Une alternative à ZipArchive en supposant que cela n’est pas autorisé sur le serveur. Quelque chose à utiliser avec ces serveurs gratuits.
Cela fonctionne déjà assez, construisez les structures ZIP avec PHP et utilisez gzdeflate () pour générer les données compressées.
Le problème, c’est que gzdeflate () nécessite le chargement de l’ensemble du fichier dans la mémoire et je souhaite que la classe fonctionne avec une mémoire limitée à 32 Mo. Actuellement, il stocke des fichiers de plus de 16 Mo sans aucune compression.
J'imagine que je devrais faire compresser les données par blocs de 16 Mo à 16 Mo, mais je ne sais pas comment concaténer le résultat de deux gzdeflate ().
Je l'ai testé et il semble que cela nécessite quelques calculs dans les 16 derniers bits, sorte de buff- > last16bits = (buff- > last16bits & newblock- > first16bits) | 0xfffe
, ça marche, mais pas pour tous les échantillons ...
Question: Comment concaténer deux flux DEFLATEd sans les décompresser?
La solution
Les filtres de flux PHP sont utilisés pour effectuer de telles tâches. stream_filter_append
peut être utilisé en lisant ou en écrivant des flux. Par exemple
$fp = fopen($path, 'r');
stream_filter_append($fp, 'zlib.deflate', STREAM_FILTER_READ);
Maintenant, fread
vous renverra les données déflatées.
Autres conseils
Cela peut ou peut ne pas aider. Il semble que gzwrite vous permettra d'écrire des fichiers sans les charger complètement en mémoire. Cet exemple de la page du manuel PHP montre comment compresser un fichier avec gzwrite et fopen.
http://us.php.net/manual/en/function .gzwrite.php
function gzcompressfile($source,$level=false){
// $dest=$source.'.gz';
$dest='php://stdout'; // This will stream the compressed data directly to the screen.
$mode='wb'.$level;
$error=false;
if($fp_out=gzopen($dest,$mode)){
if($fp_in=fopen($source,'rb')){
while(!feof($fp_in))
gzwrite($fp_out,fread($fp_in,1024*512));
fclose($fp_in);
}
else $error=true;
gzclose($fp_out);
}
else $error=true;
if($error) return false;
else return $dest;
}