require
Si el archivo falta, detiene el programa.
Es lo que quieres para todo lo imprescindible: la cabecera, la conexión a la base de datos, la configuración. Sin eso, la página no tiene sentido.
Un sitio pequeño tiene ocho páginas, y las ocho llevan la misma cabecera con el mismo menú. Copiado ocho veces. Entra un servicio nuevo, se añade al menú… y unas semanas después alguien nota que en tres páginas ese enlace no está.
No es descuido: es que ocho copias no se mantienen. La solución de PHP es escribir la cabecera una vez y pedirle a cada página que la traiga.
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title><?= htmlspecialchars($titulo ?? 'Mi sitio') ?></title>
</head>
<body>
<nav>
<a href="/">Inicio</a>
<a href="/servicios.php">Servicios</a>
<a href="/contacto.php">Contacto</a>
</nav><?php
$titulo = 'Nuestros servicios';
require __DIR__ . '/partes/cabecera.php';
?>
<h1>Nuestros servicios</h1>
<p>Contenido propio de esta página.</p>
<?php require __DIR__ . '/partes/pie.php'; ?>Ya está. El menú vive en un solo archivo, y el día que entre un servicio nuevo se añade una vez y aparece en las ocho páginas.
Fíjate en $titulo: se define antes de traer la cabecera,
y la cabecera lo usa. El archivo incluido comparte las variables de quien lo incluye,
como si su contenido estuviera escrito justo ahí.
Si el archivo falta, detiene el programa.
Es lo que quieres para todo lo imprescindible: la cabecera, la conexión a la base de datos, la configuración. Sin eso, la página no tiene sentido.
Si el archivo falta, avisa y sigue.
Solo para lo accesorio: un banner opcional, un bloque que puede no existir. Usado por costumbre, produce páginas rotas a medias que nadie entiende.
Igual que require, pero si ese archivo ya se incluyó, no
lo vuelve a incluir.
Es el que se usa para archivos con funciones: incluirlo dos veces daría «ya existe una función con ese nombre» y el programa muere.
No es una forma de incluir: es la carpeta donde está este archivo.
Ponerlo delante hace que la ruta funcione sin importar desde dónde se llame a la página. Sin él, las rutas relativas se rompen en cuanto un archivo incluye a otro.
Cuando el archivo es sobre todo HTML con algo de PHP, las llaves y los
<?php echo ... ?> lo vuelven ilegible. PHP tiene dos atajos pensados
justo para esto.
<?= $x ?> es <?php echo $x; ?>, y a diferencia
de las etiquetas cortas siempre está disponible. Y las estructuras se
pueden escribir con : y endforeach en vez de llaves:
<ul>
<?php foreach ($servicios as $s): ?>
<li>
<strong><?= htmlspecialchars($s['nombre']) ?></strong>
<?php if ($s['destacado']): ?>
<span class="badge">Destacado</span>
<?php endif; ?>
</li>
<?php endforeach; ?>
</ul>Fíjate en que cada dato que se imprime pasa por
htmlspecialchars(), tal como quedó en la lección 5. En una
plantilla es donde más se olvida, porque uno está pensando en el diseño.
Ahora sí, la promesa de la lección 1. En un archivo que solo
tiene PHP -una configuración, un archivo de funciones- no se escribe el
?> final. Lo recomienda la propia documentación oficial.
El motivo: cualquier espacio o salto de línea después del ?> se envía
al navegador como contenido de la página. Y en cuanto se ha enviado algo, PHP ya no puede
mandar cabeceras.
Warning: Cannot modify header information - headers already sent by
(output started at /var/www/config.php:12) in /var/www/entrar.php on line 4Cuando veas ese mensaje, léelo entero: el paréntesis te dice
exactamente qué archivo y qué línea empezaron a imprimir. Casi siempre es un salto de
línea suelto detrás de un ?> en un archivo incluido.
Rompe justo lo que se hace después: header('Location: ...') para
redirigir, las cookies y el arranque de la sesión de la lección 7.
Al partir el sitio en archivos aparece uno especial: el que guarda la contraseña de la base de datos, la clave del servicio de correo, los datos que no puede ver nadie.
La reacción normal es guardarlo como config.php junto a las demás páginas
y confiar en que, al ser .php, el servidor lo ejecute en vez de mostrarlo.
Es verdad… mientras el servidor esté ejecutando PHP.
config.inc, config.txt,
config.php.bak, config.php~ del editor. Ninguno lo
ejecuta PHP: el servidor los entrega como texto plano, con la
contraseña dentro, a quien acierte el nombre.
Una actualización mal hecha o un módulo que no carga y el servidor deja
de interpretar PHP. Durante esos minutos, cada .php se descarga
como texto: todo tu código y todas tus claves.
Cachés, copias de seguridad, exportaciones, registros. Se cuelan porque «es solo un temporal», y un punto delante del nombre no esconde nada.
La solución es de estructura, no de permisos: lo que no es una página
se saca de la carpeta pública. El servidor solo publica una carpeta -a menudo
llamada public_html o public-, y todo lo demás vive un nivel
por encima, donde no hay ninguna dirección que lleve hasta ahí.
mi-sitio/
├── config.php <- claves. FUERA de lo publicado
├── incluye/
│ └── funciones.php
└── public_html/ <- lo único que el servidor publica
├── index.php require __DIR__ . '/../config.php';
├── servicios.php
└── partes/
├── cabecera.php
└── pie.phpcurl -o /dev/null -w "%{http_code}\n" https://ejemplo.com/config.php
curl -o /dev/null -w "%{http_code}\n" https://ejemplo.com/config.php.bak404 404
Un 404 es la respuesta correcta: ahí no hay nada que pedir. Un 200 significa que el archivo se está entregando, y entonces da igual lo bien escrita que esté tu aplicación.
Es una comprobación de treinta segundos y hay que hacerla cada vez que se publica un archivo nuevo, no una vez al año. Suponer que está bien es exactamente cómo se filtran las cosas.
En algunos alojamientos compartidos solo tienes acceso a
public_html. Entonces el archivo se protege desde el propio
servidor, con una regla en .htaccess que deniegue el acceso a esa
carpeta o a ese archivo.
Funciona, pero es un candado que depende de la configuración: si alguien mueve el sitio o cambia el servidor, el candado se queda atrás. Por eso, cuando se puede elegir, se prefiere sacar el archivo de ahí.
Se comprueba con curl, igual que arriba. La única
diferencia entre un sitio protegido y uno que cree estarlo es que en el primero
alguien pidió la dirección y miró el número que salió.
Un archivo con las funciones del sitio se incluye desde dos sitios distintos y sale «cannot redeclare function». ¿Qué usas?
require_once no vuelve a incluir un archivo ya
incluido, que es justo el problema. Y si falta, detiene el programa en vez de
seguir a medias.Sale «Cannot modify header information - headers already sent by (output started at config.php:12)». ¿Qué buscas?
Guardas una copia de config.php como
config.php.bak en la misma carpeta. ¿Qué pasa?
curl: debe responder 404.Tu sitio ya está partido en piezas y la configuración está donde debe. Falta que el servidor sepa quién está al otro lado: en la siguiente lección haces un inicio de sesión, guardas una contraseña sin poder leerla nunca y cierras una zona privada de verdad.
Siguiente: Sesiones y una zona con contraseña
Continuar ← Formularios: recibir y validar en el servidor