Manipulando arquivos carregados por upload no Laravel

Laravel é um framework que tem se tornado bastante popular no mundo do PHP. Uma das vantagens dele sobre outros frameworks é que ele permite que seu código fique limpo e fluído, especialmente pela forma como ele trata as dependências e outras ajudas. Mas isso é assunto para outro momento. Agora, queria falar um pouco sobre

Laravel é um framework que tem se tornado bastante popular no mundo do PHP. Uma das vantagens dele sobre outros frameworks é que ele permite que seu código fique limpo e fluído, especialmente pela forma como ele trata as dependências e outras ajudas. Mas isso é assunto para outro momento. Agora, queria falar um pouco sobre a manipulação de arquivos carregados via upload.

Para começar, queria compartilhar uma situação hipotética: por causa da lógica de negócio por trás do projeto que você está trabalhando, é necessário garantir que arquivos duplicados não sejam carregados via upload. Usar o nome do arquivo nem sempre é a melhor forma de fazer isso porque o usuário pode simplesmente usar outro nome. Então quero compartilhar uma forma de fazer isso usando Laravel.

A documentação do framework não é muito clara a respeito da classe que representa um arquivo carregado. Procurando no código-fonte, porém, é possível encontrar evidências de que o objeto retornado pelo método $request->file() é uma instância da classe SplFileInfo. Isso significa que é possível manipular o arquivo sem grandes complicações. E o melhor: é possível fazer isso antes mesmo de gravar o arquivo no destino final.

Você pode encontrar essa evidência da SplFileInfo na classe File:

Essa referência a uma classe do Symfony pode parecer estranha se você não tem familiriadade com a arquitetura do Laravel, mas ele usa vários componentes do Symfony internamente.

Bom, vamos ver como é possível fazer a manipulação na prática!

Resolvendo um upload

Uma action (método de um controller) simples para upload de arquivo geralmente pega a instância do arquivo do request, verifica se um arquivo foi enviado e grava ele no destino final. Provavelmente algo parecido com isso:

Lendo e comparando o arquivo em partes

Usando aquela instância do arquivo que pegamos do request, podemos escrever um método que compara ela com uma outra instância da classe SplFileInfo. Para agilizar o processamento, você não precisa comparar os arquivos inteiros. Ir por partes é a melhor estratégia. Você pode ler um pedaço do mesmo tamanho de ambos os arquivos e compará-los. Assim que uma diferença for encontrada, pare a execução do método.

Melhorando a performance

A função que escrevemos acima é uma ótima maneira de comparar dois arquivos. Porém, abrir, ler e comparar o conteúdo de cada arquivo enviado anteriormente para a aplicação pode consumir muitos recursos (tempo, I/O, processamento). Podemos reduzir significamente esse consumo comparando o tamanho dos arquivos primeiro, e então apenas abrir e comparar o conteúdo dos arquivos que tiverem o mesmo tamanho. Isso ficaria assim:

Gravando o arquivo

Voltando à action que definimos no começo e usando esse último método que escrevemos, podemos finalmente gravar o arquivo. É importante lembrar de chamar o método de gravação (store) apenas depois de ter verificado se o arquivo já não existe.

Conclusão

Essa é apenas uma maneira de trabalhar com o arquivo retornado pelo request, pensando no que ele é internamente. Existem provavelmente outras mil maneiras de utilizar isso para resolver outros problemas ou ao menos tornar seu código mais fluído.

Também é importante entender que essa é apenas uma forma de fazer isso usando o framework. Você provavelmente pode usar outras táticas para resolver o mesmo problema. Por exemplo, seria possível armazenar o arquivo enviado em um diretório temporário e então fazer as comparações necessárias. Ou você pode aproveitar a lógica descrita aqui e usar as funções nativas do PHP para upload ao invés das funções do Laravel.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *