2.4 · Fechas, expresiones regulares y correos electrónicos

Nivel 2 · PHP y la Web

2.4Fechas, expresiones regulares y correos electrónicos

Objetivo: Manipular fechas con DateTime (huso, formato de almacenamiento), validar con filter_var (antes que regex caseras) y enviar correos vía bibliotecas dedicadas — apoyándose en herramientas probadas.
Tiempo estimado: 11 min · lectura autónoma · Si solo tienes 5 min: lee «Lo esencial en 30s» + el esquema.

Lo esencial en 30 segundos

  • Fechas con DateTime: crear, formatear al mostrar (->format), calcular diferencias (->diff) — huso configurado si no horas erróneas.
  • Guardar ISO, mostrar local: se guarda AAAA-MM-DD (ordenable, no ambiguo) y se formatea solo al mostrar — nunca formato localizado en la base.
  • filter_var primero, regex si hace falta, biblioteca para los correos: correo y URL vía filter_var, patrones de negocio en regex probada, envíos vía PHPMailer o Symfony Mailer — nunca mail() en producción seria.

Minicaso hilado — Riad fecha, controla y escribe a los miembros

Último acto del proyecto: Riad fecha las inscripciones (2.1) y las fotos (2.3) con DateTime — tras perder una tarde con horas desplazadas por el huso no configurado. Controla los números de miembro (formato interno preciso) con una regex probada, pero valida los correos con filter_var antes que una regex casera. Y para el boletín, abandona mail() por una biblioteca dedicada que gestiona la autenticación y la entregabilidad. El proyecto del nivel 2 está entregado: formularios, sesiones, archivos, fechas.

Epílogo del hilo 2.1-2.3: el sitio de Riad maneja fechas, patrones y correos con las herramientas correctas.

1. Fechas: DateTime, huso y almacenamiento

Las fechas están en todas partes (creación, eventos, duraciones) y PHP moderno las gestiona en ORIENTADO A OBJETOS con DateTime — y DateTimeImmutable, preferible por no modificable: crear (new DateTime('2026-07-25'), new DateTime() para ahora), FORMATEAR para mostrar (->format('d/m/Y')), calcular DIFERENCIAS (->diff() entre dos fechas, que gestiona años bisiestos y meses desiguales), sumar/restar duraciones. Las funciones procedurales antiguas (date(), time(), strtotime()) existen — las encontrará. Dos precauciones: el huso horario (a configurar explícitamente, si no todas las horas quedan desplazadas — la trampa n.º 1 de Riad; para lo internacional, guardar en UTC y convertir al mostrar) y el formato de almacenamiento: se guarda en formato estándar ISO (AAAA-MM-DD, también el de las bases — ordenable, no ambiguo) y se FORMATEA solo al mostrar — nunca al revés.

2. Regex: potentes, pero no para todo

Las expresiones regulares (regex) describen PATRONES en texto: comprobar un formato (código postal, referencia de negocio), extraer partes, sustituir según un patrón. En PHP: preg_match() (¿corresponde?), preg_match_all(), preg_replace(), preg_split(). Son POTENTES pero de fama difícil (sintaxis críptica, fáciles de escribir mal — demasiado estrictas, demasiado laxas, a veces lentas). De ahí la regla: para validaciones CORRIENTES (correo, URL, IP, entero), no escriba SU regex — use filter_var() (FILTER_VALIDATE_EMAIL, FILTER_VALIDATE_URL), probado y fiable (validar un correo correctamente por regex es sorprendentemente difícil). Reserve las regex a patrones ESPECÍFICOS no cubiertos por los filtros — como el número de miembro de Riad — probándolas con cuidado y comentándolas. Para manipulaciones SIMPLES (buscar, sustituir, trocear), prefiera las funciones de cadenas, más legibles y más rápidas.

3. Correos: biblioteca dedicada, cabeceras blindadas

