Formularios

La gestión de formularios es una de las mejores características de PHP. La combinación de HTML para construir formularios, PHP para gestionar datos y MySQL para almacenarlos son una de las tareas mas eficientes.

<form method=POST [action=resp.php] accept-charset='UTF-8'>
...
</form>

El flujo básico consiste en capturar la información que el usuario ingresa en los elementos del formulario y enviarla al servidor cuando se ejecuta el evento de envío (submit).

Puede crear el formulario en HTML y la gestión de datos en un script PHP separado asociado con ACTION.

1 Method

PHP gestiona los datos entrantes mediante arrays superglobales predefinidos.

1.1 Method=GET

El método GET pasa argumentos de una pagina a la siguiente como parte de la URL, en formato de pares tipo nombre=valor separando el primero con ? y los siguientes con &. Ej: ?user=juan&cat=5

<Form Method=GET accept-charset='UTF-8'>
<input type=text name=nombre>
</Form>
<?PHP
$variable = $_GET['nombre'];
$variable = $_REQUEST['nombre'];
?>

Cuidado cuando se usa GET, los datos del formulario enviado serán visibles con la URL de la página

1.2 Method=POST

Es el método preferido de envío de formularios porque los pares de valores no son visibles. Los datos viajan ocultos en el cuerpo de la petición HTTP, no aparecen en la URL.

<Form Method=POST accept-charset='UTF-8'>
<input type=text name=nombre>
</Form>
<?PHP
$variable = $_POST['nombre'];
$variable = $_REQUEST['nombre'];
?>

2 Action

Define la URL o script .php que recibirá y procesará los datos. Si se deja vacío o no poner action, el formulario se enviará a la misma página.

<form method=GET|POST [action=script.php] [ accept-charset='UTF-8']></form>
<Form Method=GET accept-charset='UTF-8'>
<input type=text name=nombre>
</Form>
<?PHP
$variable = $_GET['nombre'];
$variable = $_REQUEST['nombre'];
?>

Puede recuperar los datos enviado mediante los métodos: GET o POST con $_REQUEST[]

<Form Method=POST accept-charset='UTF-8'>
<input type=text name=nombre>
</Form>
<?PHP
$variable = $_POST['nombre'];
$variable = $_REQUEST['nombre'];
?>

Antes de procesar la información, es indispensable comprobar que los campos existan y no contengan valores maliciosos.

//Texto
if (isset($_REQUEST['txt']) and !empty(trim($_REQUEST['txt']))) {
   $txt = $_REQUEST['txt'];
}
//Numero
if (isset($_REQUEST['num']) and is_numeric($_REQUEST['num'])) {
   $num = round((float) $_REQUEST['num'],2); ;
}

2.1 Autoenvio

Se llama asi cuando el mismo script contiene el formulario y su gestión de datos.

1. logica PHP
2. formulario

Recuerde que la lógica debera estar siempre antes que la visualización. Es recomendable usar el botón <input type=SUBMIT> como variable de nivel.

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
   // Procesar los datos del formulario de forma segura
   $user = $_REQUEST['user'] ?? '';
   echo 'Formulario enviado.';
} else {
   // Mostrar el formulario limpio por primera vez (petición GET)
   echo 'Por favor, completa el formulario.';
}
<?PHP
if (isset($_REQUEST['sem']) and !empty(trim($_REQUEST['sem']))){
   $sem = $_REQUEST['sem'];
}else{
   $sem = date('YW');
}
echo '<Form>';
echo "<input type=text name=sem value=$sem maxlength=6> Ej 202607";
echo '</Form>';
?>
<?PHP
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // 1. Verificación de existencia
    if (isset($_POST['user']) && !empty(trim($_POST['user']))) {
        // 2. Sanitización (limpieza contra XSS)
        $user = htmlspecialchars(trim($_POST['user']), ENT_QUOTES, 'UTF-8');
        // 3. Validación de formato (ejemplo para email)
        if (isset($_POST['email'])) {
            $email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
            if (!$email) {
                echo 'El correo ingresado no es válido.<p>';
            }
        }
        echo 'Hola, '. $user .'<p>';
    } else {
        echo 'El campo de usuario es obligatorio.<p>';
    }
}
echo '<form method=POST>';
echo 'Nombre: <input type=text name=user><p>';
echo 'Correo: <input type=email name=email><p>';
echo '<input type=submit value=Enviar>';
echo '</form>';
?>

2.2 Autoseleccion de un SELECT

Muchas veces recuperamos las opciones de un registro y luego tenemos que seleccionar (SELECTED) la opción adecuada. Una solucion es ir preguntando si se leigio esa opcion miestras construimos el formulario asi:

<select name=cat id=cat>
   <option value=H5
      <?PHP if ($cat == 'H5'){echo ´ SELECTED´};?>
   >Hotel 5
	<option value=H4
      <?PHP if ($cat == 'H4'){echo ´ SELECTED´};?>
   >Hotel 4
	<option value=H3
      <?PHP if ($cat == 'H3'){echo ´ SELECTED´};?>
   >Hotel 3
	<option value=H2
      <?PHP if ($cat == 'H2'){echo ´ SELECTED´};?>
   >Hotel 2
	<option value=H1
      <?PHP if ($cat == 'H1'){echo ´ SELECTED´};?>
   >Hotel 1
	<option value=NC
      <?PHP if ($cat == 'NC'){echo ´ SELECTED´};?>
   >No clasificado
</select>

Pero una solución mucho mas eficiente es usar jQuery asi:

<select name=cat id=cat>
   <option value=H5>Hotel 5
	<option value=H4>Hotel 4
	<option value=H3>Hotel 3
	<option value=H2>Hotel 2
	<option value=H1>Hotel 1
	<option value=NC>No clasificado
</select>
<!-- Selecciono la opción adecuada del select -->
<Script>$('#cat option[value=<?PHP echo $cat; ?>]').attr('selected',true);</Script>

3 accept-charset

Este especifica las codificaciones de caracteres que se usarán para el envío del formulario. Lo valores comunes con URF-8 o ISO-8859-1.

<Form Method=POST accept-charset='character-set'>

4 Elementos de formulario

Elementos de formulario
ElementoDescripción
InputCon Type se determina su formato: submit, text, checkbox, radio, password, hidden, URL, number, range, file, image, datetime, color, etc. Recuerdo siempre determinar Name.
LabelDefine una etiqueta para los botones type=input.
ButtonCon Type se determina el formato: button, submit, etc
SelectDefine una lista desplegable.
TextareaUse optiman para determinar las opciones. SELECTED para el seleccionado.
KeygenPara facilitar la generación de claves de certificados.

Nunca use datos sin filtrar en una consulta a BD. Siempre use NAME para cada elemento, al enviar se convertiran en variables. Use VALUE para establecer valores predeterminados.

4.1 Input

Elemento para ingresar datos en un formulario.

Elementos input
TypeDescripción
text,email,passwordCampos de entra de texto corto
number,week,monnth
CheckboxSelector multiple
RadioSelector unico
fileSubida de archivo (requiere enctype='multipart/form-data').
SubmitBotón que dispara el envío del formulario.

Para limitar al usuario de introducir solo digitos use type=number o type=range.

<input type=number name=num value=50.0 min=0 max=100 step=0.1>

Los elementos tipo checkbox y radio son especiales al enviar formulario porque solo se envian si estan marcados.

4.2 Label

Para asociar una etiqueta a un elemento.

<label for=val1>Nombre:</label><br>
<input type=text name=nom id=val1><
<form>
   <label for=nom>Nombre:</label><br>
   <input type=text name=nom id=nom><br>
   <label for=ape>Apellido:</label><br>
   <input type=text name=ape id=ape>
</form>

4.3 Button

Botón que no tiene ninguna funcionalidad.

<button>Mensaje</button>
<button onClick='alert("Hola mundo")'>Envia mensaje</button>

Si lo añadimos dentro de un formulario mágicamente asumirá el rol de botón para enviar formulario (submit).

4.4 Select

Menú desplegable de opciones

<Select name=filter title='Selecciona una moneda' required>
	<option value='' disabled selected hidden>--- elige una moneda ---
	<option value=S>Soles
	<option value=D>Dolares
	<option value=E>Euros
</Select>

