terça-feira, 5 de novembro de 2024

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

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>

   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" (zero) 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 descomentada com On;
- 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” 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 deve-se 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:

https://winginx.com/en/htaccess

   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.

https://www.cyberciti.biz/faq/linux-unix-bsd-nginx-413-request-entity-too-large/

   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[‘arquivo’][‘size’]);
$arquivo = $_FILES[‘arquivo’];
switch($arquivo) {
    case ($arquivo[‘size’] > (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[‘arquivo’][‘size’]);” 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[‘size’] > (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 (veja a função de conversão no código ao final do texto):

/var/www/html/testup/upload.php:51:float 2621440 //2.5MB

   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 ‘8716100’(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 hidden (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.


A SOLUÇÃO

   Uma solução para enviar mensagens ao usuário informando que o arquivo excede o limite permitido, além de outras mensagens (no caso de ser enviado por POST), é a seguinte, que, no caso em específico, estamos permitindo somente upload de arquivo PDF até 2MB de tamanho, mas você pode adaptar para suas necessidades.

   E a questão também não é somente enviar a mensagem, mas fazer as verificações necessárias. No código PHP adiante foi utilizada a biblioteca PDFParser (sem Composer) para extrair o conteúdo do arquivo PDF e fazer algumas verificações, porém, você pode usar outra ou adaptar para as suas conveniências.


   O CSS das mensagens está embutido no PHP; o CSS do HTML está embutido no HTML. Fiz umas perfumarias com as mensagens, mas você pode desfazê-las e/ou modificar de acordo com as suas preferências.

   Ao clicar em “Selecione um arquivo” abrirá a janela para escolher o arquivo no sistema e depois de selecionado, o nome do arquivo aparecerá no lugar de “Selecione um arquivo”. Clicando em “Enviar”, o arquivo será enviado e aparecerá a respectiva mensagem.

   Como não há uma maneira de indicar sem JavaScript se algum arquivo foi selecionado, a class=”no-js” na tag <html> é adicionada para que o script adiante (primeira tag <script>) possa saber se o Javascript está disponível no navegador e, caso não estiver, prevalecerá a aparência padrão da entrada do arquivo para fins de usabilidade.



index.html

<!DOCTYPE html>
<html lang="pt-br" class=”no-js”>
    <head>
        <title>Upload de Arquivos</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <!-- remove this if you use Modernizr -->
        <script>
            (function(e,t,n) {
                var r=e.querySelectorAll("html")[0];r.className=r.className.replace(/(^|\s)no-js(\s|$)/,"$1js$2");
            }) (document,window,0);
        </script>
        <script>javascript:window.history.forward(0);</script>
        <script>
                if (window.history.replaceState) {
                    window.history.replaceState(null, null, window.location.href);
            }
        </script>
        <style>
            #tudo{
                margin-top:3%;
                alignment-adjust:middle;
                vertical-align:middle;
                text-align:center;/* "remédio" para o hack do IE */
            } 
            /* Esconde o input */
            input[type='file'] {
                /*display: none;*/
                width: 0;
                height: 0;
                opacity: 0;
            }
            /* Aparência que terá o seletor de arquivo */
            label {
                background-color: #3498db;
                border-radius: 5px;
                color: #fff;
                cursor: pointer;
                margin: 10px;
                padding: 6px 20px;
            }
            #enviar_arquivo{
                background-color:#00ff7f;
                border-color:#00ff7f;
                border-radius:5px;
                cursor: pointer;
            }
        </style>
    </head>

    <body>
        <div id="tudo" class="container">Upload de Arquivos<br>É permitido somente arquivo PDF com, no máximo, 2MB.<br>Arquivo PDF com texto e imagem, será lido somente o texto.<br><br>
            <!-- O tipo de encoding de dados, enctype, DEVE ser especificado abaixo -->
            <form id="form2" name="form2" enctype="multipart/form-data" action="upload.php" method="post">
                <!--O input hidden com MAX_FILE_SIZE deve preceder o campo input file-->
                <input type="hidden" name="MAX_FILE_SIZE" value="2097152"><!-- Setar "upload_max_filesize" no php.ini -->
                <!-- O Nome do elemento input determina o nome da array $_FILES accept="application/pdf" -->
                <!--input type="file" name="arquivo" id="arquivo" accept="application/pdf,.pdf"-->
                <input type="file" name="arquivo" id="arquivo" class="inputfile" accept="application/pdf,.pdf">
                <label for="arquivo">
                    <span>Selecione um arquivo</span>
                </label><br><br>
                <input type="submit" name="enviar_arquivo" id="enviar_arquivo" value="Enviar">
            </form>
        </div>
        <!--Fim div tudo-->
        <script src="./customiza.js"></script>
    </body>

</html>


   O arquivo customiza.js faz a troca dos dizeres “Selecione um arquivo” pelo nome do arquivo selecionado.

customiza.js

// Início
'use strict';
;( function ( document, window, index ) {
        var inputs = document.querySelectorAll( '.inputfile' );
        Array.prototype.forEach.call( inputs, function( input )
    {
        var label = input.nextElementSibling,
        labelVal = label.innerHTML;
        input.addEventListener( 'change', function( e ) {
            var fileName = '';
            if( this.files && this.files.length > 1 )
                fileName = ( this.getAttribute( 'data-multiple-caption' ) || '' ).replace( '{count}', this.files.length );
            else
                fileName = e.target.value.split( '\\' ).pop();
            if( fileName )
                label.querySelector( 'span' ).innerHTML = fileName;
            else
                label.innerHTML = labelVal;
        });
        // Firefox bug fix
        input.addEventListener( 'focus', function(){ input.classList.add( 'has-focus' ); });
        input.addEventListener( 'blur', function(){ input.classList.remove( 'has-focus' ); });
    });
}( document, window, 0 ));
//Fim


   O arquivo upload.php faz o trabalho pesado.

upload.php

<?php
if(!isset($_SESSION) || (session_status() == PHP_SESSION_NONE) || (session_status() !== PHP_SESSION_ACTIVE) || (session_id() === "" )) {
    session_start();
}
$_SESSION = array();
session_unset();
session_destroy();
require_once 'E:/www/Desenvolvimento/projetoMSG/pdfparser-master/pdfparser-master/alt_autoload.php';
$uploaddir = 'E:/www/Desenvolvimento/projetoMSG/upload/';
//require_once '/var/www/html/projetoMSG/pdfparser-master/pdfparser-master/alt_autoload.php';
//$uploaddir = '/home/debina/Desenvolvimento/projetoMSG/upload/';
//Sete os parâmetros 'post_max_size' e 'upload_max_filesize' com o mesmo valor no php.ini.
//Recebe o dado necessário do formulário:
$dados = filter_input(INPUT_SERVER,'CONTENT_LENGTH');
//$enviar = filter_input(INPUT_POST, 'enviar_arquivo', FILTER_UNSAFE_RAW);
//
//Função que converte string em bytes:
function convertToBytes($string) {
    $unit = strtoupper(substr($string, -1));
    $value = substr($string, 0, -1);
    switch($unit) {
        case 'K':
            return $value * 1024;
        case 'M':
            return $value * 1024 * 1024;
        case 'G':
            return $value * 1024 * 1024 * 1024;
        default:
        return $value;
    }
}
// Converte a string 'XM' (X é um número) do php.ini em bytes usando a função convertToBytes:
$uploadmaximo = ini_get('upload_max_filesize');
$bytesup = convertToBytes($uploadmaximo);
//$postmaximo = ini_get('post_max_size');
//$bytespost = convertToBytes($postmaximo);
//Convertendo $dados para array:
$value = (array)$dados;
/*var_dump($_FILES['arquivo']['size']);*/
$arquivos = (!empty($_FILES['arquivo']));
switch($arquivos) {
    case (!empty($arquivos['size']) > (2097152)): //2MB
        echo "Este arquivo excede o tamanho de 2MB!";
    break;
}
//var_dump($uploadmaximo);
//var_dump($postmaximo).'<br>';
//var_dump($bytesup);
//var_dump($value);
//Selecionando o elemento desejado no array:
//$element = (array_values($value));
//Verifica se a variável $value está vazia e envia para a página inicial caso o usuário der um refresh na página:
if (empty($value[0])) {
    header("Location: index.html"); exit();
}
//Verifica se o tamanho do arquivo é superior ao limite do php.ini e envia mensagem:
if ($value[0] > $bytesup) {
    //echo "<p style='color: #f00;'>Este arquivo excede o tamanho de 2MB!</p>";
    include_once 'index.html';
    echo "<style>
        #tudo {
            animation:fadeInAnimation ease 2s;
            animation-iteration-count:1;
            animation-fill-mode:none;
        }
        @keyframes fadeInAnimation {
            0% {
                opacity:0;
            }
            50% {
                opacity:0;
            }
            100% {
                opacity:1;
            }
        }
        .captcentro{
            position:fixed;
            margin:0 auto;
            top:20.5%;
            left:50%;
            transform:translate(-50%, -50%);
            animation:hideAnimation 0s ease-in 4s;
            animation-fill-mode:forwards;
            border:2px solid #fff;
            padding:15px;
            background-color:#000000;
            border-radius:10px;
            font-size:20px;
            text-align:center;
            /*text-decoration:underline white;*/
        }
        @keyframes hideAnimation {
            to {
                visibility:hidden; width:0; height:0;
            }
        }
        @media only screen and (max-width:576px) {
            .captcentro{
                /*width:280px;*/
                position:fixed;
                margin:0 auto;
                top:19.5%;
                left:50%;
                transform:translate(-50%, -50%);
                animation:hideAnimation 0s ease-in 4s;
                animation-fill-mode:forwards;
                border:2px solid #fff;
                padding:10px;
                background-color:#000000;
                border-radius:10px;
                font-size:16px;
                text-align:center;
                /*text-decoration:underline white;*/
            }
            @keyframes hideAnimation {
                to {
                    visibility:hidden; width:0; height:0;
                }
            }
        }
    </style>";
    //header("Refresh: 0");
    echo "<div class='captcentro'><span style='color:red; font-size:20px;'><b>O arquivo excede o tamanho de 2MB!</b></span></div>";
    //header("Refresh: 0; url=pagina2.php");
    exit();
}
$arquivo = $_FILES['arquivo'];
//var_dump($arquivo);
//Verifica se o arquivo é PDF:
if (($arquivo['type'] === '.pdf') or ($arquivo['type'] === 'application/pdf') or ($value[0]) === ($value)) {
    //Captura a exceção da classe Parser do PDFParser e envia mensagem amigável ao usuário:
    try {
        $parser = new \Smalot\PdfParser\Parser(); //var_dump($parser);
        //$pdf = $parser->parseFile($_FILES['arquivo']['tmp_name']);
        $pdf = $parser->parseContent(file_get_contents($_FILES['arquivo']['tmp_name']));
        $text = $pdf->getText();
    }
    catch (Exception $e) {
        //echo "<p style='color: #f00;'>Este arquivo está corrompido, vazio ou protegido!<br>Tente outro arquivo.</p>";
        // $e->getMessage(), "\n";
        include_once 'index.html';
        echo "<style>
            #tudo {
                animation:fadeInAnimation ease 2s;
                animation-iteration-count:1;
                animation-fill-mode:none;
            }
            @keyframes fadeInAnimation {
                0% {
                    opacity:0;
                }
                50% {
                    opacity:0;
                }
                100% {
                    opacity:1;
                }
            }
            .captcentro{
                position:fixed;
                margin:0 auto;
                top:20.5%; left:50%;
                transform:translate(-50%, -50%);
                animation:hideAnimation 0s ease-in 4s;
                animation-fill-mode: forwards;
                border:4px solid #ffffff;
                padding:15px;
                background-color:#ffff00;
                border-radius:10px;
                font-size:20px;
                text-align:center;
                /*text-decoration:underline white;*/
            }
            @keyframes hideAnimation {
                to {
                    visibility: hidden; width:0; height:0;
                }
            }
            @media only screen and (max-width:576px) {
                .captcentro{
                    /*width:280px;*/
                    position:fixed;
                    margin:0 auto;
                    top:19.5%;
                    left:50%;
                    transform:translate(-50%, -50%);
                    animation:hideAnimation 0s ease-in 4s;
                    animation-fill-mode:forwards;
                    border:4px solid #ffffff;
                    padding:10px;
                    background-color:#ffff00;
                    border-radius:10px;
                    font-size:16px;
                    text-align:center;
                    /*text-decoration:underline white;*/
                }
                @keyframes hideAnimation {
                    to {
                        visibility:hidden;
                        width:0;
                        height:0;
                    }
                }
            }
        </style>";
        echo "<div class='captcentro'><span style='color:red;'><b>O arquivo está corrompido, vazio ou protegido!</b></span></div>";
        exit();
    }
    //Verifica se o arquivo foi enviado por POST:
    if (is_uploaded_file($_FILES['arquivo']['tmp_name'])) {
        if (!is_dir($uploaddir)) {
            mkdir($uploaddir);
        }
        $uploadfile = $uploaddir . ($_FILES['arquivo']['name']);
        $parser = new \Smalot\PdfParser\Parser();
        //var_dump($parser);
        //$pdf = $parser->parseFile($_FILES['arquivo']['tmp_name']);
        $pdf = $parser->parseContent(file_get_contents($_FILES['arquivo']['tmp_name']));
        $text = $pdf->getText();
        //echo $text;
        //Move o arquivo temporário para a pasta de destino:
        move_uploaded_file($_FILES['arquivo']['tmp_name'], $uploadfile);
        //echo "<p style='color: #f00;'>O arquivo ". $_FILES['arquivo']['name'] ." foi enviado com sucesso!</p>\n<br><br>";
        require_once 'index.html';
        echo "<style>
            #tudo {
                animation:fadeInAnimation ease 2s;
                animation-iteration-count:1;
                animation-fill-mode:none;
            }
            @keyframes fadeInAnimation {
                0% {
                    opacity:0;
                }
                50% {
                    opacity:0;
                }
                100% {
                    opacity:1;
                }
            }
            .captcentro{
                position:fixed;
                margin:0 auto;
                top:20.5%;
                left:50%;
                transform:translate(-50%, -50%);
                animation:hideAnimation 0s ease-in 4s;
                animation-fill-mode:forwards;
                border:2px solid #ffffff;
                padding:15px;
                background-color:#ffd700;
                border-radius:10px;
                font-size:20px;
                text-align:center;
                /*text-decoration:underline white;*/
            }
            @keyframes hideAnimation {
                to {
                    visibility:hidden;
                    width:0;
                    height:0;
                }
            }
            @media only screen and (max-width:576px) {
                .captcentro{
                    /*width:280px;*/
                    position:fixed;
                    margin:0 auto;
                    top:19.5%;
                    left:50%;
                    transform:translate(-50%, -50%);
                    animation:hideAnimation 0s ease-in 4s;
                    animation-fill-mode:forwards;
                    border:2px solid #ffffff;
                    padding:10px;
                    background-color:#ffd700;
                    border-radius:10px;
                    font-size:16px;
                    text-align:center;
                    /*text-decoration:underline white;*/
                }
                @keyframes hideAnimation {
                    to {
                        visibility:hidden;
                        width:0;
                        height:0;
                    }
                }
            }
        </style>";
        echo "<div class='captcentro'><span style='color:red; font-size:20px;'><b>O arquivo ". $_FILES['arquivo']['name'] ." foi enviado com sucesso!</b></span></div>";
        exit();
    }
    exit();
}
//Verifica se o tamanho do arquivo é menor ou igual ao limite do php.ini e exibe mensagem:
if (($arquivo['size'] !== 0) or ($value[0]) === ($arquivo['size'])) {
    if (($arquivo['type'] !== '.pdf') or ($arquivo['type'] !== 'application/pdf')) {
        //echo "<p style='color: #f00;'>Este arquivo não é PDF!</p>"; include_once 'index.html’;
        echo "<style>
            #tudo {
                animation:fadeInAnimation ease 2s;
                animation-iteration-count:1;
                animation-fill-mode:none;
            }
            @keyframes fadeInAnimation {
                0% {
                    opacity:0;
                }
                50% {
                    opacity:0;
                }
                100% {
                    opacity:1;
                }
            }
            .captcentro{
                position:fixed;
                margin:0 auto;
                top:20.5%;
                left:50%;
                transform:translate(-50%, -50%);
                animation:hideAnimation 0s ease-in 4s;
                animation-fill-mode:forwards;
                border:2px solid #fff;
                padding:15px;
                background-color:#000000;
                border-radius:10px;
                font-size:20px;
                text-align:center;
                /*text-decoration:underline white;*/
            }
            @keyframes hideAnimation {
                to {
                    visibility:hidden; width:0; height:0;
                }
            }
            @media only screen and (max-width:576px) {
                .captcentro{
                    /*width:280px;*/
                    position:fixed;
                    margin:0 auto;
                    top:19.5%;
                    left:50%;
                    transform:translate(-50%, -50%);
                    animation:hideAnimation 0s ease-in 4s;
                    animation-fill-mode:forwards;
                    border:2px solid #fff;
                    padding:10px;
                    background-color:#000000;
                    border-radius:10px;
                    font-size:16px;
                    text-align:center;
                    /*text-decoration:underline white;*/
                }
                @keyframes hideAnimation {
                    to {
                        visibility:hidden;
                        width:0;
                        height:0;
                    }
                }
            }
        </style>";
        echo "<div class='captcentro'><span style='color:red;'><b>O arquivo não é PDF!</b></span></div>";
        exit();
    }
}
//Condição que chama o 'index.html' caso o usuário clicar no botão enviar sem selecionar arquivo:
if (($value[0]) !== ($arquivo['size'])) {
    header("Location: index.html");
    exit();
}