La función nativa mail() es BÁSICA y poco fiable (entregabilidad, spam, configuración del servidor): para enviar en serio, se usan BIBLIOTECAS dedicadas (PHPMailer, Symfony Mailer) que gestionan la autenticación SMTP, los adjuntos, el HTML y la entregabilidad — o servicios de envío terceros. Punto de SEGURIDAD: no insertar nunca datos de usuario no controlados en las CABECERAS de un correo (fallo de inyección de cabecera). El boletín de Riad sale pues vía una biblioteca, con cabeceras construidas a partir de valores controlados. Principio transversal de la sección: apoyarse en las HERRAMIENTAS PROBADAS (DateTime, filter_var, bibliotecas de correo) antes que chapucearlo todo a mano.

Error frecuente de interpretación: «Una regex casera para los correos es más precisa que filter_var». No, es al revés: la especificación de correos válidos es de una complejidad temible, y las regex caseras casi siempre son o demasiado estrictas (rechazan correos válidos) o demasiado laxas (aceptan cualquier cosa) — sin hablar de los casos límite nunca probados. filter_var con FILTER_VALIDATE_EMAIL aplica una validación probada y mantenida. La regla de Riad: caso corriente cubierto por un filtro = filter_var, sin discutir; regex reservada a patrones específicos de su necesidad, probada y comentada.
Fechas, patrones, correos Las buenas herramientas probadas DateTimeCrear, formatear, ->diff; huso + ISO+Regex frente a filter_varfilter_var para email/URL; regex = patrones específicos+CorreosBiblioteca dedicada (no mail()) Apoyarse en las herramientas probadas antes que hacerlo todo a mano.
Las buenas herramientas probadas
Versión en texto del esquema (SEO / lectores de pantalla / traducción): 1) Riad maneja las FECHAS con DateTime: creación, formateo al mostrar, diferencias con ->diff — huso configurado, almacenamiento en ISO, nunca formato localizado en la base. 2) Para los PATRONES, valida correos y URL con filter_var (probado) y reserva las regex probadas a formatos de negocio específicos. 3) Envía sus CORREOS vía una biblioteca dedicada (autenticación, entregabilidad), sin dato no controlado en las cabeceras. Lección: la buena herramienta probada para cada necesidad, sin chapuzas caseras.

¿Lo sabía?

Riad perdió una tarde con horas desplazadas: el huso del servidor no era el de Constantine.
Verdadero: un huso no configurado falsea todas las marcas de tiempo — la trampa n.º 1 de las fechas.

Una línea de huso vale una tarde de depuración.

🔎 Ejemplo concreto — 🔎 Ejemplo concreto — La inscripción de Riad, fechada y validada

DateTime + filter_var, como en casa de Riad:

$d = new DateTime('2026-07-25');
echo $d->format('d/m/Y');
// almacenamiento : formato ISO 2026-07-25
if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
  echo htmlspecialchars($email, ENT_QUOTES, 'UTF-8');
}

Lectura: creación y formateo de fecha, almacenamiento ISO, validación fiable sin regex casera.

Lección: configurar el huso; guardar ISO, formatear al mostrar.

Vocabulario de la sección

Fechas (DateTime)
PHP moderno maneja las fechas con DateTime/DateTimeImmutable: crear, FORMATEAR para mostrar (->format), calcular diferencias (->diff), sumar/restar.

Ejemplo sencillo: Riad fecha cada inscripción con new DateTime().

Lo que no es: unos cálculos de duración a mano sobre timestamps.

Reflejo: manejar una fecha = DateTime.

Huso y formato de almacenamiento
Configurar el HUSO horario (si no horas erróneas); GUARDAR en formato estándar ISO (AAAA-MM-DD) y FORMATEAR solo al mostrar.

Ejemplo sencillo: Riad guarda 2026-07-25 y muestra 25/07/2026.

Lo que no es: una fecha localizada guardada tal cual en la base.

Reflejo: guardar ISO, mostrar local.

Expresiones regulares (regex)
Minilenguaje que describe patrones en texto; preg_match (¿corresponde?), preg_replace (sustituir) — potentes pero difíciles.