Para que un select sea required tienes que poner el primer valor en vacio.

4.5 Datalist

Opciones acotadas sin menú desplegable.

<input list=navegadores name=nav>
   <datalist id=navegadores>
      <option value=Edge>
      <option value=Firefox>
      <option value=Chrome>
      <option value=Opera>
      <option value=Safari>
   </datalist>

4.6 Textarea

Entrada de texto de múltiples líneas.

<textarea name=txt [rows=x] [cols=y] [maxlenght=n] [wrap]></textarea>

5 Buenas praticas de seguridad

En PHP, $_SERVER['REQUEST_METHOD'] es una variable superglobal que devuelve el método de petición HTTP usado para acceder a la página actual. Se usa principalmente para detectar cómo interactuó el usuario con tu script (por ejemplo, cargando la página normalmente o enviando un formulario). Posibles respuestas: GET, POST, PUT, PATCH o DELETE.

Siempre en mayúsculas
El texto devuelto siempre estará en mayúsculas (ej. 'POST', no 'post').
Línea de comandos (CLI)
Si ejecutas tu script PHP desde la terminal en lugar de un servidor web, esta variable estará vacía o no existirá.
Seguridad
Nunca confíes únicamente en el método de petición para la seguridad. Siempre debes validar y desinfectar los datos recibidos en $_GET o $_POST o $_REQUEST.
$metodo = $_SERVER['REQUEST_METHOD'];
switch ($metodo) {
   case 'GET':
      // Obtener y mostrar datos
      break;
   case 'POST':
      // Crear un nuevo registro
      break;
   case 'PUT':
      // Reemplaza el registro completo (mas pesado)
      break;
   case 'PATCH':
      // Actualizar parcialmente un registro existente (mas ligero)
      break;
   case 'DELETE':
      // Eliminar un registro
      break;
   default:
      // Método no permitido
      http_response_code(405);
}

Evitar XSS (Cross-Site Scripting)
Aplica htmlspecialchars() siempre que vayas a imprimir en pantalla datos provenientes del usuario.
Validación y Sanitización
Usa las funciones nativas filter_input() y filter_var().
Protección CSRF
Incluye tokens aleatorios en la sesión para validar que las peticiones provengan del mismo sitio web.
Subida de Archivos
Valida la extensión, el tipo MIME y el tamaño del archivo almacenado en $_FILES, renombrándolo antes de moverlo al servidor mediante move_uploaded_file().
Protección XSS en el atributo action
Se aplica htmlspecialchars($_SERVER['PHP_SELF']) al action para prevenir inyecciones de código malicioso a través de la URL.
Desactivación temporal de HTML5
El atributo novalidate en la etiqueta <form> desactiva la validación nativa del navegador para permitir comprobar el funcionamiento del backend en PHP.
Evita la duplicación de datos
En los <input value=$val> hace que el formulario mantenga el texto escrito por el usuario en caso de que ocurra un error en otro campo.
Manejo asociativo de errores
La estructura del array $errores['campo'] permite colocar dinámicamente los mensajes directamente debajo del input correspondiente.

<html>
<Body>
<?php 
if ($exito){
   echo '<div class=alerta-exito>';
   echo 'Mensaje enviado correctamente. Nos pondremos en contacto pronto.</div>';
}
?>
<!-- novalidate evita que el navegador intercepte la validación para probar PHP -->
<form action="<?= htmlspecialchars($_SERVER['PHP_SELF']); ?>" method=POST novalidate>
   <div class=campo>
      <label for=nombre>Nombre:</label>
      <input type=text id=nombre name=nombre value='<?= $nombre; ?>'>
      <?php if (isset($errores['nombre'])): ?>
      <span class=error-msg><?= $errores['nombre']; ?></span>
      <?php endif; ??>
   </div>
   <div class=campo>
      <label for=email>Correo Electrónico:</label>
      <input type=email id=email name=email value='<?= $email; ??>'?>
      <?php if (isset($errores['email'])): ??>
      <span class=error-msg><?= $errores['email']; ??>?</span?>
      <?php endif; ??>
   </div>
   <div class=campo>
       <label for=mensaje>Mensaje:</label>
       <textarea name=mensaje id=mensaje rows=4><?= $mensaje; ?></textarea>
       <?php if (isset($errores['mensaje'])): ??>
       <span class=error-msg><?= $errores[mensaje]; ??></span?>
       <?php endif;?>
   </div>
   <button type=submit>Enviar</button>
