Saltar al contenido
include-y-require.php · devschool

include y require en PHP

Lección 12 de 26 · 11 min de lectura · Actualizado el

En esta lección
  1. Cómo funciona include
  2. Las cuatro variantes
  3. Rutas que no fallan: __DIR__
  4. Plantillas: cabecera y pie comunes
  5. Archivos de configuración que devuelven un valor
  6. Seguridad: dos reglas de oro
  7. Más allá de include: autoload
  8. Errores frecuentes
  9. Resumen

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:

  • include y require no son funciones, son construcciones del lenguaje: no necesitan paréntesis. require 'funciones.php'; y require('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ónSi el archivo no existeSi ya se incluyó antes
includeWarning y el script sigueLo vuelve a incluir
requireFatal error y el script se detieneLo vuelve a incluir
include_onceWarning y el script sigueNo lo incluye otra vez
require_onceFatal error y se detieneNo 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:

  • require para 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).
  • include para 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:

ConstanteValor
__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>&copy; <?= 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.php puede usar $titulo. Si el require está 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.php con valores falsos y añadir config.php al .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ón allow_url_include viene 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 .php en 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 <?php en 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 $titulo y compañía antes del require de la cabecera.
  • Usar include para algo imprescindible: si falta el archivo, la página sigue a medias y los errores aparecen más abajo, lejos de la causa. Usa require.
  • Incluir rutas construidas con datos del usuario: usa una lista cerrada con match.
  • Guardar configuración en archivos .inc, .txt o .ini dentro de la carpeta pública: el servidor puede enviarlos como texto.

Resumen

ConceptoLo esencial
includeInserta y ejecuta otro archivo; si falta, Warning y sigue
requireIgual, pero si falta, Fatal error y se detiene
_onceNo 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__
Plantillascabecera.php y pie.php; las variables definidas antes son visibles
Configuraciónreturn [...] en config.php y $config = require ...
SeguridadNunca incluir rutas del usuario; extensión .php; carpeta public/
ClasesAutoload con Composer

En la siguiente lección aprenderás a trabajar con fechas y horas: fechas.

Pon a prueba lo que has aprendido

[PHP] El archivo no existe. ¿Qué diferencia hay entre include y require?

[PHP] Incluyes dos veces un archivo con la función precioConIva() y aparece "Cannot redeclare function". ¿Cuál es la solución más sencilla?

[PHP] ¿Por qué se escribe require __DIR__ . '/includes/funciones.php' en vez de una ruta relativa?

[PHP] ¿Qué riesgo tiene include $_GET['seccion'] . '.php';?

¿Te ha quedado claro? Márcala y verás tu progreso en el explorador.