CONCLUSÃO

   Você pode (e deve) melhorar os arquivos e adaptá-los para as suas necessidades.
Em pesquisa na internet notei uma falta de artigos, tutoriais, etc, neste sentido de configurar mensagens em PHP após o envio de arquivos.
      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á.

   Enfim, deixo como mais uma sugestão de programação neste sentido.


quarta-feira, 4 de setembro de 2024

O Banquete


   Saboreando "O Banquete" de Arístocles, vulgo Platão (plato - ombros largos), chamou-me exótica atenção o relato de Aristófanes sobre os três gêneros da natureza de antanho da humanidade. Resolvi, então, compor excêntrico texto com toda humildade.

   Lembrando que "Humildade", do grego HUMUS, significa "terra", coisa que a broderagem grega não tinha em abundância devido a dificuldade de se achar algum herói humilde na mitologia Grega. Temos Aedos, mas esta daemon era mais propriamente a personificação da vergonha e do pudor do que da humildade em si... então não vale.

   Ante à provocação do texto, tentarei, tal qual Ulisses na Odisséia, tentarei escapar a nado - com vigorosas braçadas - do violento mar das críticas evitando o ímpeto de ser mais satírico ainda do que Aristófanes.

   Vamos aos excertos:

"Na verdade, Erixímaco, disse Aristófanes, é de outro modo que tenho a intenção de falar, diferente do teu e do de Pausânias. Com efeito, parece-me os homens absolutamente não terem percebido o poder do amor, que se o percebessem, os maiores templos e altares lhe preparariam, e os maiores sacrifícios lhe fariam, não como agora que nada disso há em sua honra, quando mais que tudo deve haver.
   É ele com efeito o deus mais amigo do homem, protetor e médico desses males, de cuja cura dependeria sem dúvida a maior felicidade para o gênero humano. Tentarei eu portanto iniciar-vos em seu poder, e vós o ensinareis aos outros. Mas é preciso primeiro aprenderdes a natureza humana e as suas vicissitudes. Com efeito, nossa natureza outrora não era a mesma que a de agora, mas diferente.
