PHP : Extraindo arquivos zipados

maio 17th, 2009 | by DragaO~ |

Estou vindo aqui novamente para disponibilizar mais um script que, ao meu ver, é de bastante utilidade ;)

O script a seguir faz a simples tarefa de excluir um arquivo zipado, porém, essa simples tarefa pode ser muito útil, principalmente para quem, assim como eu, envia muitos arquivos pelo FTP o dia todo. Como já devem ter percebido, enviar um arquivo grande é muito mais rápido do que enviar diversos arquivos pequenos, e é justamente aí que essa função aparece :)
Neste post, explicarei de um modo diferente para facilitar, vou comparar a manipualação com um outro post, o Script PHP : Lendo pastas/diretórios recursivamente, pois acho que vai facilitar a compreensão do script (e talvez ajude até mesmo quem ainda encontra dificuldades em manipular pastas ;))

O funcionamento é bastante simples, basta informar qual o arquivo a ser extraído que a função faz todo o resto; veja o script :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?
/**
 * funcao que extrai arquivos .zip
 *
 * @author DragaO~ <http://blog.pensaofunbari.com/dragao>
 * @version 0.1-2009-05-17
 *
 */
 
function unzip($zip)
{
	//pegando o caminho completo do arquivo zip
	$caminho = dirname($zip);
	//abrindo o arquivo zip
	$zip = zip_open($zip);
	//lendo todo o conteudo do arquivo zip
	while(($elemento = zip_read($zip)) != false)
	{
		//pegando o nome do arquivo/diretorio em questao
		$nome = zip_entry_name($elemento);
		//descartando os diretorios "." e ".."
		if($nome != '.' && $nome != '..')
		{
			//verificando o tamanho total do elemento
			if(zip_entry_filesize($elemento))
			{
				//se possui tamanho, entao nao eh uma pasta, logo, devemos
				//criar um arquivo com o mesmo nome
				$arquivo = fopen($nome, 'wb');
				//escrevendo todo o conteudo do elemento para o arquivo que
				//acabamos de criar
				fwrite($arquivo, zip_entry_read($elemento, zip_entry_filesize($elemento)));
				//fechando o arquivo que criamos
				fclose($arquivo);
				//voltando para o while
				continue;
			}
			//se a pasta nao existir, cria
			if(!file_exists($caminho . '/' . $nome))
			{
				mkdir($caminho . '/' . $nome);
			}
		}
	}
	return 0;
}
unzip(dirname(__FILE__) . '/arquivo.zip');
?>

vale lembrar que essa função funciona apenas em PHP 5.2.0 ou superior (parece que funciona na 4.1.0 ou superior, mas eu não tenho como testar, por isso feedbacks são bem-vindos).

Apesar de manipulção de arquivos zip, ao meu ver, ser bastante parecida com a manipulação de arquivos, vou explicar as linhas :

15
$zip = zip_open($zip);

aqui estamos apenas abrindo o nosso arquivo zip e colocando o identificador em uma variável; se fôssemos comparar a manipulação de pastas/diretórios com a manipulação de arquivos zip, poderíamos dizer que o código acima é o equivalente à nossa linha 5 do primeiro script de leitura recursiva de diretórios.

17
while(($elemento = zip_read($zip)) != false)

aqui estamos fazendo uma verificação e atribuição, basicamente estamos atribuindo o nome de um dos arquivos/pastas do nosso arquivo zip à uma variável, e estamos testando se ela possui conteúdo, ou seja, estamos fazendo um laço para percorrer todos arquivos do nosso zip. O interessantes dessa função é que ela “sabe” quando o elemento que estamos testando é uma pasta, e ela também “sabe” que ela deve entrar na pasta, portanto, não precisamos nos preocupar com a recursividade, pois a função nativa do php faz isso para nós (o que, particularmente, achei bastante estranho). Essa linha é equivalente à linha 7 do primeiro script de leitura recursiva de diretórios, com a diferença de que, essa função não nos retorna o nome de um arquivo, mas sim, um novo ponteiro para um elemento de dentro do zip.

20
$nome = zip_entry_name($elemento);

