Apuntes php

PHP: Porque a veces necesitas un poco de caos en tu vida.

Variables Externas y Superglobales en PHP

En un programa las variables pueden venir de tu propio código o del exterior, a través de formularios o URLs. Aqui aprenderemos de dónde vienen las variables, cómo manejarlas con superglobales ($_GET, $_POST, etc.), y por qué la antigua configuración register_globals era un riesgo.

¿De dónde vienen las variables?

Las variables en PHP tienen dos orígenes: -

  • Internas: Definidas por el programador, como $contador = 0;.
  • Externas, proporcionadas por usuarios o el entorno, a través de:
    • GET: Cadenas en la URL (por ejemplo, ?nombre=Juan).
    • POST: Datos de formularios HTML.
    • Cookies: Datos almacenados en el navegador.
    • Archivos: Subidas vía formularios ($_FILES).
    • Servidor: Variables de entorno o HTTP ($_SERVER).
    • Sesiones: Datos persistentes entre páginas ($_SESSION).

Las variables externas son útiles, pero pueden ser manipuladas por usuarios, lo que puede ser un riesgo de seguridad si no se manejan correctamente. Un usuario podría intentar “inyectar” valores no deseados, comprometiendo la seguridad.

Ejemplo de riesgo (histórico):

<?php
function authenticateUser(): bool {
    // Simula validación de usuario
    return false; // Usuario no válido
}

if (authenticateUser()) {
    $userOk = true; // Solo debería ser true si el usuario es válido
}

if ($userOk) {
    echo "Acceso permitido\n";
} else {
    echo "Acceso denegado\n";
}
?>

Con la antigua configuración register_globals on, un atacante podía añadir ?userOk=1 a la URL, forzando $userOk = true y obteniendo acceso no autorizado.

La directiva register_globals (obsoleta)

En versiones antiguas de PHP (hasta 5.3), la directiva register_globals en php.ini controlaba si las variables externas (GET, POST, Cookies, etc.) se convertían automáticamente en variables globales. Con register_globals on un valor como ?userOk=1 creaba $userOk = 1 globalmente. Esto mezclaba variables internas y externas, facilitando ataques.

Desde PHP 4.2.0 (2002), se recomendó register_globals off, y en PHP 5.4 (2012) fue eliminado. En PHP 8.3, todas las variables externas se acceden a través de superglobales, como $_GET['userOk'], lo que es más seguro porque:

  • Separa variables internas de externas.
  • Obliga a especificar el origen (GET, POST, etc.).
  • Evita inyecciones accidentales.
  • Mejora la claridad del código.

Configuración: - No puedes cambiar register_globals en PHP 8.3 (ya no existe). - En servidores antiguos, podías usar .htaccess (si AllowOverride lo permitía): apache php_flag register_globals off O en configuraciones VirtualHost (con permisos administrativos): apache <VirtualHost 127.0.0.1> ServerName localhost DocumentRoot /var/www/html/misitio php_value register_globals 0 </VirtualHost>

Ejemplo:

<?php
// URL: http://www.sitio.com/index.php?mail=usuario@ejemplo.com
$mail = $_GET['mail'] ?? ''; // Seguro, accedes explícitamente
echo "Email: $mail\n"; // Imprime: Email: usuario@ejemplo.com

// Con register_globals on, $mail existiría directamente
// pero podría ser manipulada sin control
?>

Superglobales

En PHP 8.3, las variables externas se acceden a través de arrays superglobales:

  1. $_GET: Datos de la URL (por ejemplo, $_GET['nombre']).
  2. $_POST: Datos de formularios POST (por ejemplo, $_POST['mail']).
  3. $_COOKIE: Datos de cookies (por ejemplo, $_COOKIE['sesion']).
  4. $_FILES: Archivos subidos (por ejemplo, $_FILES['foto']).
  5. $_SESSION: Datos de sesiones (por ejemplo, $_SESSION['usuario']).
  6. $_SERVER: Información del servidor (por ejemplo, $_SERVER['PHP_SELF']).
  7. $_ENV: Variables de entorno.
  8. $_REQUEST: Combina GET, POST, y Cookies (evítalo, es menos seguro).
  9. $_GLOBALS: Todas las variables globales (incluye internas y externas definidas).

Ejemplo:

<?php
// URL: http://www.sitio.com/index.php?op=login
echo $_GET['op'] ?? 'No definido'; // Imprime: login

// Formulario: <input name="mail">
echo $_POST['mail'] ?? 'No enviado'; // Imprime: valor del formulario

// Servidor
echo $_SERVER['PHP_SELF']; // Imprime: /index.php
?>

Advertencia: Evita $_REQUEST, ya que mezcla orígenes (GET, POST, Cookies), lo que puede causar confusión o vulnerabilidades.

Procesamiento seguro de variables externas

Siempre valida y sanitiza datos externos usando funciones modernas como filter_input() y htmlspecialchars():

<?php
declare(strict_types=1);

const CAMPO_MAIL = 'mail'; // Constante para nombre del campo

// Sanitiza y valida un email de POST
$mail = filter_input(INPUT_POST, CAMPO_MAIL, FILTER_SANITIZE_EMAIL) ?? '';
$mail = (string)$mail; // Forzar tipo string

if ($mail === '' || !filter_var($mail, FILTER_VALIDATE_EMAIL)) {
    echo "Email inválido\n";
} else {
    echo "Email válido: " . htmlspecialchars($mail) . "\n";
}
?>

Notas: - Usa constantes para nombres de campos, mejorando la mantenibilidad. - filter_input() sanitiza datos según el tipo (por ejemplo, FILTER_SANITIZE_EMAIL). - (string) asegura que el dato sea tratado como cadena. - htmlspecialchars() protege contra ataques XSS.

Ejemplo completo

index.php:

<!DOCTYPE html>
<html>
<head>
    <title>Procesar Formulario</title>
</head>
<body>
    <h1>Enviar Datos</h1>
    <form action="index.php" method="post">
        <label>Email: <input type="email" name="mail" /></label><br>
        <input type="submit" value="Enviar" />
    </form>

    <?php
    declare(strict_types=1);

    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        $mail = filter_input(INPUT_POST, 'mail', FILTER_SANITIZE_EMAIL) ?? '';
        $mail = (string)$mail;

        if ($mail === '' || !filter_var($mail, FILTER_VALIDATE_EMAIL)) {
            echo "<p style='color: red;'>Por favor, introduce un email válido</p>";
        } else {
            echo "<p>Email recibido: " . htmlspecialchars($mail) . "</p>";
        }
    }
    ?>
</body>
</html>

Explicación: - Procesa un formulario POST de forma segura. - Valida y sanitiza el email. - Muestra el resultado con htmlspecialchars().

Consejos para seguridad

  1. Inicializa variables internas: Define $userOk = false; al inicio para evitar manipulaciones.
  2. Usa superglobales específicas: Prefiere $_POST o $_GET sobre $_REQUEST.
  3. Valida y sanitiza: Usa filter_input(), filter_var(), y htmlspecialchars().
  4. Verifica orígenes: Asegúrate de que los datos vienen del método esperado (por ejemplo, $_SERVER['REQUEST_METHOD'] === 'POST').
  5. Protege cookies y archivos: Valida $_COOKIE y $_FILES rigurosamente.
  6. Usa PHP actualizado: PHP 8.3 elimina riesgos como register_globals.
  7. Errores en producción: Configura display_errors = Off para no exponer información sensible.
  8. Actualiza scripts de terceros: Mantén los scripts al día para evitar vulnerabilidades.
TOP