Enviar mensagem ao usuário trabalhando com as opções do php.ini

Veremos como enviar uma mensagem amigável de “Este arquivo excede o tamanho permitido” (ou algo parecido) quando se permite upload via POST de determinados arquivos na aplicação/site em PHP.

[ Hits: 29 ]

Por: Buckminster em 26/11/2024


O Problema



O problema resume-se em enviar uma mensagem amigável de "Este arquivo excede o tamanho permitido" (ou algo parecido) quando se permite upload via POST de determinados arquivos na aplicação/site em PHP porque o PHP não possui um tipo unknown.

A diretiva do arquivo php.ini upload_max_filesize define o tamanho máximo de arquivo que um usuário pode enviar, enquanto post_max_size define a quantidade máxima de dados que podem ser enviados por meio de um POST em um formulário. Por exemplo, você pode definir upload_max_filesize como 1 megabyte no php.ini, o que significa que o maior arquivo único que um usuário enviará terá 1 megabyte, porém, esse usuário pode enviar 5 arquivos de 1 megabyte se post_max_size estiver definido como 5 megabytes.

Lembrando que, para permitir upload de vários arquivos ao mesmo tempo, é preciso adicionar a propriedade "multiple" ao elemento input no HTML:

<input type="file" id="meuinput" multiple>
Aqui não usaremos essa propriedade 'multiple', pois só permitiremos o upload de um arquivo por vez.

As diretivas file_uploads e max_file_uploads devem estar configuradas no php.ini. Os códigos dos arquivos estão na seção "A Solução".

Nível Intermediário.