aqui estamos armazenando o nome do arquivo/pasta em questão, sem muitos mistérios :). Esta linha pode ser comparada com mais exatidão à variável “$diretório” do nosso script de manipulação de diretórios.

22
if($nome != '.' && $nome != '..')

aqui estamos verificando se o nome do arquivo é “.” (diretório atual) ou “..” (um diretório acima), apenas para evitar loops infinitos. Corresponde à linha 11 do script de manipulação de diretórios.

25
if(zip_entry_filesize($elemento))

como a função “zip_read()” nos retorna um ponteiro, nós não podemos testar para ver se é um diretório (como acontece na linha 15 do script de manipulação de diretórios), portanto, aqui estou utilizando a função “zip_entry_filesize()” para verificar o tamanho do elemento em questão, e, caso ele seja 0 (zero), o elemento é um diretório, simples não? Tem o mesmo efeito que a linha 15 do script de manipulação de diretórios.

29
$arquivo = fopen($nome, 'wb');

aqui estamos fazendo manipalação de arquivos “pura”, sem mistério algum; estamos apenas abrindo/criando um arquivo com o mesmo nome do elemento do nosso arquivo zip.

32
fwrite($arquivo, zip_entry_read($elemento, zip_entry_filesize($elemento)));

aqui estamos escrevendo, dentro do nosso arquivo criado, todo o conteudo do nosso elemento. A função “zip_entry_read()” recebe dois parâmetros, um deles é o elemento que queremos ler e o outro é o tamanho total que queremos ler, que, no nosso caso foi todo o elemento.

34
fclose($arquivo);

aqui estamos apenas fechando o nosso arquivo, nada como uma boa prática :)

36
continue;

aqui, para quem não sabe, estamos fazendo com que a execução ignore tudo que tem abaixo e volte para o laço. É mais ou menos como um “break”, mas no caso do “break” ele encerra a execução do laço/condicional, o “continue” faz com que o fluxo do laço prossiga prossiga.

39
if(!file_exists($caminho . '/' . $nome))

caso o nosso script cheguq até esta parte, é porque o elemento em questão não possui tamanho algum, deduzimos então que se trata de uma pasta, e, o que devemos fazer, nada mais é do que criar a pasta, porém, devemos verificar se a pasta já existe, que é o que estamos fazendo aqui :)

41
mkdir($caminho . '/' . $nome);

finalmente, se a pasta nao existir, criamos ela

a chamada do nosso script é bem fácil, bastando apenas informar o caminho do nosso arquivo zip, assim :

47
unzip(dirname(__FILE__) . '/arquivo.zip');

pronto, agora podemos compactar nossos projetos enormes e enviar eles compactados :)
Existem, ao meu ver, duas grandes vantagens em se fazer isso :

  1. Diminuição do tamanho total dos scripts: o wordpress, por exemplo, descompactado possui 6 Mb, compactado com zip, possui apenas 2 Mb, 3 vezes menos
  2. Processamento no envio dos arquivos: normalmente os FTP’s fazem o upload verificando se o arquivo local existe no servidor remoto, se existir, pergunta o que fazer, e só então faz o upload; no caso de arquivos zip, isso ocorre apenas uma vez, sem contar que o FTP não precisa ficar entrando e saindo de pastas, ou seja, menos processamento e menos interrupção entre um arquivo e outro (eu diria “nenhuma interrupção, pois existe apenas um arquivo a ser enviado)

Essa função extrai os arquivos do zip no mesmo diretório do zip, mas poderia ser facilmente adaptado para extrair em outro lugar, ou para pegar arquivos zip vindos, por exemplo, de um formulário, aí é contigo :)

referência das estruturas de controle:
while“, “if“, “continue“, “return

referência das funções:
dirname()“, “zip_open()“, “zip_read()“, “zip_entry_name()“, “zip_entry_filesize()“, “fopen()“, “fwrite()“, “zip_entry_read()“, “fclose()“, “file_exists()“, “mkdir()

Até a próxima :)

VN:F [1.4.3_701]
Rating: 7.7/10 (3 votes cast)


