Esta lección comenta el uso de los formularios HTML para conseguir páginas web PHP interactivas.
Los formularios son los elementos de las páginas web que permiten a un usuario introducir información en una página web. Así, los formularios nos permiten crear páginas web PHP interactivas en las que el contenido de la página se adapta a la información proporcionada por el usuario.
En el caso más simple, se suelen distribuir las tareas en dos páginas independientes:
El ejemplo siguiente corresponde a la imagen anterior (la página con el formulario se llama form-1-1.php y la página que recibe los datos se llama form-1-2.php):
Las etiquetas de HTML que permiten la creación de formularios y de los diferentes tipos de controles (cajas de texto, casillas de verificación, botones radio, etc.) se comentan en las lecciones Formularios (1) y Formularios (2) de los apuntes de Páginas web HTML y hojas de estilo CSS.
Este curso de PHP se centra en el tratamiento de los datos proporcionados por el usuario mediante el uso de formularios, no en el diseño de formularios. De hecho, en la mayoría de ejercicios propuestos en estos apuntes, los formularios están incluidos en las plantillas de los ejercicios y el alumno no necesita crearlos, pero se recomienda tener un conocimiento general de las etiquetas y atributos relacionados con formularios.
Cuando un formulario envía los datos a una página PHP, los datos están automáticamente a disposición del programa PHP en una matriz llamada $_REQUEST. Cada dato recibido es un elemento de la matriz $_REQUEST: el índice del elemento es el nombre del control y el valor del elemento es el dato introducido o seleccionado por el usuario en el control.
Nota: Si el atributo name contiene espacios en blanco, puntos o el carácter [ (sin el carácter ]), estos se convierten en guiones bajos en la matriz $_REQUEST.
En el siguiente ejemplo, el programa que recibe los datos del formulario simplemente muestra el contenido de la matriz $_REQUEST utilizando la función print_r() que muestra los índices y valores de la matriz. La página con el formulario se llama form-2-1.php y la página que recibe los datos se llama form-2-2.php
Como se puede comprobar en el ejemplo anterior, el control de caja de texto crea siempre un elemento en la matriz $_REQUEST (aunque la caja de texto se deje vacía), mientras que el botón radio solamente crea un elemento en la matriz $_REQUEST si se elige una de las opciones del botón radio.
En la lección Controles en formularios de estos apuntes se detallan las particularidades de cada tipo de control.
Los valores que se reciben de un formulario son siempre de tipo cadena, aunque sean valores numéricos. Sin embargo, los nombres de los controles que se reciben de un formulario (y que se convierten en índices de la matriz $_REQUEST) pueden ser de tipo entero (si son números enteros) o de tipo cadena (si no son números enteros). Los nombres de los controles pueden tener estructura de matriz, incluyendo corchetes.
<form action="form-6-2.php" method="get">
<p>Nombre: <input type="text" name="nombre"></p>
<p>Edad: <input type="number" name="1"></p>
<p>
Aficiones:
<input type="checkbox" name="aficion[1]"> Deporte
<input type="checkbox" name="aficion[2]"> Lectura
</p>
<p><input type="submit" value="Enviar"></p>
</form>
El atributo method de la etiqueta <form> permite elegir si la información de los controles se incluye en la URL de llamada a la página (method="get") o se incluyen en las cabeceras HTTP (method="post"). Si no se incluye el atributo method, el comportamiento predeterminado es el mismo que con get, es decir, los datos se incluyen en la URL.
La diferencia es que con el valor get se pueden ver en la barra de dirección los nombres de los controles y los valores introducidos por el usuario, mientras que con el valor post no. Los datos recibidos son los mismos y desde el punto de vista de la seguridad ambos métodos son equivalentes (es decir, inseguros si se utiliza http y seguros si se utiliza https).
Normalmente, los formularios disponibles en Internet utilizan el método post, de manera que las URL sean más "limpias" al no contener los datos de los formularios. Pero en estos apuntes, los formularios utilizan el método get, de manera que se puedan simular fácilmente ataques de inyección, como se comenta en el apartado siguiente.
El formulario envía el valor de un control incluyéndolo en una cabecera HTTP, que no es visible para el usuario, como se ve en el ejemplo siguiente:
<form action="form-3-2.php" method="post">
<p>Nombre: <input type="text" name="nombre"></p>
<p><input type="submit" value="Enviar"></p>
</form>
<?php
print "<pre>";
print_r($_REQUEST);
print "</pre>\n";
?>
El formulario envía el valor de un control incluyéndolo al final de la URL, añadiendo un interrogante, el nombre del control, un signo igual y el valor (es decir, ?nombre=valor), como se puede comprobar en el ejemplo siguiente. Para poder ver las URL en su navegador, abra el ejemplo en una pestaña haciendo clic en el icono de enlace al ejemplo situado a la derecha del ejemplo.
<form action="form-4-1.php" method="get">
<p>Nombre: <input type="text" name="nombre"></p>
<p><input type="submit" value="Enviar"></p>
</form>
<?php
print "<pre>";
print_r($_REQUEST);
print "</pre>\n";
?>
En caso de que haya varios controles que envíen información en un formulario con get, los nombres y valores aparecen en la barra de dirección separados por el carácter ampersand (&), como nombre1=valor1&nombre2=valor2&..., como se puede comprobar en el ejemplo siguiente. Para poder ver las URL en su navegador, abra el ejemplo en una pestaña haciendo clic en el icono de enlace al ejemplo situado a la derecha del ejemplo.
<form action="form-5-1.php" method="get">
<p>Nombre: <input type="text" name="nombre"></p>
<p>Apellidos: <input type="text" name="apellidos"></p>
<p><input type="submit" value="Enviar"></p>
</form>
<?php
print "<pre>";
print_r($_REQUEST);
print "</pre>\n";
?>
PHP incluye en la matriz $_REQUEST todos los datos que llegan junto con la petición de la página, tanto si están incluidos en la URL como si están incluidos en cabeceras HTTP. PHP también crea otras dos matrices, $_GET y $_POST, que contienen los datos recibidos por uno de los métodos, $_GET los recibidos en la URL (get) y $_POST los recibidos en cabeceras (post).
Es importante ser consciente de que cualquier página PHP puede recibir datos y que se pueden enviar datos a cualquier página PHP. Enviar datos a una página que no espera recibir datos no suele afectar al funcionamiento de la página y por tanto no suele suponer un riesgo de seguridad, pero si hablamos de una página que espera recibir datos de un formulario, entonces estamos ante la posibilidad de que la página sea "atacada" con datos inesperados que sí pueden afectar a su funcionamiento. Este tipo de ataques se denominan en general ataques de inyección y pueden ser de muy diversa naturaleza, según cuál sea el objetivo del ataque.
Por ello, una página que reciba datos de un formulario debe protegerse ante este tipo de ataques. Por ejemplo, debe funcionar correctamente aunque no le lleguen los datos esperados o aunque los datos no tengan el formato esperado.
Para realizar un ataque de inyección, basta con editar la URL y modificar los datos, borrando, modificando o añadiendo nuevos datos, respetando la notación ?clave1=valor1&clave2=valor2 .... Puede abrir el ejemplo siguiente en una nueva pestaña y modificar la URL como se muestra en las capturas siguientes.
Si el programa PHP trabaja con $_REQUEST o $_GET, el ataque de inyección se puede realizar manipulando la URL. Si el programa PHP trabaja con $_POST, el ataque de inyección se tendría que realizar con alguna herramienta que generara las cabeceras HTTP.
Los programas que recogen datos de formularios necesitan protegerse de los ataques de inyección. En estos apuntes, se recomienda:
Las soluciones de los ejercicios propuestos siguen las recomendaciones de estas lecciones.