Em primeiro lugar, três eram os gêneros da humanidade, não dois como agora, o masculino e o feminino, mas também havia a mais um terceiro, comum a estes dois, do qual resta agora um nome, desaparecida a coisa; andrógino era então um gênero distinto, tanto na forma como no nome comum aos dois, ao masculino e ao feminino, enquanto agora nada mais é que um nome posto em desonra.
   Depois, inteiriça era a forma de cada homem, com o dorso redondo, os flancos em círculo; quatro mãos ele tinha, e as pernas o mesmo tanto das mãos, dois rostos sobre um pescoço torneado, semelhantes em tudo; mas a cabeça sobre os dois rostos opostos um ao outro era uma só, e quatro orelhas, dois sexos, e tudo o mais como desses exemplos se poderia supor.
   E quanto ao seu andar, era também ereto como agora, em qualquer das duas direções que quisesse; mas quando se lançavam a uma rápida corrida, como os que cambalhotando e virando as pernas para cima fazem uma roda, do mesmo modo, apoiando-se nos seus oito membros de então, rapidamente eles se locomoviam em círculo.
   Eis por que eram três os gêneros, e tal a sua constituição, porque o masculino de início era descendente do sol, o feminino da terra, e o que tinha de ambos era da lua, pois também a lua tem de ambos; e eram assim circulares, tanto eles próprios como a sua locomoção, por terem semelhantes genitores. ..."

   O excerto é auto-explicativo e não demanda muitos comentários.
   Aristófanes, como todo bom dramaturgo intensamente satírico - sarcástico até -, descreve anedoticamente a origem de sermos assim como somos fisicamente: cabeça, tronco e membros; porém, tínhamos quatro braços, quatro pernas, uma cabeça, dois rostos, quatro orelhas e dois sexos. Provavelmente transávamos com nós mesmos. Veja só, já tínhamos há 2.500 anos a habilidade de futére com nós mesmos. Tínhamos três gêneros: masculino, feminino e andrógino... e também já tínhamos a tal diversidade que alguns usam como desculpa para enlaçar-se com criancinhas.
   Pelo que se entende tinha-se três tipos de pessoas, sendo que cada gênero habitava num corpo próprio e quando precisávamos correr das vicissitudes da vida dávamos uma cambalhota ficando com os oito membros no chão e nos locomovíamos como caranguejos com rostos... sigamos.

