PHP tiene cuatro funciones para generar números aleatorios que sirven para propósitos muy distintos: rand() y mt_rand() para uso general (no criptográfico), y random_int() y random_bytes() para contextos de seguridad. Elegir la función incorrecta puede comprometer la seguridad de tu aplicación.
rand() y mt_rand(): uso general
<?php // rand(): genera un entero aleatorio en el rango [min, max] echo rand(); // número aleatorio entre 0 y PHP_INT_MAX echo rand(1, 100); // número entre 1 y 100 // mt_rand(): usa el algoritmo Mersenne Twister, más rápido y con mejor distribución echo mt_rand(); echo mt_rand(1, 6); // simular un dado // Desde PHP 7.1, rand() usa internamente el mismo algoritmo que mt_rand() // La diferencia es mÃnima; mt_rand() sigue siendo marginalmente más rápido ?>
Ni rand() ni mt_rand() son adecuadas para criptografÃa. Su secuencia es predecible si se conoce la semilla, que PHP puede reutilizar entre llamadas del mismo proceso.
random_int(): enteros seguros criptográficamente
random_int(int $min, int $max) está disponible desde PHP 7.0 y usa la fuente de entropÃa del sistema operativo (/dev/urandom en Linux, CryptGenRandom en Windows):
<?php
// Entero criptográficamente seguro en el rango [1, 100]
$numero = random_int(1, 100);
// Simular un dado de 6 caras de forma segura
$dado = random_int(1, 6);
// Si no hay suficiente entropÃa, lanza una Exception
try {
$seguro = random_int(PHP_INT_MIN, PHP_INT_MAX);
} catch (Exception $e) {
// Muy raro en sistemas modernos; gestionar igualmente
error_log('Error de entropÃa: ' . $e->getMessage());
}
?>
random_bytes(): bytes seguros criptográficamente
random_bytes(int $length) genera una cadena de N bytes aleatorios criptográficamente seguros:
<?php // Generar 16 bytes aleatorios (128 bits de entropÃa) $bytes = random_bytes(16); echo bin2hex($bytes); // representación hexadecimal (32 chars) echo base64_encode($bytes); // representación base64 (24 chars, con padding) ?>
Ejemplo real: generar contraseñas seguras
<?php
function generarPassword(int $longitud = 16, string $caracteres = ''): string
{
if ($caracteres === '') {
$caracteres = 'abcdefghijklmnopqrstuvwxyz'
. 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
. '0123456789'
. '!@#$%^&*()-_=+[]{}|;:,.<>?';
}
$max = strlen($caracteres) - 1;
$password = '';
for ($i = 0; $i < $longitud; $i++) {
$password .= $caracteres[random_int(0, $max)];
}
return $password;
}
echo generarPassword(20);
// Por ejemplo: "aK3!mZ9xP#2qN7wR8tYv"
?>
Ejemplo real: tokens CSRF
<?php
// Generar token CSRF para formularios
function generarTokenCsrf(): string
{
$token = bin2hex(random_bytes(32)); // 64 chars hex
$_SESSION['csrf_token'] = $token;
return $token;
}
function validarTokenCsrf(string $tokenRecibido): bool
{
$tokenEsperado = $_SESSION['csrf_token'] ?? '';
// hash_equals evita timing attacks
return hash_equals($tokenEsperado, $tokenRecibido);
}
// En el formulario
$token = generarTokenCsrf();
echo '<input type="hidden" name="csrf_token" value="' . htmlspecialchars($token) . '">';
// Al procesar el formulario
if (!validarTokenCsrf($_POST['csrf_token'] ?? '')) {
http_response_code(403);
exit('Token CSRF inválido');
}
?>
Ejemplo real: sorteos y selección aleatoria
<?php
// Seleccionar N ganadores de una lista sin repetición
function seleccionarGanadores(array $participantes, int $n): array
{
if ($n > count($participantes)) {
throw new InvalidArgumentException('No hay suficientes participantes');
}
$ganadores = [];
$indices = range(0, count($participantes) - 1);
for ($i = 0; $i < $n; $i++) {
$pos = random_int(0, count($indices) - 1);
$ganadores[] = $participantes[$indices[$pos]];
array_splice($indices, $pos, 1); // eliminar el Ãndice ya seleccionado
}
return $ganadores;
}
$participantes = ['Ana', 'Luis', 'MarÃa', 'Carlos', 'Elena', 'Pedro'];
$ganadores = seleccionarGanadores($participantes, 2);
echo implode(' y ', $ganadores) . ' han ganado el sorteo';
?>
Ejemplo real: códigos de recuperación de cuenta
<?php
// Generar 8 códigos de recuperación legibles (estilo GitHub)
function generarCodigosRecuperacion(int $cantidad = 8): array
{
$codigos = [];
for ($i = 0; $i < $cantidad; $i++) {
// Formato: XXXX-XXXX (solo hex en minúsculas, fácil de leer y escribir)
$parte1 = substr(bin2hex(random_bytes(2)), 0, 4);
$parte2 = substr(bin2hex(random_bytes(2)), 0, 4);
$codigos[] = "$parte1-$parte2";
}
return $codigos;
}
$codigos = generarCodigosRecuperacion();
// ['a3f1-b82c', '7d4e-1c9a', ...]
?>
Cuándo usar cada función
Función | Criptográfica | Úsala para... |
| No | Juegos, tests, datos de ejemplo, simulaciones no crÃticas |
| Sà | Passwords, tokens, sorteos, códigos de verificación |
| Sà | CSRF tokens, claves de sesión, IVs para cifrado |
La documentación de random_int() y la de random_bytes() detallan las fuentes de entropÃa utilizadas en cada sistema operativo y las excepciones que pueden lanzar.
