HTTP nativo: superglobais e o ciclo de requisição

1. O Ciclo de Vida de uma Requisição HTTP no PHP

1.1. Do servidor web ao interpretador PHP

Quando um cliente faz uma requisição HTTP, o servidor web (Apache, Nginx, etc.) recebe a solicitação e, baseado na configuração, encaminha o processamento ao interpretador PHP. O servidor analisa a URL, determina qual arquivo PHP deve ser executado e passa informações cruciais como headers, método HTTP e parâmetros.

1.2. Inicialização do script e o fim da execução

O PHP inicia a execução do script a partir do arquivo solicitado. Durante esse processo, popula automaticamente as superglobais com os dados da requisição. Ao final, o script gera uma saída (HTML, JSON, etc.) que é enviada de volta ao servidor web, que a transmite ao cliente.

<?php
// Exemplo simples do ciclo requisição-resposta
echo "Requisição recebida em: " . date('Y-m-d H:i:s');
?>

1.3. Headers, status code e a saída para o cliente

Antes de qualquer saída, o PHP permite modificar headers HTTP e códigos de status. Toda saída gerada (echo, print, HTML fora das tags PHP) compõe o corpo da resposta.

<?php
header('Content-Type: text/html; charset=utf-8');
http_response_code(200);
echo '<h1>Resposta enviada com sucesso!</h1>';
?>

2. Superglobais de Entrada: Capturando Dados do Cliente

2.1. $_GET: parâmetros da URL

A superglobal $_GET contém parâmetros enviados via query string na URL. É usada principalmente em requisições GET.

<?php
// URL: http://exemplo.com/?nome=Joao&idade=30
$nome = $_GET['nome'] ?? 'visitante';
$idade = $_GET['idade'] ?? 'desconhecida';
echo "Olá $nome, você tem $idade anos.";
?>

2.2. $_POST: dados de formulários

Para formulários com method="POST", os dados são acessíveis via $_POST.

<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $email = $_POST['email'] ?? '';
    $senha = $_POST['senha'] ?? '';
    // Processar login...
}
?>

2.3. $_REQUEST: unificação e cuidados com segurança

$_REQUEST combina $_GET, $_POST e $_COOKIE. Seu uso é desencorajado por questões de segurança, pois não permite distinguir a origem dos dados.

<?php
// Evite: não sabemos se o dado veio de GET ou POST
$valor = $_REQUEST['campo']; // Inseguro

// Prefira: explicitar a origem
$valor = $_POST['campo'] ?? $_GET['campo'] ?? '';
?>

3. Superglobais de Ambiente e Servidor

3.1. $_SERVER: cabeçalhos HTTP, método, URI e IP

$_SERVER é rica em informações sobre o servidor e a requisição atual.

<?php
$metodo = $_SERVER['REQUEST_METHOD'];
$uri = $_SERVER['REQUEST_URI'];
$ip = $_SERVER['REMOTE_ADDR'] ?? '127.0.0.1';
$userAgent = $_SERVER['HTTP_USER_AGENT'] ?? 'Desconhecido';

echo "Método: $metodo<br>";
echo "URI: $uri<br>";
echo "IP: $ip<br>";
echo "User-Agent: $userAgent<br>";
?>

3.2. $_ENV: variáveis de ambiente

Útil para configurações externas como credenciais de banco de dados.

<?php
$db_host = $_ENV['DB_HOST'] ?? 'localhost';
$db_user = $_ENV['DB_USER'] ?? 'root';
?>

3.3. Casos práticos: detectando HTTPS

<?php
$isHttps = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
    || $_SERVER['SERVER_PORT'] == 443;