"Eram por conseguinte de uma força e de um vigor terríveis, e uma grande presunção eles tinham; mas voltaram-se contra os deuses, e o que diz Homero de Efialtes e de Otes é a eles que se refere, a tentativa de fazer uma escalada ao céu, para investir contra os deuses. Zeus então e os demais deuses puseram-se a deliberar sobre o que se devia fazer com eles, e embaraçavam-se; não podiam nem matá-los e, após fulminá-los como aos gigantes, fazer desaparecer-lhes a raça - pois as honras e os templos que lhes vinham dos homens desapareceriam nem permitir-lhes que continuassem na impiedade.
   Depois de laboriosa reflexão, diz Zeus: "Acho que tenho um meio de fazer com que os homens possam existir, mas parem com a intemperança, tornados mais fracos. Agora com efeito, continuou, eu os cortarei a cada um em dois, e ao mesmo tempo eles serão mais fracos e também mais úteis para nós, pelo fato de se terem tomado mais numerosos; e andarão eretos, sobre duas pernas. Se ainda pensarem em arrogância e não quiserem acomodar-se, de novo, disse ele, eu os cortarei em dois, e assim sobre uma só perna eles andarão, saltitando." Logo que o disse pôs-se a cortar os homens em dois, como os que cortam as sorvas para a conserva, ou como os que cortam ovos com cabelo; a cada um que cortava mandava Apolo voltar-lhe o rosto e a banda do pescoço para o lado do corte, a fim de que, contemplando a própria mutilação, fosse mais moderado o homem, e quanto ao mais ele também mandava curar.
   Apolo torcia-lhes o rosto, e repuxando a pele de todos os lados para o que agora se chama o ventre, como as bolsas que se entrouxam, ele fazia uma só abertura e ligava-a firmemente no meio do ventre, que é o que chamam umbigo. As outras pregas, numerosas, ele se pôs a polir, e a articular os peitos, com um instrumento semelhante ao dos sapateiros quando estão polindo na forma as pregas dos sapatos; umas poucas ele deixou, as que estão à volta do próprio ventre e do umbigo, para lembrança da antiga condição. Por conseguinte, desde que a nossa natureza se mutilou em duas, ansiava cada um por sua própria metade e a ela se unia, e envolvendo-se com as mãos e enlaçando-se um ao outro, no ardor de se confundirem, morriam de fome e de inércia em geral, por nada quererem fazer longe um do outro. E sempre que morria uma das metades e a outra ficava, a que ficava procurava outra e com ela se enlaçava, quer se encontrasse com a metade do todo que era mulher - o que agora chamamos mulher quer com a de um homem; e assim iam se destruindo. ..."

   Nós tínhamos uma força e um vigor terríveis, mas éramos (e ainda somos) presunçosos e tentamos escalar ao céu.
   Zeus não gostou nada disso e, como castigo, partiu-nos ao meio... Zeus deu no meio da humanidade!
   Daí vem o porquê de procurarmos a cara metade e morrermos abraçados no casamento: é um castigo de Zeus!
   Lembrando que, na Bíblia, Deus castiga a humanidade com o trabalho, mas isso é outra estória.
   Zeus não quis perder a idolatria dos seres humanos... e está tendo pleno êxito nisso até os dias atuais: a idolatria segue firme, forte e rija.
   Nós, seres humanos, já não estávamos satisfeitos no episódio da Torre de Babel na Bíblia quando tentamos trepar aos céus pela primeira vez e fomos castigados com o embaralhamento da língua que gerou a confusão suprema de não nos entendermos mais... se é que já nos entendíamos.
   Acredito que procurando na história encontraremos mais passagens em outras mitologias onde o ser humano tenta, em vão, subir aos céus para massacrar deuses. De certa maneira, até hoje fazemos isso.
   Interessante é o trecho onde Aristófanes descreve como Apolo poliu algumas pregas do ser humano e outras Apolo teve a gentileza de deixar rugosas para lembrar-nos da antiga condição.  Lembramo-nos disso todos os dias quando vamos aos pés!
   Vamos adiante.