Postagens parecidas/interessantes:

  1. 8 Responses to “PHP : Extraindo arquivos zipados”

  2. By Andrew on jun 30, 2009 | Reply

    Como que faço pro script funcionar?
    Onde coloco o caminho que ta as imagens zipadas?
    Outra dúvida, funciona apenas com zip ou rar também?

    Abraços!

    Quote

    VA:F [1.4.3_701]
    Rating: 0.0/5 (0 votes cast)
  3. By DragaO~ on jun 30, 2009 | Reply

    Andrew: Como que faço pro script funcionar?
    Onde coloco o caminho que ta as imagens zipadas?

    renomeie o arquivo que você deseja deszipar como “arquivo.zip” e coloque-o na mesma pasta em que esse script, depois basta rodá-lo para que a pasta seja extraída :)
    caso queira realizar essa operação dinâmicamente, basta colocar o caminho e o nome do arquivo aqui :

    unzip(dirname(__FILE__) . '/arquivo.zip');

    nesse caso, o arquivo deve-se chamar “arquivo.zip” e estar no mesmo diretório onde o script está rodando :)

    e, caso não dê certo, peço que me diga qual a versão do php em que tu está tentando fazer isso; também peço detalhes sobre a instalação e/ou configuração do php (sistema operacional, libs adicionais (caso haja), como foi instalado, etc)

    Andrew:Outra dúvida, funciona apenas com zip ou rar também?Abraços!

    apenas zip, pois o php não possui suporte nativo à arquivos “rar”
    talvez o php venha a possuir suporte nativo à arquivos “rar”, mas não sei como anda isso, mas é fato que existem funções que manipulam arquivos rar :D

    Quote

    VN:F [1.4.3_701]
    Rating: 0.0/5 (0 votes cast)
  4. By Claiton on jul 17, 2009 | Reply

    Bah, n tinha visto este Post ainda…
    Muita boa a função…
    Há muito tempo eu venho usando uma classe que faz isso(além de criar), e acho que deve ter 1 milhão de linhas..uehaheuhe
    Boa, vou migrar…

    Quote

    VA:F [1.4.3_701]
    Rating: 0.0/5 (0 votes cast)
  5. By DragaO~ on jul 21, 2009 | Reply

    pois é, eu sempre tive dúvidas em relação à esse tipo de coisa no php desde que vi no wordpress, aí eu tive a vontade tirar um dia pra aprender isso (não procurei no código do wordpress porque se não eu iria demorar séculos pra achar), no final, acabei descobrindo que é muito mais fácil do que se imagina :D

    e realmente, agora só falta fazer uma função que cria zip e colocar numa classe :D

    Quote

    VN:F [1.4.3_701]
    Rating: 0.0/5 (0 votes cast)
  6. By João Matheus (JOMARUMU) on set 6, 2009 | Reply

    Nossa, agora eu vou começar a fazer meu site em PHP, e tem muitos arquivos que tem mais de 1 mega, mas compactado não tem nem 10% do tamanho, estava testando no XAMPP e funcionou perfeitamente, muito bom esse script.

    Obrigado DragaO~

    Quote

    VA:F [1.4.3_701]
    Rating: 0.0/5 (0 votes cast)
  7. By Claiton on set 9, 2009 | Reply

    Ai DragaO~, fazendo sucesso!! :D

    Quote

    VA:F [1.4.3_701]
    Rating: 0.0/5 (0 votes cast)
  8. By DragaO~ on set 9, 2009 | Reply

    HAUSEuHAUSEHUAHSUeAUSE
    quem me dera 8D

    Quote

    VN:F [1.4.3_701]
    Rating: 0.0/5 (0 votes cast)
  9. By J. Matheus (JOMARUMU) on mai 15, 2010 | Reply

    Quanto tempo que não acessava mais seu blog XD.

    No Xampp foi tudo bem, mas no locaweb não funcionou, mesmo assim não estou mais precisando do script.

    Obrigado e abração.

    Quote

    VA:F [1.4.3_701]
    Rating: 0.0/5 (0 votes cast)

Deixe um comentário

Vai postar algum código? Leia isso antes