if (!$isHttps) {
    header('Location: https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
    exit;
}
?>

4. Cookies e Sessões com Superglobais

Cookies são armazenados no navegador do cliente e enviados em cada requisição.

<?php
// Definir cookie
setcookie('preferencia_tema', 'escuro', time() + 86400 * 30, '/');

// Ler cookie
$tema = $_COOKIE['preferencia_tema'] ?? 'claro';
echo "Tema selecionado: $tema";
?>

4.2. $_SESSION: gerenciamento de estado

Sessões armazenam dados no servidor, associados a um ID único.

<?php
session_start();
$_SESSION['usuario_id'] = 123;
$_SESSION['ultimo_acesso'] = time();

// Em outra página
session_start();
if (isset($_SESSION['usuario_id'])) {
    echo "Usuário logado: " . $_SESSION['usuario_id'];
}
?>

4.3. Diferenças e boas práticas

Cookies são adequados para preferências não sensíveis; sessões para dados críticos como autenticação.

5. Upload de Arquivos com $_FILES

5.1. Estrutura do array $_FILES

<?php
// Formulário: <input type="file" name="arquivo">
$arquivo = $_FILES['arquivo'];
echo "Nome original: " . $arquivo['name'];
echo "Tipo: " . $arquivo['type'];
echo "Tamanho: " . $arquivo['size'] . " bytes";
echo "Erro: " . $arquivo['error'];
echo "Temp: " . $arquivo['tmp_name'];
?>

5.2. Validação de upload

<?php
$tiposPermitidos = ['image/jpeg', 'image/png', 'application/pdf'];
$tamanhoMaximo = 5 * 1024 * 1024; // 5MB

if ($_FILES['arquivo']['error'] === UPLOAD_ERR_OK) {
    $tipo = mime_content_type($_FILES['arquivo']['tmp_name']);
    $tamanho = $_FILES['arquivo']['size'];

    if (!in_array($tipo, $tiposPermitidos)) {
        die("Tipo de arquivo não permitido.");
    }

    if ($tamanho > $tamanhoMaximo) {
        die("Arquivo muito grande.");
    }
}
?>

5.3. Movendo arquivos temporários

<?php
$destino = __DIR__ . '/uploads/' . basename($_FILES['arquivo']['name']);
if (move_uploaded_file($_FILES['arquivo']['tmp_name'], $destino)) {
    echo "Upload realizado com sucesso!";
} else {
    echo "Erro ao salvar o arquivo.";
}
?>

6. Manipulação do Corpo da Requisição (Raw Input)

6.1. php://input para requisições PUT, PATCH e DELETE

<?php
$dadosRaw = file_get_contents('php://input');
// Útil quando o Content-Type não é application/x-www-form-urlencoded
?>

6.2. Parse de JSON e XML

<?php
$json = file_get_contents('php://input');
$dados = json_decode($json, true);

if (json_last_error() === JSON_ERROR_NONE) {
    echo "Nome: " . ($dados['nome'] ?? '');
} else {
    http_response_code(400);
    echo "JSON inválido.";
}
?>

6.3. Diferença entre $_POST e php://input

$_POST só é populado para application/x-www-form-urlencoded ou multipart/form-data. Para JSON, XML ou outros formatos, use php://input.

7. Enviando Respostas HTTP no PHP Puro

7.1. Função header()

<?php
// Redirecionamento
header('Location: /login.php');
exit;

// Definir status code
header('HTTP/1.1 404 Not Found');

// Content-Type customizado
header('Content-Type: application/json');
?>

7.2. Construindo resposta JSON

<?php
header('Content-Type: application/json');
$resposta = [
    'status' => 'sucesso',
    'dados' => ['id' => 1, 'nome' => 'João']
];
echo json_encode($resposta);
?>

7.3. Tratamento de erros

<?php
http_response_code(500);
echo "<h1>Erro interno do servidor</h1>";
echo "<p>Desculpe, algo deu errado. Tente novamente mais tarde.</p>";
?>

8. Boas Práticas e Segurança no Tratamento de Entradas

8.1. Validação vs sanitização

<?php
// Validação
$email = filter_var($_POST['email'], FILTER_VALIDATE_EMAIL);
if ($email === false) {
    die("Email inválido.");
}

// Sanitização para saída
$nome = htmlspecialchars($_POST['nome'] ?? '', ENT_QUOTES, 'UTF-8');
echo "Olá, $nome";
?>

8.2. Proteção contra injeção

<?php
// Nunca confie em dados externos
$id = (int) $_GET['id']; // Forçar tipo inteiro
$nome = filter_input(INPUT_POST, 'nome', FILTER_SANITIZE_STRING);
?>

8.3. Organização do código

<?php
// router.php
$rota = $_SERVER['REQUEST_URI'];
$metodo = $_SERVER['REQUEST_METHOD'];

switch ($rota) {
    case '/login':
        if ($metodo === 'POST') {
            $dados = $_POST;
            // Processar login...
        }
        break;
    case '/api/usuarios':
        header('Content-Type: application/json');
        $dados = json_decode(file_get_contents('php://input'), true);
        break;
}
?>

Referências