Ejemplo sencillo: Riad controla el número de miembro con una regex probada.

Lo que no es: una regex casera para validar los correos.

Reflejo: patrón de negocio específico = regex probada y comentada.

filter_var para validar
Para validaciones corrientes (correo, URL…), preferir filter_var (FILTER_VALIDATE_EMAIL…) a una regex casera — más fiable.

Ejemplo sencillo: Cada correo de miembro pasa por FILTER_VALIDATE_EMAIL.

Lo que no es: una regex copiada sin probar para los correos.

Reflejo: caso corriente = filtro probado.

Envío de correos
La función nativa mail() es básica y poco fiable; usar bibliotecas dedicadas (PHPMailer, Symfony Mailer) — nunca datos no controlados en las cabeceras.

Ejemplo sencillo: La carta de Riad sale vía una biblioteca con SMTP autenticado.

Lo que no es: un mail() artesanal para envíos masivos.

Reflejo: correo serio = biblioteca dedicada.

En la práctica — En la práctica — Fechas, regex y correos

  1. Maneje fechas con DateTime: cree, formatee para mostrar (->format('d/m/Y')), calcule una diferencia (->diff); configure el huso horario.
  2. Recuerde: guardar las fechas en formato estándar (ISO) y FORMATEAR solo al mostrar (nunca guardar un formato localizado).
  3. Valide con filter_var (correo, URL) antes que con una regex casera; reserve las regex (preg_match) a patrones específicos.
  4. Para enviar un correo en serio, use una biblioteca dedicada (PHPMailer / Symfony Mailer) antes que mail(); no inyecte nunca datos no controlados en las cabeceras.
Maneja las fechas con DateTime (huso, formato de almacenamiento), valida con filter_var (antes que regex caseras) y envía correos vía bibliotecas dedicadas — apoyándose en las herramientas probadas.

Script listo para decir — defender las herramientas probadas en revisión de código (30 s)

«Para las fechas uso DateTime con el huso configurado, guardo en ISO y formateo al mostrar — fin de las horas desplazadas. Los correos pasan por filter_var, no por una regex casera. Y los envíos salen vía una biblioteca con SMTP autenticado, no por mail(). Tres herramientas probadas, cero chapuzas.»

Para decir mostrando el error de huso corregido y una regex casera sustituida por filter_var.

Modelo copiar-pegar — fecha, diferencia y validación de correo

format('d/m/Y');
$aujourdhui = new DateTime();
$ecart = $inscription->diff($aujourdhui);
echo $ecart->format('%a jours d\u2019ancienneté');
// almacenamiento : $inscription->format('Y-m-d H:i:s')
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
  echo 'E-mail invalide.';
}

Antigüedad de miembro

Riad calcula los años de membresía con ->diff: bisiestos y meses desiguales gestionados, sin cálculo manual.

Referencia de negocio

El número de miembro sigue un formato interno estricto: regex dedicada, probada en casos límite, comentada.

Correo de bienvenida

Dirección validada por filter_var, envío vía biblioteca SMTP: la bienvenida llega en lugar de acabar en spam.

Código antiguo procedural

Un date() o strtotime() cruzado en mantenimiento: Riad lo lee, luego migra a DateTime para toda manipulación.

Prudencia: No inserte nunca un dato de usuario no controlado en las cabeceras de un correo: un atacante inyecta ahí sus propias cabeceras (destinatarios ocultos, contenido forjado) y desvía su servidor para spam. Construya las cabeceras a partir de valores controlados y pase por una biblioteca que las protege. Esta guía da el principio — haga validar todo envío real antes de la puesta en producción.

✓ Buenas prácticas

  • Usar DateTime/DateTimeImmutable; configurar el huso horario.
  • Guardar las fechas en ISO, formatear solo al mostrar.
  • Validar correo/URL con filter_var; enviar los correos vía una biblioteca dedicada.

