PHP y AJAX
Aprende a combinar PHP y AJAX para crear aplicaciones web dinámicas que actualicen partes de la página sin recargarla.
Este capítulo explica cómo combinar AJAX (en el navegador) con PHP (en el servidor) para que una página pueda comunicarse con el servidor en segundo plano y actualizar solo la parte que ha cambiado, sin necesidad de recarga completa. Construirás un ejemplo completo y funcional, verás cómo leer la solicitud en PHP y devolver JSON, y aprenderás las reglas de seguridad y manejo de errores que necesitan las aplicaciones reales.
¿Qué es PHP AJAX?
AJAX son las siglas de Asynchronous JavaScript and XML (JavaScript y XML asíncronos). A pesar del nombre, el AJAX moderno raramente usa XML: envía y recibe JSON, porque JSON se asigna directamente a objetos JavaScript y arrays PHP. La palabra clave es asíncrono: el navegador lanza una solicitud y sigue ejecutándose. Cuando el servidor responde, un callback actualiza la página. El usuario nunca ve una pantalla en blanco recargándose.
"PHP AJAX" es simplemente este patrón con PHP como lado del servidor: JavaScript envía la solicitud, un script PHP la gestiona (frecuentemente consultando una base de datos), y PHP devuelve JSON para que JavaScript lo renderice.
Usos comunes:
- Búsqueda en vivo / autocompletado — las sugerencias aparecen mientras escribes.
- Validación de formularios en línea — comprobar un nombre de usuario o correo electrónico antes de que el usuario envíe.
- Botones de me gusta / voto / favorito — actualizar un contador sin abandonar la página.
- Scroll infinito y "cargar más" — obtener la siguiente página de resultados bajo demanda.
Cómo fluye una solicitud AJAX
Un viaje de ida y vuelta siempre sigue los mismos cuatro pasos:
- Evento — el usuario escribe, hace clic o envía. JavaScript captura el evento.
- Solicitud — JavaScript envía una solicitud HTTP a un endpoint PHP (con
fetchoXMLHttpRequest). - Trabajo del servidor — PHP lee la entrada de
$_GET,$_POSTo el cuerpo raw de la solicitud, realiza su trabajo (p. ej., una consulta a la base de datos) y haceechode una respuesta JSON. - Actualización — JavaScript recibe el JSON, lo parsea y actualiza el DOM.
El navegador es el cliente; el script PHP es el servidor. Solo intercambian pequeñas porciones de datos, razón por la que AJAX parece instantáneo comparado con recargar una página entera.
Enviar la solicitud: fetch vs XMLHttpRequest
XMLHttpRequest (XHR) es la API AJAX original. fetch es el reemplazo moderno basado en promesas — más corto, más fácil de leer y disponible en todos los navegadores actuales. Usa fetch para código nuevo; solo necesitas XHR cuando debes admitir navegadores muy antiguos.
// Modern: fetch returns a Promise
fetch('endpoint.php')
.then(res => res.json()) // parse the JSON body
.then(data => console.log(data));
// Legacy: the equivalent with XMLHttpRequest
const xhr = new XMLHttpRequest();
xhr.open('GET', 'endpoint.php');
xhr.onload = () => console.log(JSON.parse(xhr.responseText));
xhr.send();Leer la solicitud y responder con JSON en PHP
La forma en que PHP lee los datos entrantes depende de cómo los envió JavaScript:
| JavaScript envía | PHP los lee con |
|---|---|
Cadena de consulta en la URL (?q=...) | $_GET['q'] |
FormData (un formulario real) | $_POST['field'] |
Cuerpo JSON.stringify(obj) | json_decode(file_get_contents('php://input'), true) |
Independientemente de la entrada, la respuesta debe ser JSON con la cabecera correcta para que el navegador la parsee correctamente:
<?php
header('Content-Type: application/json');
echo json_encode(['status' => 'success', 'value' => 42]);La línea header() indica al navegador que el cuerpo es JSON. json_encode() convierte el array PHP en una cadena JSON. Consulta PHP JSON y json_encode() para la referencia completa.
Un ejemplo completo: sugerencias de búsqueda en vivo
Este es un autocompletado completo y funcional: escribe en el cuadro, JavaScript consulta search.php y PHP devuelve los elementos coincidentes como JSON.
HTML + JavaScript (la página):
<input id="searchInput" type="text" placeholder="Search fruit…" autocomplete="off">
<ul id="results"></ul>
<script>
const input = document.getElementById('searchInput');
const list = document.getElementById('results');
let timer;
input.addEventListener('input', () => {
// Debounce: wait until the user pauses typing (avoids a request per keystroke)
clearTimeout(timer);
timer = setTimeout(() => {
const query = input.value.trim();
if (!query) { list.innerHTML = ''; return; }
fetch(`search.php?q=${encodeURIComponent(query)}`)
.then(res => res.json())
.then(data => {
list.innerHTML = data.suggestions
.map(item => `<li>${item}</li>`)
.join('');
})
.catch(() => { list.innerHTML = '<li>Search failed</li>'; });
}, 250);
});
</script>PHP (search.php):
<?php
header('Content-Type: application/json');
// 1. Read and sanitise the input
$query = trim($_GET['q'] ?? '');
// 2. Do the work. In real code this is a *prepared* SQL query — see the note below.
$fruits = ['apple', 'apricot', 'banana', 'cherry', 'grape', 'mango'];
$matches = array_values(array_filter(
$fruits,
fn($fruit) => str_contains($fruit, strtolower($query))
));
// 3. Reply with JSON
echo json_encode(['suggestions' => $matches]);Escribe ap y la lista muestra cada fruta que contiene esas letras — apple, apricot y grape — y la página nunca se recarga. Para obtener sugerencias de una base de datos en lugar del array en memoria, usa una declaración preparada como se muestra en AJAX y base de datos MySQL.
Usa siempre declaraciones preparadas. Nunca insertes
$_GET['q']directamente en una cadena SQL — eso es un agujero de inyección SQL. Usa parámetros enlazados (consulta PHP MySQLi).
Validación de formularios en línea
Valida un campo en el servidor antes de que el usuario envíe el formulario completo. Las mismas reglas PHP que protegen el envío pueden reutilizarse para la comprobación AJAX.
const form = document.getElementById('myForm');
form.addEventListener('submit', (e) => {
e.preventDefault(); // stop the normal page reload
fetch('validate.php', {
method: 'POST',
body: new FormData(form) // sends fields as $_POST
})
.then(res => res.json())
.then(data => {
if (data.valid) form.submit();
else console.log(data.errors);
});
});<?php
header('Content-Type: application/json');
$errors = [];
$email = trim($_POST['email'] ?? '');
if ($email === '') {
$errors[] = 'Email is required';
} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors[] = 'Invalid email format';
}
echo json_encode(['valid' => empty($errors), 'errors' => $errors]);new FormData(form) recoge todos los campos, por lo que PHP los lee desde $_POST. Para una cobertura más profunda de formularios, consulta Validación de formularios PHP y Superglobales PHP $_GET / $_POST.
Errores comunes
- CORS. Una solicitud a un origen diferente (dominio, puerto o esquema) queda bloqueada a menos que el servidor PHP envíe
Access-Control-Allow-Origin. Las solicitudes del mismo origen no necesitan nada. - Establece la cabecera JSON. Olvidar
header('Content-Type: application/json')sigue funcionando conres.json(), pero rompe las herramientas que dependen del tipo de contenido. Ponla siempre. - Gestiona los errores. Los fallos de red y las respuestas 500 deben capturarse — añade un
.catch()y compruebares.ok, o la interfaz de usuario fallará en silencio. - Aplica debounce a las solicitudes en vivo. Sin el debounce
setTimeoutanterior, cada pulsación de tecla lanza una solicitud y sobrecarga el servidor. - Escapa la salida que inyectas en el DOM. Insertar texto del servidor sin procesar con
innerHTMLpuede introducir XSS; escápalo o usatextContentpara datos no confiables.
Resumen
PHP AJAX permite que una página intercambie pequeñas cantidades de datos con el servidor en segundo plano y se actualice en su lugar. JavaScript envía la solicitud con fetch, PHP la lee desde $_GET/$_POST/php://input, realiza su trabajo y devuelve JSON mediante json_encode(). Mantén las entradas en declaraciones preparadas, establece la cabecera JSON y gestiona siempre la ruta de error.
Próximos pasos: conecta AJAX a una base de datos real en AJAX y MySQL, y aprende el formato de respuesta en profundidad en PHP JSON.