"Tomado de compaixão, Zeus consegue outro expediente, e lhes muda o sexo para a frente - pois até então eles o tinham para fora, e geravam e reproduziam não um no outro, mas na terra, como as cigarras; pondo assim o sexo na frente deles fez com que através dele se processasse a geração um no outro, o macho na fêmea, pelo seguinte, para que no enlace, se fosse um homem a encontrar uma mulher, que ao mesmo tempo gerassem e se fosse constituindo a raça, mas se fosse um homem com um homem, que pelo menos houvesse saciedade em seu convívio e pudessem repousar, voltar ao trabalho e ocupar-se do resto da vida.
   E então de há tanto tempo que o amor de um pelo outro está implantado nos homens, restaurador da nossa antiga natureza, em sua tentativa de fazer um só de dois e de curar a natureza humana. Cada um de nós portanto é uma téssera complementar de um homem, porque cortado como os linguados, de um só em dois; e procura então cada um o seu próprio complemento. Por conseguinte, todos os homens que são um corte do tipo comum, o que então se chamava andrógino, gostam de mulheres, e a maioria dos adultérios provém deste tipo, assim como também todas as mulheres que gostam de homens e são adúlteras, é deste tipo que provêm.
   Todas as mulheres que são o corte de uma mulher não dirige muito sua atenção aos homens, mas antes estão voltadas para as mulheres e as amiguinhas provêm deste tipo. E todos os que são corte de um macho perseguem o macho, e enquanto são crianças, como cortículos do macho, gostam dos homens e se comprazem em deitar-se com os homens e a eles se enlaçar, e são estes os melhores meninos e adolescentes, os de natural mais corajoso. Dizem alguns, é verdade, que eles são despudorados, mas estão mentindo; pois não é por despudor que fazem isso, mas por audácia, coragem e masculinidade, porque acolhem o que lhes é semelhante. Uma prova disso é que, uma vez amadurecidos, são os únicos que chegam a ser homens para a política, os que são desse tipo. E quando se tornam homens, são os jovens que eles amam, e a casamentos e procriação naturalmente eles não lhes dão atenção, embora por lei a isso sejam forçados, mas se contentam em passar a vida um com o outro, solteiros.
   Assim é que, em geral, tal tipo torna-se amante e amigo do amante, porque está sempre acolhendo o que lhe é aparentado. Quando então se encontra com aquele mesmo que é a sua própria metade, tanto o amante do jovem como qualquer outro, então extraordinárias são as emoções que sentem, de amizade, intimidade e amor, a ponto de não quererem por assim dizer separar-se um do outro nem por um pequeno momento. E os que continuam um com o outro pela vida afora são estes, os quais nem saberiam dizer o que querem que lhes venha da parte de um ao outro.
   A ninguém com efeito pareceria que se trata de união sexual, e que é porventura em vista disso que um gosta da companhia do outro assim com tanto interesse; ao contrário, que uma coisa quer a alma de cada um, é evidente, a qual coisa ela não pode dizer, mas adivinha o que quer e o indica por enigmas. Se diante deles, deitados no mesmo leito, surgisse Hefesto e com seus instrumentos lhes perguntasse: Que é que quereis, ó homens, ter um do outro?, e se, diante do seu embaraço, de novo lhes perguntasse: Porventura é isso que desejais, ficardes no mesmo lugar o mais possível um para o outro, de modo que nem de noite nem de dia vos separeis um do outro? Pois se é isso que desejais, quero fundir-vos e forjar-vos numa mesma pessoa, de modo que de dois vos tomeis um só e, enquanto viverdes, como uma só pessoa, possais viver ambos em comum, e depois que morrerdes, lá no Hades, em vez de dois ser um só, mortos os dois numa morte comum; mas vede se é isso o vosso amor, e se vos contentais se conseguirdes isso.
   Depois de ouvir essas palavras, sabemos que nem um só diria que não, ou demonstraria querer outra coisa, mas simplesmente pensaria ter ouvido o que há muito estava desejando, sim, unir-se e confundir-se com o amado e de dois ficarem um só. 0 motivo disso é que nossa antiga natureza era assim e nós éramos um todo; é portanto ao desejo e procura do todo que se dá o nome de amor."

   Zeus, tendo piedade de nós, compadeceu-se de nos ter cortado ao meio e ter nos obrigado a reproduzir-nos na terra tal como as cigarras - talvez fez isso para nos ensinar humildade (humus, terra) -, mas arrependeu-se e colocou-nos os órgãos genitais na frente, como é até hoje, para reproduzirmos macho na fêmea... ainda bem!
   Devia ser ruim copular a terra.
   Cada homem é uma téssera da mulher e vice-versa, são complementares, não são sexos opostos como sonha nossa vã filosofia moderna.
   Aristófanes segue dizendo que os homens e as mulheres que estão na procura da sua cara metade são um corte de tipo filé-mignon de linguado extraído do gênero andrógino. Os adúlteros e adúlteras também vem do gênero andrógino, mas são um corte de tipo comum da espada de Zeus, o açougueiro. As lésbicas são o corte de uma mulher (gênero feminino) e os que são corte de um macho (gênero masculino) são os homossexuais masculinos procurando sua cara metade.
   A partir do trecho

