2.4Fechas, expresiones regulares y correos electrónicos
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.
¿Lo sabía?
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
- Maneje fechas con DateTime: cree, formatee para mostrar (->format('d/m/Y')), calcule una diferencia (->diff); configure el huso horario.
- Recuerde: guardar las fechas en formato estándar (ISO) y FORMATEAR solo al mostrar (nunca guardar un formato localizado).
- Valide con filter_var (correo, URL) antes que con una regex casera; reserve las regex (preg_match) a patrones específicos.
- 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.
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.
✓ 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().
- 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.
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.
¿Cómo validar un correo en PHP?