gzdeflate() e grande quantidade de dados
Pergunta
Estou construindo uma classe para criar arquivos ZIP em PHP.Uma alternativa ao ZipArchive assumindo que não é permitido no servidor.Algo para usar com esses servidores gratuitos.
Já está meio que funcionando, construir as estruturas ZIP com PHP, e usar gzdeflate() para gerar os dados compactados.
O problema é que gzdeflate() exige que eu carregue o arquivo inteiro na memória e quero que a classe funcione limitada a 32 MB de memória.Atualmente ele armazena arquivos maiores que 16 MB sem nenhuma compactação.
Imagino que deveria compactar os dados em blocos, 16MB por 16MB, mas não sei como concatenar o resultado de dois gzdeflate().
Eu estive testando e parece que requer um pouco de matemática nos últimos 16 bits, mais ou menos buff->last16bits = (buff->last16bits & newblock->first16bits) | 0xfffe
, funciona, mas não para todas as amostras ...
Pergunta:Como concatenar dois fluxos DEFLATEd sem descompactá-los?
Solução
Filtros de fluxo PHP são usados para realizar tais tarefas. stream_filter_append
pode ser usado durante a leitura ou gravação em fluxos.Por exemplo
$fp = fopen($path, 'r');
stream_filter_append($fp, 'zlib.deflate', STREAM_FILTER_READ);
Agora fread
retornará dados deflacionados.
Outras dicas
Isto pode ou não ajudar. Parece que o Gzwrite permitirá que você escreva arquivos sem que eles sejam completamente carregados na memória. Este exemplo da página Manual PHP mostra como você pode comprimir um arquivo usando Gzwrite e 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;
}