"...e enquanto são crianças, como cortículos do macho, gostam dos homens e se comprazem em deitar-se com os homens e a eles se enlaçar, e são estes os melhores meninos e adolescentes,..."

vemos que a coisa descamba para uma junção de Paidí (criança) com Philia (amizade íntima) onde Aristófanes arremata sugerindo que todo político é gay e pedófilo com um casamento de fachada porque a "nobreza obriga":

"Uma prova disso é que, uma vez amadurecidos [os cortículos do macho], são os únicos que chegam a ser homens para a política, os que são desse tipo. E quando se tornam homens, são os jovens que eles amam, e a casamentos e procriação naturalmente eles não lhes dão atenção, embora por lei a isso sejam forçados, mas se contentam em passar a vida um com o outro, solteiros."

   Depois, em outra ocasião, o espevitado Aristófanes, na sua peça "As Nuvens", prega uma peça em Sócrates ajudando a ferrar a vida dele acusando-o de corromper a sociedade, não a dos Poetas Mortos, mas a dos Bróderes Vivos.
   Deixando Aristófanes de lado, O Banquete todo é de uma broderagem descarada, principalmente a parte onde a ciumenta invejosa Alcibíades chega desabridamente embriagado e tem um ataque de pelanca quando vê Sócrates refocilar-se no colo do licencioso Agatão:

"E Sócrates: - Agatão, vê se me defendes! Que o amor deste homem se me tornou um não pequeno problema. Desde aquele tempo, com efeito, em que o amei, não mais me é permitido dirigir nem o olhar nem a palavra a nenhum belo jovem, senão este homem, enciumado e invejoso, faz coisas extraordinárias, insulta-me e mal retém suas mãos da violência. Vê então se também agora não vai ele fazer alguma coisa, e reconcilia-nos; ou se ele tentar a violência, defende-me, pois eu da sua fúria e da sua paixão amorosa muito me receio.
- Não! - disse Alcibíades - entre mim e ti não há reconciliação. Mas pelo que disseste depois eu te castigarei;"

   Qual "castigo" Alcibíades deu em Sócrates não sabemos se ficou somente nas palavras ou se Alcibíades partiu para a ação punitiva na prática "castigando" Sócrates..
   O que sabemos é que os Gregos distinguiam o amor em sete tipos diferentes: o Eros (amor erótico) , a Philia (amizade íntima), o Ludus (amor lúdico ou sedutor), o Storge (amor familiar), a Philautia (amor próprio), o Pragma (amor companheiro) e o Ágape (amor universal).
   Os integrantes da vida noturna de O Banquete, envoltos em túnicas, chitons e sacos de batata coloridos - mas sem nada por baixo -, depois do banquete mandavam as serviçais mulheres embora e caíam apetitosamente no Simpósio alimentando-se quase que exclusivamente do Eros.

   Para quem quiser uma abordagem mais austera e completa: