include y require en PHP
En esta lección
Cuando una web crece, copiar la misma cabecera, el mismo menú y las mismas funciones en cada página se vuelve insostenible: si cambias un enlace del menú, tienes que cambiarlo en veinte archivos. PHP resuelve esto con include y require, que insertan el contenido de otro archivo en el punto donde los escribes. En esta lección verás la diferencia entre las cuatro variantes, cómo construir rutas que no fallen, cómo organizar una web en plantillas, funciones y configuración, y qué errores de seguridad debes evitar.
Cómo funciona include
Imagina que tienes un archivo con una función:
<?php
// funciones.php
function precioConIva(float $precio): float
{
return round($precio * 1.21, 2);
}
Y otro archivo que la necesita:
<?php
// tienda.php
require 'funciones.php';
echo precioConIva(50), " €\n";
// 60.5 €
Cuando PHP llega a la línea del require, abre funciones.php y lo ejecuta ahí mismo, como si su contenido estuviera escrito en ese punto. A partir de entonces la función existe y puedes usarla.
Fíjate en dos detalles:
includeyrequireno son funciones, son construcciones del lenguaje: no necesitan paréntesis.require 'funciones.php';yrequire('funciones.php');hacen lo mismo; lo habitual hoy es sin paréntesis.- El archivo incluido empieza con su propia etiqueta
<?php. Si no la tuviera, PHP enviaría su contenido tal cual, como texto o HTML. Eso es justo lo que permite incluir trozos de HTML, como verás enseguida.
Las cuatro variantes
| Instrucción | Si el archivo no existe | Si ya se incluyó antes |
|---|---|---|
include | Warning y el script sigue | Lo vuelve a incluir |
require | Fatal error y el script se detiene | Lo vuelve a incluir |
include_once | Warning y el script sigue | No lo incluye otra vez |
require_once | Fatal error y se detiene | No lo incluye otra vez |
include frente a require
La diferencia está en qué pasa si el archivo no se encuentra:
include 'no-existe.php';
echo "Con include, el programa continúa\n";
require 'tampoco-existe.php';
echo "Esta línea nunca se ejecuta\n";
// Warning: include(no-existe.php): Failed to open stream: No such file or directory in ...
// Warning: include(): Failed opening 'no-existe.php' for inclusion ...
// Con include, el programa continúa
// Warning: require(tampoco-existe.php): Failed to open stream: No such file or directory in ...
// Fatal error: Uncaught Error: Failed opening required 'tampoco-existe.php' ...
¿Cuál usar? Pregúntate si la página tiene sentido sin ese archivo:
requirepara lo imprescindible: funciones, configuración, conexión a la base de datos. Si falta, es mejor parar que seguir con la página rota (y quizá mostrando errores raros más abajo).includepara lo opcional: un banner de temporada o un bloque de publicidad. Si falta, el resto de la página se muestra igual.
En la práctica, require es lo más habitual.
Las versiones _once
Si incluyes dos veces un archivo que define funciones, PHP da un error, porque no se puede declarar dos veces la misma función:
Fatal error: Cannot redeclare function precioConIva() (previously declared in .../funciones.php:3)
Esto pasa más fácil de lo que parece: index.php incluye funciones.php y también carrito.php, que a su vez incluye funciones.php. Con require_once, PHP recuerda qué archivos ya ha cargado y no repite ninguno:
require_once 'funciones.php';
require_once 'funciones.php'; // se ignora
echo precioConIva(10), "\n";
// 12.1
Usa require_once para archivos que definen cosas (funciones, clases, constantes) y include o require normales para trozos de HTML que quieras mostrar varias veces, como una tarjeta de producto dentro de un bucle.
Rutas que no fallan: __DIR__
Las rutas relativas ('funciones.php', '../config.php') tienen reglas enrevesadas: según cómo empiecen, PHP las busca en las carpetas de la directiva include_path, en la carpeta del script o en el directorio de trabajo, que depende de cómo se ejecutó la página. Por ejemplo, '../config.php' siempre se resuelve desde el directorio de trabajo, no desde el archivo que hace el require. El resultado: un require que funciona en index.php deja de funcionar dentro de un archivo de otra carpeta, o al ejecutar el script desde la terminal.
La solución es construir siempre rutas absolutas con la constante mágica __DIR__, que vale la carpeta del archivo donde está escrita:
require_once __DIR__ . '/includes/funciones.php';
require_once __DIR__ . '/../config.php'; // la carpeta de arriba
require_once dirname(__DIR__) . '/config.php'; // lo mismo, más claro
dirname() devuelve la carpeta que contiene a otra. Es la misma técnica que usarás con ficheros en Ficheros y subidas.
Otras constantes mágicas
Se llaman “mágicas” porque su valor cambia según dónde las escribas:
| Constante | Valor |
|---|---|
__DIR__ | Carpeta del archivo actual |
__FILE__ | Ruta completa del archivo actual |
__LINE__ | Número de línea donde aparece |
__FUNCTION__ | Nombre de la función donde aparece |
<?php
// demo.php
function registrar(string $mensaje): void
{
echo "[", __FUNCTION__, "] ", $mensaje, " (línea ", __LINE__, ")\n";
}
registrar("Reserva guardada");
echo basename(__FILE__), "\n";
// [registrar] Reserva guardada (línea 5)
// demo.php
basename() se queda con la última parte de una ruta. Son útiles sobre todo para mensajes de depuración y registros de errores.
Plantillas: cabecera y pie comunes
El uso más clásico es compartir la cabecera y el pie de todas las páginas. Esta podría ser la estructura de la web de un rocódromo:
mi-web/
├── index.php
├── horarios.php
├── tarifas.php
└── includes/
├── cabecera.php
├── pie.php
└── funciones.php
La cabecera contiene el principio del HTML y el menú. Usa una variable $titulo que definirá cada página:
<?php // includes/cabecera.php ?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title><?= htmlspecialchars($titulo ?? 'Rocódromo') ?> | Rocódromo</title>
<link rel="stylesheet" href="/css/estilos.css">
</head>
<body>
<header>
<nav>
<a href="/">Inicio</a>
<a href="/horarios.php">Horarios</a>
<a href="/tarifas.php">Tarifas</a>
</nav>
</header>
<main>
El pie cierra lo que abrió la cabecera:
<?php // includes/pie.php ?>
</main>
<footer>
<p>© <?= date('Y') ?> Rocódromo. Todos los derechos reservados.</p>
</footer>
</body>
</html>
Y cada página queda reducida a su contenido propio:
<?php
// tarifas.php
require_once __DIR__ . '/includes/funciones.php';
$titulo = 'Tarifas';
$tarifas = ['Entrada de día' => 9, 'Bono 10 entradas' => 80, 'Cuota mensual' => 45];
require __DIR__ . '/includes/cabecera.php';
?>
<h1>Tarifas</h1>
<ul>
<?php foreach ($tarifas as $nombre => $precio): ?>
<li><?= htmlspecialchars($nombre) ?>: <?= precioConIva($precio) ?> €</li>
<?php endforeach; ?>
</ul>
<?php require __DIR__ . '/includes/pie.php'; ?>
Las claves de este patrón:
- El archivo incluido ve las variables del lugar donde se incluye. Por eso
cabecera.phppuede usar$titulo. Si elrequireestá dentro de una función, solo verá las variables de esa función. - Cambiar el menú supone editar un único archivo, y todas las páginas se actualizan.
$titulo ?? 'Rocódromo'da un valor por defecto si alguna página olvida definir el título.- La sintaxis
foreach (...):/endforeach;es la sintaxis alternativa, más legible cuando se mezcla con HTML.
Marcar el enlace activo
Un detalle habitual: resaltar en el menú la página en la que estás. Cada página define también una variable $pagina, y la cabecera la compara:
<?php
$enlaces = ['index' => 'Inicio', 'horarios' => 'Horarios', 'tarifas' => 'Tarifas'];
$pagina = 'horarios';
foreach ($enlaces as $archivo => $texto) {
$activo = $archivo === $pagina ? ' aria-current="page"' : '';
echo "<a href=\"/$archivo.php\"$activo>$texto</a>\n";
}
// <a href="/index.php">Inicio</a>
// <a href="/horarios.php" aria-current="page">Horarios</a>
// <a href="/tarifas.php">Tarifas</a>
El atributo aria-current="page" le dice a los lectores de pantalla cuál es la página actual, y puedes darle estilo en CSS con [aria-current="page"].
Archivos de configuración que devuelven un valor
Un archivo incluido puede terminar con return, y ese valor es lo que devuelve el require. Es la forma moderna de guardar la configuración:
<?php
// config.php
return [
'nombre_web' => 'Rocódromo Vertical',
'email_contacto' => 'info@ejemplo.com',
'bd' => [
'host' => 'localhost',
'nombre' => 'rocodromo',
'usuario' => 'web',
'clave' => 'cambia-esto',
],
];
$config = require __DIR__ . '/config.php';
echo $config['nombre_web'], "\n";
echo $config['bd']['host'], "\n";
// Rocódromo Vertical
// localhost
Ventajas frente a definir variables sueltas en config.php: queda claro de dónde viene cada dato ($config['bd']), no “ensucia” las variables de la página y puedes tener un config.php distinto en tu ordenador y en el servidor. Usarás esta idea en MySQL con PDO.
Cuidado: si usas Git, no subas el archivo con contraseñas reales al repositorio. Lo habitual es subir un
config.ejemplo.phpcon valores falsos y añadirconfig.phpal.gitignore.
Seguridad: dos reglas de oro
1. Nunca incluyas un archivo elegido por el usuario
En webs antiguas era habitual algo así para cargar secciones:
// MAL: el usuario controla qué archivo se ejecuta
include $_GET['seccion'] . '.php';
Un atacante puede pedir ?seccion=../../algo y hacer que tu web lea o ejecute archivos que no debía. Es una vulnerabilidad llamada inclusión de archivos locales (LFI). Si necesitas elegir la página según un parámetro, usa una lista cerrada:
$seccion = $_GET['seccion'] ?? 'inicio';
$archivo = match ($seccion) {
'inicio' => 'inicio.php',
'horarios' => 'horarios.php',
'tarifas' => 'tarifas.php',
default => '404.php',
};
echo "Se incluiría: $archivo\n";
// Se incluiría: inicio.php
Así, el valor del usuario solo sirve para elegir entre opciones que tú controlas; nunca forma parte de la ruta. Tienes más técnicas en Seguridad.
Nota: PHP también podría incluir archivos desde una URL (
include 'http://...'), y verás ejemplos así en tutoriales viejos. La opciónallow_url_includeviene desactivada por defecto, y así debe seguir: ejecutar código descargado de otro servidor es un riesgo enorme.
2. Deja fuera de la web lo que no sea una página
Si alguien escribe en el navegador tuweb.com/includes/funciones.php, el servidor ejecutará ese archivo. Normalmente no mostrará nada, pero no es buena idea dejarlo accesible. Y si tu archivo de configuración se llamara config.inc en lugar de config.php, el servidor lo enviaría como texto, contraseñas incluidas.
Por eso:
- Usa siempre la extensión
.phpen los archivos incluidos. - En proyectos más serios, se separa la carpeta pública (la única accesible desde el navegador) del resto:
proyecto/
├── config.php ← fuera de la carpeta pública
├── src/
│ └── funciones.php
├── plantillas/
│ ├── cabecera.php
│ └── pie.php
└── public/ ← el servidor solo sirve esta carpeta
├── index.php
└── css/
Desde public/index.php, los archivos de fuera se cargan con require dirname(__DIR__) . '/src/funciones.php';. En un hosting compartido no siempre puedes elegir la carpeta pública, pero muchos lo permiten desde su panel.
Más allá de include: autoload
Cuando trabajes con clases (lo verás en Clases y objetos), escribir un require_once por cada clase se vuelve pesado. PHP permite registrar una función de autocarga (autoload) que carga cada clase automáticamente la primera vez que se usa. Normalmente no la escribirás tú: se encarga Composer, que genera un único archivo vendor/autoload.php que incluyes al principio.
Errores frecuentes
- Rutas relativas que funcionan en una página y fallan en otra: construye las rutas con
__DIR__ . '/...'. - “Cannot redeclare function”: has incluido dos veces un archivo con funciones. Usa
require_once. - Olvidar
<?phpen el archivo incluido: su código aparece como texto en la página en lugar de ejecutarse. - Variables que “no existen” en la cabecera: define
$tituloy compañía antes delrequirede la cabecera. - Usar
includepara algo imprescindible: si falta el archivo, la página sigue a medias y los errores aparecen más abajo, lejos de la causa. Usarequire. - Incluir rutas construidas con datos del usuario: usa una lista cerrada con
match. - Guardar configuración en archivos
.inc,.txto.inidentro de la carpeta pública: el servidor puede enviarlos como texto.
Resumen
| Concepto | Lo esencial |
|---|---|
include | Inserta y ejecuta otro archivo; si falta, Warning y sigue |
require | Igual, pero si falta, Fatal error y se detiene |
_once | No vuelve a incluir un archivo ya cargado; para funciones y clases |
| Rutas | __DIR__ . '/includes/archivo.php', dirname(__DIR__) para subir |
| Constantes mágicas | __DIR__, __FILE__, __LINE__, __FUNCTION__ |
| Plantillas | cabecera.php y pie.php; las variables definidas antes son visibles |
| Configuración | return [...] en config.php y $config = require ... |
| Seguridad | Nunca incluir rutas del usuario; extensión .php; carpeta public/ |
| Clases | Autoload con Composer |
En la siguiente lección aprenderás a trabajar con fechas y horas: fechas.
Pon a prueba lo que has aprendido
¿Te ha quedado claro? Márcala y verás tu progreso en el explorador.