</form>
</body>
</html>

6 Algunas funciones de seguridad

Alunas funciones utiles de PHP y MySQL para seguridad.

Elementos input
FuncionDescripción
trim()Borra los espacios en blanco invisibles que el usuario pudo haber dejado sin querer al inicio o al final del correo.
htmlspecialchars()Evita ataques de XSS (Cross-Site Scripting). Si un atacante escribe código malicioso en un formulario (como <script>alert('hacked')</script>), esta función lo transforma en texto inofensivo para que no se ejecute en tu base de datos o pantalla. Te protege contra JavaScript.
$mysqli-%gt;escape_string()Proyege contra Inyección SQL. Escapa caracteres especiales (como las comillas ' o ") para que el motor de la base de datos los interprete como simple texto y no como código SQL malicioso.
$mysqli-%gt;prepare()
bind_param()

Si guardas datos usando htmlspecialchars() en la base de datos: Estás alterando los datos originales de forma innecesaria (un nombre con comillas se guardará deformado con códigos como "). Además, no te protege adecuadamente de ciertos tipos de inyección SQL.

$nom = trim($_REQUEST['nom'] ?? '');
// Al momento de mostrarlo en el HTML, usas htmlspecialchars()
echo 'Hola, '. htmlspecialchars($nom, ENT_QUOTES, 'UTF-8');

Si muestras datos en HTML usando $mysqli-%gt;escape_string: No te servirá de nada. El código <script> se ejecutará en el navegador del usuario y tu web será hackeada.

$nom = trim($_REQUEST['nom'] ?? '');
// Preparar la consulta (Inmune a Inyección SQL)
$sql = $mysqli-?>prepare('INSERT INTO usuarios (nom) VALUES (?)');
$sql-?>bind_param('s',$nom);          // El driver se encarga de la seguridad automáticamente
$sql-?>execute();

7 Validar datos

Antes de ingresar los datos en una BD es necesario validar el tipo de datos y su existencia.

Funciones para validar datos
FuncionDescripcion
ctype_alnumChequear posibles caracteres alfanuméricos
ctype_alphaChequear posibles caracteres alfabéticos
ctype_spaceChequear posibles caracteres de espacio en blanco
ctype_upperChequear posibles caracteres en mayúscula
ctype_lowerChequear posibles caracteres en minúscula
ctype_graphChequear posibles caracteres imprimibles, con excepción de los espacios
ctype_printChequear posibles caracteres imprimibles
ctype_punctChequear posibles caracteres imprimibles que no son ni espacios en blanco ni caracteres alfanuméricos.
ctype_cntrlChequear posibles caracteres de control
ctype_digitChequear posibles caracteres numéricos
ctype_xdigitChequear posibles caracteres que representen un dígito hexadecimal
//Cadenas
if (isset($_REQUEST['txt']) and is_string($_REQUEST['txt'])){
   $txt = trim($_REQUEST['txt']);
}
//Numeros
if (isset($_REQUEST['num']) and is_numeric($_REQUEST['num'])){
   $num = (int) $_REQUEST['num'];
}
Funciones para validar datos
FuncionDescripcion
is_stringDetermina si una variable es de tipo cadena (string)
is_numericDetermina si una variable es una cadena numérica
is_intDetermina si una variable es de tipo integer
is_integerAlias de is_int
is_longAlias de is_int
is_floatDetermina si una variable es de tipo float
is_doubleAlias de is_float
is_realAlias de is_float
is_countableVerifica si el contenido de la variable es un valor contable
is_nullIndica si una variable es null
is_objectDetermina si una variable es de tipo objeto
is_arrayDetermina si una variable es un array
is_boolDetermina si una variable es un bool
is_callableDetermina si un valor puede ser llamado como una función en el ámbito actual
is_iterableDetermina si el contenido de la variable es iterable.
is_resourceDetermina si una variable es un recurso
is_scalarIndica si una variable es un escalar