✗ Errores frecuentes

  • Huso horario no configurado (horas desplazadas) — trampa n.º 1.
  • Guardar una fecha en formato localizado (ambiguo, no ordenable).
  • Escribir una regex casera para validar un correo (difícil, poco fiable).

Puntos clave

  • FECHAS: PHP moderno usa la clase DateTime/DateTimeImmutable (crear, ->format para mostrar, ->diff para las diferencias). Precaución: HUSO horario (si no horas erróneas) y FORMATO de ALMACENAMIENTO (ISO AAAA-MM-DD, formatear solo al mostrar).
  • REGEX (preg_match, preg_replace) = patrones en texto, potentes pero difíciles. Para validaciones CORRIENTES (correo, URL), preferir filter_var (FILTER_VALIDATE_EMAIL) a una regex casera.
  • CORREOS: la función nativa mail() es básica/poco fiable; usar BIBLIOTECAS dedicadas (PHPMailer, Symfony Mailer) para la fiabilidad y la entregabilidad.
  • Principio transversal: apoyarse en las HERRAMIENTAS PROBADAS (DateTime, filter_var, bibliotecas de correo) antes que hacerlo todo a mano. Seguridad: sin datos no controlados en las cabeceras de correo.

Reto 48h — aplique mañana

Feche un dato real con DateTime (huso configurado, almacenamiento ISO, visualización formateada, un ->diff real), sustituya una regex casera de correo por filter_var y prepare un envío vía biblioteca en lugar de mail().

Lista de salida de la sección
  • Puedo manejar una fecha (crear, formatear, calcular una diferencia) sin error de huso.
  • Sé cuándo usar filter_var y cuándo una regex está justificada.
  • He preparado un envío de correo vía biblioteca, cabeceras blindadas.
Autoevaluación 1-5: ¿guardo ISO y formateo al mostrar?¿elijo la herramienta probada antes que la chapuza casera?

Preguntas frecuentes

¿Cuáles son las trampas corrientes con las fechas en PHP y cómo evitarlas?

(1) HUSO HORARIO mal configurado (trampa n.º 1): horas desplazadas, marcas falsas. Configúrelo explícitamente (date_default_timezone_set() o date.timezone); para lo internacional, guarde en UTC y convierta al mostrar. (2) Confundir ALMACENAMIENTO y VISUALIZACIÓN: no guarde nunca un formato localizado — guarde en ISO (AAAA-MM-DD, ordenable, no ambiguo, estándar en base) y formatee SOLO al mostrar (->format('d/m/Y')). (3) Funciones antiguas (date(), strtotime()): prefiera DateTime/DateTimeImmutable para las manipulaciones. (4) Cálculos manuales (timestamps restados): tramposos (bisiestos, meses desiguales) — use ->diff(). (5) Cambio de hora: DateTime con los buenos husos lo gestiona. (6) Análisis: DateTime::createFromFormat() con formato preciso, luego validación.

¿Hay que aprender las expresiones regulares y cuándo usarlas (o evitarlas)?

Sí, las BASES — las encontrará en todas partes — pero sin obsesión. A EVITAR: (1) validaciones CORRIENTES (correo, URL, IP, entero) — use filter_var (FILTER_VALIDATE_EMAIL…): validar un correo por regex es sorprendentemente difícil, las regex caseras son demasiado estrictas o demasiado laxas; (2) manipulaciones SIMPLES — prefiera las funciones de cadenas (str_contains, str_replace, explode). JUSTIFICADAS: patrones ESPECÍFICOS no cubiertos (formato interno, referencia de negocio, extracción precisa) — probadas con cuidado (casos límite) y COMENTADAS (ilegibles si no). El buen desarrollador sabe cuándo emplear una regex y cuándo preferir la herramienta dedicada — nada de regex en todas partes por virtuosismo.

Comprueba tu comprensión

¿Cómo validar un correo en PHP?

Recursos adicionales (opcional, para ir más allá)

Examen del nivel 2Preguntas inéditas y más difíciles para validar tus conocimientos