Primeiro veremos as diretivas do php.ini:

  • - file_uploads = On (Permite uploads de arquivos HTTP);
  • - max_file_uploads = 10 (Número máximo de arquivos que podem ser enviados em uma única requisição);
  • - post_max_size = 2M (Tamanho máximo dos dados POST que o PHP aceitará, valor 0 desabilita o limite. É ignorada se a leitura dos dados POST está desabilitada por meio de enable_post_data_reading = Off, ou seja, para post_max_size funcionar, enable_post_data_reading deve estar no padrão (comentada) ou não comentada com On;
  • - ;enable_post_data_reading = Off

ou

  • enable_post_data_reading = On;
  • upload_max_filesize = 2M (Tamanho máximo permitido para envio de um arquivo);

Algumas vezes, caso use FCGID com Apache (FPM/FASTCGI), Nginx, etc, tem de se alterar também os arquivos nesses programas para não dar ERRO 500, 413, 400, etc. Por exemplo, no Apache em algumas distribuições Linux tem de se alterar o arquivo /etc/apache2/mods-available/fcgid.conf (ou num vhost.conf) acrescentando uma linha assim:

"FcgidMaxRequestLen 10485760" (10M) tendo o cuidado de deixar esse valor com o mesmo valor de upload_max_filesize no php.ini.

É que o limite para o tamanho do corpo da requisição HTTP estabelecido pelo módulo FastCGI costuma ser de 128 KBytes (131072 bytes) no Apache e 1M no Nginx, o que afeta o tamanho do arquivo para upload com POST, já que o mesmo é enviado no corpo da requisição.

Apache:
Nginx:
Para fins de informação, na RFC 9110 na seção "18.3. Status Code Registration" (link também nas referências) tem os códigos 1XX, 2XX, 3XX, 4XX e 5XX.
O PHP não capta o tamanho do arquivo da aplicação/site quando as diretivas post_max_size e upload_max_filesize estiverem setadas no php.ini para menos do que o tamanho do arquivo enviado (o que sempre acontecerá, pois é isso mesmo que queremos: limitar o tamanho do upload), porém, o PHP "pega" o tamanho do arquivo no cabeçalho da solicitação HTTP quando esta chega no servidor. Por exemplo: quero enviar uma mensagem ao usuário de que o arquivo excedeu o tamanho permitido de upload para determinada aplicação/site, sendo que as diretivas post_max_size e upload_max_filesize estão setadas em 2M e o usuário tenta enviar um arquivo de 10M;

neste caso, a mensagem de "O arquivo excede o limite..." não será exibida com um código simples porque a variável $_FILES[arquivo][size] vem igual a NULL e isso acontece porque o PHP é executado no servidor.

Outro exemplo: caso as diretivas no php.ini estiverem em 10M e o usuário envia um arquivo de 15M, a mensagem não é exibida porque $_FILES[arquivo][size] vem igual a NULL da mesma maneira. Para exibir a mensagem devem-se aumentar as diretivas, porém, isso representa uma incongruência e uma possível falha de segurança, pois estou permitindo no php.ini uploads maiores do que o desejado e/ou do que o servidor suporta no conjunto das requisições feitas por vários clientes e, muitas vezes, ao mesmo tempo. Além disso, para quanto devo aumentar as diretivas?

Não se sabe o tamanho do arquivo ou quantos arquivos um usuário mal intencionado tentará enviar. Alguns colocam um .htaccess no Apache e em conjunto aumentam as diretivas, porém, não é uma boa prática. Aliás, o próprio Apache e o Nginx desaconselham o uso de tal arquivo. O .htaccess é aconselhado somente onde tenha vários usuários do mesmo servidor web, como, por exemplo, um provedor VPS... e ainda assim com restrições.

Para quem tenha interesse, deixo aqui um conversor htaccess para Nginx:
Quando o arquivo é maior do que o permitido e não foram feitas as configurações necessárias, aparece no navegador aquela mensagem padrão do servidor web como, por exemplo, a mensagem do Nginx: "413 Request Entity Too Large nginx/1.10.3" (A entidade solicitada é muito grande), mensagem esta ininteligível para o usuário.
Vamos a um exemplo no caso que nos interessa. Considerando o seguinte trecho de código abaixo, que está comentado no código da próxima página, mas utilizei para teste:

var_dump($_FILES[[b]arquivo[/b]][[b]size[/b]]);
$arquivo = $_FILES[[b]arquivo[/b]];
switch($arquivo) {
case ($arquivo[[b]size[/b]] > (2097152)): //2MB
echo "Este arquivo excede o tamanho de 2MB!";
break;
}
Enviando um arquivo maior do que o limite setado no php.ini gerou o seguinte aviso:

Warning: Undefined array key "arquivo" in /var/www/html/testup/upload.php on line 62

E o

"var_dump($_FILES[[b]arquivo[/b]][[b]size[/b]]);"


gerou o seguinte:

/var/www/html/testup/upload.php:62:null E enviando um arquivo dentro do limite, no caso um arquivo com 312,4KB, gerou somente o var_dump, o que é óbvio:

/var/www/html/testup/upload.php:62:int 319925 No caso da diretiva upload_max_file_size estar setada no php.ini em, por exemplo, 10M, se o usuário enviar um arquivo de 15M o PHP não exibe a mensagem porque a variável $arquivo[size] vem como NULL. Com if else acontece a mesma coisa (entre if else e switch procuro sempre utilizar quando possível o switch, pois a diferença de desempenho em relação ao if else é muito melhor e bem mais rápido).

E caso você colocar no código:

case ($arquivo[[b]size[/b]] > (10485760)):   //10MB
ainda assim o PHP não enviará mensagem e permitirá uploads via POST até o limite permitido no php.ini, no caso, 10MB. Alguns aumentam os limites para 100MB ou mais para poder enviar mensagem ou para evitar o "Warning" do PHP. Contudo, aumentar os limites para 100MB, por exemplo, permitirá que um usuário mal intencionado burle o HTML e envie arquivos com 100MB podendo saturar e travar o servidor, pois você mesmo configurou o PHP para aceitar uploads de 100MB. Lembrando que a diretiva 'max_file_uploads' (número máximo de arquivos que podem ser enviados em uma única requisição) vem com 20 como padrão, ou seja, 20 arquivos de 100MB são 2GB de upload, isso somente de um cliente.

Setando agora o upload_max_filesize em 2.5MB e o post_max_size em 2MB, o var_dump($bytesup) nos diz que a conversão está sendo feita:

/var/www/html/testup/upload.php:51:float 2621440 //2.5MB Na seção "A Solução" no código "upload.php" tem a função que converte string em bytes.

A questão é que por estarem setados os parâmetros no php.ini (e não pode ser diferente), eles vem como NULL quando o arquivo enviado excede o tamanho permitido.

Quando se clica no botão "Enviar" (input type="submit" name="enviar_arquivo" value="Enviar") depois de selecionado um arquivo maior do que 2.5MB, no caso um arquivo de 8.3MB, temos no var_dump($value):

/var/www/html/testup/upload.php:53:
array(size=1)
0 => string [b]8716100[/b](length=7)
Que gerará no PHP o seguinte aviso:

warning: POST Content-Length of 8716100 bytes exceeds the limit of 2097152 bytes in Unknown on line 0

Que nos diz que o Content-Length – tamanho do arquivo selecionado – excede o limite em upload_max_filesize. Sabemos que é em upload_max_filesize porque a variável $uploadmaximo recebe o valor de ini_get(upload_max_filesize) para a conversão, além do que, como foi falado antes, o upload_max_filesize está em 2.5MB e o post_max_size em 2MB.

A questão agora é que o PHP só identifica o tamanho do arquivo enviado pelo HTTP quando a solicitação chega (o que é óbvio, pois o PHP é executado no servidor) e também porque o PHP não tem um tipo unknown, somente um tipo mixed.

Pode se configurar o HTML para restringir os uploads com um input escondido e um input que restringe para aceitar somente PDF:

<input type="hidden" name="MAX_FILE_SIZE" value="2097152">
<input type="file" name="arquivo" id="arquivo" class="inputfile inputfile-1" accept="application/pdf,.pdf">
Porém, o HTML pode ser burlado mais facilmente do que o PHP, mas é obrigatório fazer as sanitizações tanto no cliente quanto no servidor.

A estilização em CSS, caso for colocar em produção os arquivos, aconselho a colocar num arquivo CSS em separado e não deixar inline como está.

Aliás, sugiro fortemente nunca colocar CSS nem Javascript inline no HTML.

Para resolver o problema de enviar uma mensagem amigável, vamos aos códigos na página 2.

    Próxima página

Páginas do artigo
   1. O Problema
   2. A Solução
Outros artigos deste autor

O Kernel Linux

Como agendar um backup automático do PostgreSQL no Cron evitando o problema de senha

Configuração do sistema, DHCP, compartilhamento e DNS no Debian Squeeze

Manutenção de sistemas Linux Debian e derivados com apt-get, apt, aptitude e dpkg

Instalar OBS Studio e VLC no Slackware 15

Leitura recomendada

Upload de imagens com criação de thumbnails em PHP

PEAGLE: Serviço Web de busca indexada em seu servidor local

Organizando fotos de camêra digital

Manipulação de arquivos com PHP

Trabalhando com arquivos em PHP

  
Comentários

Nenhum comentário foi encontrado.


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts