Llevando datos de las páginas en PHP a la base en MySQL

Llevando datos de las páginas en PHP a la base en MySQL
COMPÁRTELO:

Cómo escribir datos en una base desde PHP

Ya hemos realizado páginas que leen datos de nuestra base de datos pero, muchas veces, necesitamos transitar en camino inverso, es decir, que nuestras páginas PHP agreguen datos a una base.

Serán, básicamente, dos los tipos de usuario que necesitarán agregar registros a una tabla mediante formularios HTML/PHP:

  1. Los administradores del contenido de un sitio Web, cuando ingresen a alguna página privada (protegida con usuario y clave, parte del panel de administración o back-end del sitio), para –por ejemplo- agregar productos a un catálogo, noticias a un portal y tareas similares. El objetivo de que los administradores agreguen esa información, es que luego sea visualizada por los visitantes que entren al sitio, es decir, que la naveguen utilizando páginas dinámicas como las que aprendimos a crear en el tema anterior, cuyo contenido estaba almacenado en la base de datos.
  2. Los usuarios de nuestro sitio también podrán agregar en ciertas circunstancias datos a nuestra base, cuando envíen un comentario de una noticia, un mensaje en un foro, completen sus datos en un formulario de registro, es decir, utilicen paginas HTML para escribir algo y enviarlo hacia el servidor desde el front-end (las paginas "publicas" de nuestro sitio).
back-end y front-end

Figura. El administrador interactúa con el black-end, y el usuario, con el front-end.

Sea quien fuere el tipo de usuario que agregara datos a nuestra base, lo hará utilizando una misma técnica: un formulario HTML para escribir los datos del lado del cliente (navegador) y, la pagina del destino de ese formulario, un código PHP que, al estar ubicado del lado del servidor, podrá insertar los datos en la base y luego devolver algunas respuestas al navegador.

Entonces estamos hablando de un proceso que tiene dos etapas o "momentos":

  • El momento inicial donde el usuario completa el formulario, del lado del cliente;
  • Y el segundo, cuando una página PHP recibe en el servidor las variables que el usuario completó y las utiliza para ejecutar una consulta SQL que inserta los datos de la base.

Típicamente, este proceso se dividirá en dos páginas distintas: un archivo HTML para los formularios y una página PHP para el código que se ejecutara en el servidor, insertará el dato en la base y mostrará un mensaje de éxito o error.

Formulario envia datos para insertar registros en la base

Figura. Dos páginas: un formulario envía datos y, otra, los recibe y los inserta en la base.

En la segunda página (agregar.php), para insertar los registros en la base, los pasos necesarios serán:

  1. Que el programa intérprete de PHP se identifique ante el programa gestor de MySQL y seleccione una base (ya hemos creado una función que hacia esto en el tema anterior, así que podremos utilizarla).
  2. Preparemos una variable la orden del lenguaje SQL necesaria para insertar datos en la base.
  3. Ejecutaremos esa orden SQL (no será necesario crear una función especifica para insertar datos, ya que esta consulta no trae datos, sino que la envía hacia la base, por lo cual no es necesario generar ni correr luego ningún "paquete de datos"). Ejecutaremos la orden con mysql_query directamente, será fundamental evaluar si devolvió verdadero o no la ejecución de esa consulta y, en función de ello, mostraremos un mensaje de éxito (si el dato fue insertado) o de error.

Pasemos a la acción:

Creando el formulario

Como primera medida, crearemos un formulario que nos dejará escribir los datos que queremos agregar a la tabla de "mensajes".

Este formulario tendrá dos campos de texto, para el nombre y el email, respectivamente, y un área de texto para el mensaje (el id no lo insertará el usuario, ya que es un campo auto-increment)

A este formulario lo llamaremos formulario.html, y su código podría ser algo así:

<form method="post" action="agregar.php">
<fieldset>
<legend> Ingrese su consulta</legend>
<p>
<label> Escriba su nombre:
<input type="text" name="nombre" />
</label>
</p>
<p>
<label>Escriba su correo electrónico:
<input type="text" name="email" />
</label>
</p>
<p>
<label>Escriba su mensaje:
<textarea name="mensaje" cols="30" rows="5"></textarea>
</label>
</p>
<p>
<input type="submit" value="enviar"/>
</p>
</fieldset>
</form>

Además de presentar atención a los name (ya que serán los nombres de las variables que podremos leer en la siguiente página desde una celda de la matriz $_POST).

Lo más importante aquí es que el atributo action del formulario está apuntando hacia una segunda pagina llamada agregar.php; que será la que codificaremos a continuación.

Conexión a MySQL

En la segunda página (es decir, aquella página hacia la cual apuntaba al action del formulario anterior y que decidimos denominar agregar.php), luego de validar si se recibieron las variables, el intérprete de PHP intentará conectarse al programa MySQL, y tratará de seleccionar una base.

Para estas tareas, ya habíamos creado una función en el artículo anterior, asi que vamos a reutilizarlas:

<?php
// Incluimos los datos de conexión y las funciones:
include("datos.php");
include("funciones.php");

// Usamos esas variables:
if (conectarBase($host,$usuario,$clave,$base)) {

// Aquí irá el resto

} else {
echo"<p>Servicio interrumpido</p>";

}
?>

Por supuesto, recordemos colocar los archivos datos.php y funciones.php en la misma carpeta en la que estamos trabajando para que esto pueda funcionar.

Ahora, pasemos al segundo paso.

La orden INSERT del lenguaje SQL

Una vez autenticados ante MySQL y seleccionada la base, prepararemos, dentro de una variable, la consulta del lenguaje SQL que se utiliza para insertar datos en una tabla de la base: la orden INSERT.

La sintaxis básica de la orden INSERTes la siguiente:

INSERT INTO tabla (campo1, campo2, campo3) VALUES ('valor1', 'valor2', 'valor3');

Esto podría traducirse como "Insertar en una tabla indicada, en los campos enumerados,los valores siguientes".

Veamos un ejemplo para entenderlo mejor:

INSERT INTO mensajes (id, nombre, email, mensaje) VALUES ('0', 'Delgado', 'adrian.delgado@cuc.udg.mx', 'Bla, Bla, bla')

Observemos que los valores (enumerados entre paréntesis luego de la palabra VALUES) siempre van envueltos entre comillas simples, y existe una corrección de orden, ya que se insertará, el primer campo de la lista (el campo id, en este caso), el primero de los value (el 0); en el segundo (nombre), el segundo value (Delgado), y así sucesivamente.

Notemos también que hemos proporcionado un cero como valor para el campo id, ya que será generado automáticamente (lo hemos definido como auto-increment).

De esta manera nos despreocupamos y, para todos los registros que vayamos a insertar, siempre proporcionaremos un cero como valor del id, y será MySQL quien se ocupe de asignarle el valor correspondiente (por supuesto, todo esto gracias a que hemos definido al campo id como auto-increment).

Recordemos que podemos ejecutar consultas SQL desde el phpMyAdmin, pulsando en la solapa SQL, escribiendo ordenes en lenguaje SQL dentro de la área de texto, y luego pulsaremos continuar para ver el resultado de la ejecución. Es recomendable que probemos varias veces esta orden INSERT para familiarizarnos con ella.

A esta orden INSERT del lenguaje SQL, la dejaremos escrita dentro de una variable, para que la podamos pasar como parámetro a una función que se encargue de ejecutarla.

Pero no vamos a escribir allí los datos "a mano", como en el ejemplo anterior, sino que deberemos modificar esta orden para que realmente reciba los datos enviados desde el formulario de la primera página, por lo cual quedará algo como lo que sigue:

<?php
//Validamos que hayan llegado estas variables, y que no esten vacias:
if (isset($_POST["nombre"], $_POST["email"], $_POST["mensaje"]) and $_POST["nombre"] !="" and $_POST["email"]!="" and $_POST["mensaje"]!="" ){

//traspasamos a variables locales, para evitar complicaciones con las comillas:
$nombre = $_POST["nombre"];
$email = $_POST["email"];
$mensaje = $_POST["mensaje"];

//Preparamos la orden SQL
$consulta = "INSERT INTO mensajes
(id,nombre,email,mensaje) VALUES ('0','$nombre','$email','$mensaje')";

//Aqui ejecutaremos esa orden

} else {

echo '<p>Por favor, complete el <a href="formulario.html">formulario</a></p>';
}
?>

Lo más importante aquí es que verifiquemos la presencia de las variables, y las dejemos preparadas, listas para usar dentro de $consulta.

Es muy útil, llegados a este punto previo a la ejecución de la consulta, que probemos qué contiene la variable $consulta haciendo un echo de ella.

Podemos completar algunos datos de prueba en el formulario, enviarlo, y ver que muestra el echo; a eso que muestre, podemos copiarlo y pegarlo dentro de la ventana SQL del phpMyAdmin para, de esta manera confirmar si la sintaxis de la orden fue la correcta.

Recordemos que es necesario que incluyamos este bloque de código dentro del bloque anterior que realizaba la conexión a la base, en la parte exacta en la que habíamos dejado preparado un comentario que decir: "//Aquí ira el resto"

Ejecutar la consulta

Ahora que hemos verificado que la sintaxis de la consulta es la correcta, ya podemos hacer que PHP la ejecute realmente, mediante la utilización de la función mysql_query, y, de la misma manera que en el tema anterior, ubicaremos esta consulta dentro de un condicional para comprobar si verdaderamente se insertó el registro.

Observemos que el siguiente código debe ser intercalado en el punto de código anterior en el que dejamos un comentario que decía: "//Aquí ejecutaremos esa orden".

if (mysql_query($consulta) ){
echo "<p>Registro agregado.</p>";
} else {
echo "<p>No se agregó...</p>";
}

Si luego de ejecutado esto, entramos al phpMyadmin, pulsamos en la columna izquierda sobre el nombre de la base de datos cursos y luego pulsamos el nombre de la tabla mensajes, ahora podremos hacer clic en Examinar y veremos el nuevo registro que se ha agregado a nuestra tabla.

Sin embargo, si por casualidad escribimos en el texto de alguno de los campos un acento o eñe, notaremos que se visualiza con una codificación incorrecta.

Siempre que enviemos una consulta que lleva datos hacia un base de datos, debemos especificar el juego de caracteres, que será UTF-8, en nuestro caso, para no tener problemas con los caracteres especiales (acentos, añes).

Esto lo aremos mediante la orden SET NAMES.

En este caso, la aplicaremos luego de establecida la conexión y seleccionada la base (inmediatamente después del condicional que evalúa la función conectarBase), de esta forma:

@mysql_query("SET NAMES 'utf8'");

Con esto, el proceso completo de agregar registros a una tabla desde un formulario ya funciona pero, antes de usarlo en nuestros sitios, analizaremos un típico problema de seguridad (y veremos cómo solucionarlo) de este proceso de agregar a la base información que fue ingresada por algún usuario.

Filtrar los datos de formularios: enviando inyección SQL

Un punto fundamental cuando vamos a enviar datos escritos por el usuario dentro de una consulta SQL, es "limpiarlos" antes de usarlos en una consulta que los envié hacia MySQL, ya que algún usuario con malas intenciones puede enviar datos dañinos para nuestra base de datos o, simplemente, lograr el acceso a zonas de nuestro sitio que no son públicas, utilizando una técnica muy popular, que analizaremos a continuación para poder prevenirla.

A esta técnica se le conoce como SQL injection (inyección SQL), y consiste en utilizar un campo de un formulario para "complementar" una consulta SQL (SELECT,INSERT,DELETE o UPDATE).

Por supuesto, los atacantes conocen el lenguaje SQL muy bien.

Veamos un ejemplo de esta técnica en funcionamiento, para que podamos comprobar el riesgo real de no "limpiar" los datos escritos por los usuarios.

Vamos a crear una tabla llamada "usuarios", que tendrá solo tres campos id (TINYINT), usuario y clave (ambos VARCHAR). Cargaremos un solo registro, un supuesto usuario "pepe" con la clave "clave".

Una vez creada esta sencilla tabla e insertado ese registro de prueba, crearemos un archivo "formulario.html" en el que se pueda ingresar un usuario y clave para acceder a un supuesto contenido secreto:

<form method="post" action="secreto.php">
<fieldset>
<legend> Ingrese sus datos</legend>
<p>
<label>Escriba su usuario:
<input type="text" name="usuario"/>
</label>
</p>
<p>
<label>Escriba su contraseña:
<input type="text" name="clave" />
</label>
</p>
<p>
<input type="submit" value="Enviar"/>
</p>
</fieldset>
</from>

En la segunda página (secreto.php), incluiremos, como siempre, los archivos de conexión y de funciones, y ejecutaremos una consulta SELECT para ver si el usuario y la clave ingresados por el usuario existen en nuestra tabla de usuarios: si no existen, no les dejaremos ver el contenido "secreto" de nuestra página.

Veamos cómo sería el código de secreto.php (hemos retomado el ejemplo del artículo "Llevando datos de la base en MySQL a las páginas en PHP", por lo que es imprescindible que coloquemos todos los archivos necesarios en la misma carpeta, como conexión.php y funciones.php):

<?php
// Incluimos los datos de conexión y las funciones:
include("conexion.php");
include("funciones.php");

//Validamos que hayan enviado un usuario y una clave, y que no esten vacios
if (isset ($_POST["usuario"],$_POST["clave"]) and $_POST["usuario"]<>"" and $_POST["clave"]<>"") {

// Traspasamos a variables locales:
$usuario = $_POST["usuario"];
$password = $_POST["clave"];

// Nos conectamos:
if( conectarBase($host,$usuario,$clave,$base) ){
$consulta ="SELECT * FROM usuarios WHERE usuario='$usuario' AND clave='$password'";

if( $paquete =consultar ($consulta) ){
echo "<p>Bienvenido al contenido secreto</p>";
}

else {
echo "<p> No tiene derecho a accedera nuestro contenido secreto</p>";
}
} else {
echo "<p> Servicio interrumpido</p>";
}
} else {
echo '<p>No ha completado el formulario.</p>';
}
echo '<p>Regresar al <a href="formulario.html">formulario</a></p>';
?>

Si probamos lo expresado en el cuadro anterior escribiendo un usuario y clave que no coincidan con "pepe" y "clave", no obtendremos acceso al contenido secreto, pero si obtendremos acceso si escribimos "pepe" y "clave". Hasta aquí, todo aparenta funcionar a la perfección...

Pero observemos qué intentará hacer que quiera ingresar a nuestro contenido secreto. Estando frente al formulario, escribirá esto:

Inyección de código SQL

Figura. Inyección de código SQL

Notemos que el contenido de ese campo será:

' OR ' ' = '

Lo cual llega a ser significativo si reemplazamos los valores de las variables por lo ingresado por el usuario, y lo colocamos dentro de la orden SQL que será ejecutada a continuación:

$consulta ="SELECT" * FROM usuarios WHERE usuario= 'cualquiera' AND clave=' ' OR ' '=' ' ";

Notemos que se modifica radicalmente la consulta; ya no importa que haya sido ingresado en el campo usuario (puede ser cualquier cosa), ni importa que se haya dejado vacía la clave, ya que con su primera comilla simple, ha cerrado la camilla que quedaba abierta para la clave, pero luego ha agregado: OR ''='' que es una afirmación verdadera, también podría haber puesto: OR 1=1, o cualquier otra tautología que provoque que la expresión completa sea evaluada como verdadera.

El punto de que sea evaluada como verdadera, es que recordemos… está siendo ejecutada dentro de la condicional, que es la única manera de saber si "existían" ese usuario y esa clave en la tabla de usuarios.

Conclusión: este condicional dará siempre verdadero para ese usuario, que podrá entrar libremente a nuestra zona "secreta", simplemente inyectando el mencionado código en nuestro formulario de acceso.

¿Cómo podemos evitarlo? Muy fácilmente: contamos con una función denominada mysql_real_escape_string que nos permite sanear los datos ingresados por el usuario, es decir, cambiar su valor por otro que resulte inofensivo para las consultas SQL que se enviaran hacia la base de datos.

Sólo debemos aplicarla a las variables recibidas, y desaparece el riesgo de inyección SQL:

$usuario = mysql_real_escape_string ($_POST["usuario"]);
$password = mysql_real_escape_string ($_POST["clave"]);

Si por curiosidad completamos nuevamente el formulario con 'OR''=' y luego hacemos un echo de $password para ver que contiene, veremos que las comillas fueron desactivadas ("escapadas" con una barra invertida delante):

\' OR' \'\'=\'

Esta operación lo vuelve completamente inofensivo debido a que ya no respeta las sintaxis del lenguaje SQL y, por lo tanto, el usuario que intentó esta inyección SQL ya no podrá acceder a nuestro contenido secreto.

Ahora que ya podemos insertar datos en la base desde nuestras páginas PHP con total seguridad, aprenderemos a eliminar un registro de la base mediante formularios (tarea típica de un panel de administración o back-end, desde el cual, por ejemplo, podríamos eliminar un mensaje publicado en un foro que sea ofensivo o que realice SPAM, eliminar un producto agotado, que ya no esté en venta en un catálogo, etc.).

Cómo eliminar datos de un base con PHP

A continuación, veremos los pasos de la operación que elimina un registro entero de nuestra tabla desde una página Web.

Retomemos el ejemplo del artículo anterior (recordemos ubicar los archivos conexión.php y funciones.php en la misma carpeta).

La parte que mostraba el listado de empleados era como sigue:

<?php
// Incluimos los datos de conexión y las funciones:
include("conexion.php");
include("funciones.php");

// Usamos esas variables:
if(conectarBase($host,$usuario,$clave,$base)){
$consulta = "SELECT * FROM empleados";
if ( $paquete = consultar ($consulta)){

// Llamamos a una función que muestre esos datos
$codigoTabla = tabular($paquete);
echo $codigoTabla;
} else {
echo "<p>No se encuentraron datos</p>";
}
} else {
echo "<p>Servicio interrumpido</p>";
}
?>

La parte clave del bucle de nuestra función llamada tabular, donde se armaba el código HTML de cada renglón o tr del listado, era la siguiente:

while ( $fila = @mysql_fetch_array($datos)){
$codigo .= '<tr>';

//vamos acumulando tantos "td"como sea necesario:
$codigo .= '<td>' .utf8_encode($fila["id"]).'</td>';
$codigo .= '<td>' .utf8_encode($fila["nombre"]).'</td>';
$codigo .= '<td>' .utf8_encode($fila["apellido"]).'</td>';
$codigo .= '<td>' .utf8_encode($fila["edad"]).'</td>';
$codigo .= '<td>' .utf8_encode($fila["pais"]).'</td>';
$codigo .= '<td>' .utf8_encode($fila["especialidad"]).'</td>';

// Cerramos un "tr":
$codigo .='</tr>';
}

Esto producía el siguiente resultado:

Listado original

Figura. Listado original.

Para agregar a este listado tanto la operación de borrar como la de modificar un registro, agreguemos un par de nuevas columnas td a cada fila, para que incluyan cada una un enlace que muestre las palabras BORRAR y MODIFICAR, resspectivamente.

Para ello, agreguemos al bucle anterior dos nuevos td al final de los demás, de esta manera:

$codigo .= '<td>BORRAR</td>';
$codigo .= '<td>MODIFICAR</td>';

Este agregado, por el momento, se verá así:

Listado con palabras agregadas

Figura. Listado con palabras agregadas

Por ahora necesitamos que, al pulsar una de estas palabras, cada una de ellas "envié" hacia el servidor en un enlace (que aun no hemos hecho) una variable con el código del registro que deseamos borrar o modificar.

Esta es la forma para que la página de destino sepa "a cuál registro" se está queriendo eliminar o modificar.

Comencemos convirtiendo la palabra BORRAR en un simple enlace HTML, que apunte hacia una página que denominaremos borrar.php:

$codigo .='<td><a href="borrar.php">BORRAR</a></td>';

Al implementar este cambio, el listado se verá así:

Enlace con enlace borrar

Figura. Listado con enlace en BORRAR.

Ahora viene lo más difícil; necesitamos que cada uno de esos enlaces, al ser generado dentro del bucle, obtenga de $fila["id"] el código del registro que se está armando en ese momento, y lo deje dentro del enlace, en una variable que se enviará por el método get hacia la siguiente página:

$codigo .= '<td><a htref="borrar.php?codigo='.$fila["id"].'">
BORRAR</a></td>';

Que producirá el siguiente resultado:

Enlace con identificador

Figura. Cada enlace con su identificador

Visualmente, nada ha cambiado en los enlaces, pero si apoyamos el puntero del mouse sobre cada una de las palabras BORRAR (sin pulsarlo, sólo deslizándolo por encima de cada enlace), notaremos en la barra de estado, al pie y a la izquierda del navegador, que cada enlace además de apuntar hacia borrar.php, al ser pulsado enviará también la variable "código" con su correspondiente valor.

Notaremos que si pasamos el mouse sobre las distintas palabras BORRAR a lo largo de todos los renglones, veremos que cada renglón en valor de la variable "código" es diferente, ya que se corresponde con el valor de $fila["id"] de cada registro.

De esta manera, la página de destino podría saber cuál es el registro que se desea eliminar, con total certeza.

Ahora, sólo nos resta el final: crear la página borrar.php hacia la que apuntan todos esos enlaces, que es la pagina que realmente borrará el registro cuyo id coincida con el indicado en la variable "código".

La orden DELETE del lenguaje SQL

Dentro de la página borrar.php, deberíamos estar recibiendo desde el listado anterior la variable "código", que contiene el id de alguno de los registros, el que se desea borrar.

Por supuesto, deberemos validar si ha llegado al servidor y si no está vacía.

Esto podría hacer de la siguiente manera:

<?php
if(isset($_GET["codigo"]) and $_GET["codigo"]<>""){
// Aquí ira el resto de las instrucciones
} else {
echo '<p>No especificó que desea borrar, por favor regrese al <a href="listado.php">listado</a></p>';
}
?>

Si está presente la variable "código", procedemos a eliminar el registro que posea el id que tiene especificado y, para ello, deberemos seguir los siguientes pasos:

  1. Que el programa interprete de PHP se identifique ente MySQL y seleccione una base (ya tenemos preparada una función que hace esto).
  2. Preparar en una variable la consulta SQL que ejecutaremos, que esta vez consistirá en la orden DELETE.
  3. Ejecutar esa orden (con mysql_query, nada novedoso para nosotros, y al igual que en la inserción, tampoco devolverá datos, por lo que será suficiente con evaluar con un condicional el resultado obtenido).
  4. Según el resultado del condicional, mostraremos un mensaje y permitiremos al usuario que regrese al listado, para seguir realizando otras tareas.

El único punto diferente a lo que ya sabemos es el segundo, así que veremos cuál es la sintaxis de la orden DELETE que nos permitirá eliminar registros de una tabla.

La estructura de esta orden del lenguaje SQL es:

DELETE FROM tabla WHERE compo='valor';

Notemos que el valor va entre comillas simples, como todos los valores que enviamos hacia MySQL, y también notemos el agregado de una condición WHERE.

Esta condición es imprescindible en el caso de una orden DELETE, ya que permite restringir la aplicación de la orden a apenas uno o varios registros que cumplan con esa condición, en caso contrario, de no especificar ninguna condición, borraríamos todos los registros de la tabla completa.

Atención:
Esta orden es la más peligrosa del lenguaje SQL: DELETE FROM tabla; al no poseer una condición WHERE, eliminara todos los registros de la tabla especificada.

Por lo tanto, siempre que hagamos un DELETE agregaremos un WHERE para limitar los registros que se eliminaran.

En este caso, deseamos eliminar solo uno, aquel registro que en el campo id posea el valor especificado en la variable "código", variable que el usuario ha enviado desde el listado al pulsar "ese" enlace, el correspondiente a "ese" registro que desea borrar.

Por lo tanto, en este ejemplo, nuestra orden SQL quedaría así armada:

DELETE FROM empleados WHERE id='$_GET["codigo"]';

Orden que colocaremos, como siempre, dentro de una variable llamada $consulta.

Pero ahora nos surge un ligero inconveniente: al envolver entre comillas dobles el contenido completo de la variable, entrarán en conflicto con las comillas dobles que envuelven a "codigo".

Tenemos dos maneras de remediarlo:

  • Envolver entre llaves el valor que se enviará a MySQL, es decir, la parte final de la orden DELETE que está envuelta entre comillas simples, en este caso: $_GET["codigo"]
  • O traspasar a una variable local (que no contiene comillas) el contenido de $_GET["codigo"].

En el primer caso (usando llaves), la variable $consulta quedaría así:

$consulta="DELETE FROM empleados WHERE id='{$_GET["codigo"]}'";

En el segundo caso (traspasando todo una variable local), quedaría de la siguiente manera:

$codigo = $_GET["codigo"];
$consulta = "DELETE FROM empleados WHERE id='$codigo'";

A continuación, ejecutaremos esta orden con mysql_query, evaluando con un condicional si devolvió true (verdadero) la orden de eliminación (es decir, si MySQL pudo eliminar el registro indicado) y, en ese caso, mostraremos el usuario un mensaje de "Registro eliminado"; caso contrario, mostraremos un mensaje de error.

Por esta razón, el código completo de la página borra.php quedaría así:

<?php
// Incluimos los datos de conexión y las funciones:
include("conexion.php");
include("funciones.php");

// Verificamos la presencia del codigo esperado:
if (isset($_GET["codigo"]) and $_GET["codigo"]<>""){

// Nos conectamos:
if (conectarBase ($host,$usuario,$clave,$base) ){

// Traspasamos a una variable local para evitar problemas con las comillas:
$codigo = $_GET["codigo"];
$consulta = "DELETE FROM empleados WHERE id='$codigo'";

if (mysql_query($consulta)){
echo "<p>Registro eliminado.</p>";
} else {
echo "<p>No se puede eliminar </p>";
}
else {
echo "<p>Servicio interrumpido</p>";
}
} else {
echo '<p>No se ha identificado cúal registro eliminar.</p>';
}
echo '<p>Regresar al <a href="listado.php">listado</a></p>';
?>

Cómo modificar datos de una base con PHP

El formulario más complicado: la actualización

Sólo nos resta la acción más compleja (o, al menos, la más larga) de todas, la de actualizar o modificar los valores de un registro.

Reemplazaremos dentro de la función denominada tabular la línea que generaba el ultimo td de la tabla, el que mostraba la palabra MODIFICAR.

Nuestro objetivo es hacer que esa palabra se convierta en un enlace, que envié un código hacia una nueva página que crearemos que se llamará modificar.php.

Esto no nos debería resultar un problema: es lo mismo que hemos hecho antes para eliminar un registro, apenas cambia el nombre del archivo de destino del enlace y la palabra que se mostrara:

$codigo .='<td><a href="modificar.php?codigo='.$fila["id"].' ">MODIFICAR</a></td>';

Que producirá el siguiente resultado:

Enlace para modificar

Figura. Enlaces para modificar.

Pero la complicación reside en que, para el usuario pueda modificar a su gusto los valores de los campos, se requiere un paso adicional con respecto a la eliminación: no alcanza con saber el id del registro a "actualizar" únicamente, ya que no sabemos qué campos de ese registro querrá actualizar el usuario, ni que nuevos valores le querrá dar.

Por lo tanto antes de actualizar, debemos mostrar todos los datos de ese registro, pero dentro de atributos value de campos de un formulario, para que aparezcan escritos sus valores actuales y, una vez que el usuario modifique libremente lo que está viendo en su pantalla, esos datos deberán ser enviados hacia otra pagina PHP, que estará esperando estos nuevos valores en el servidor, y esa es la pagina que realmente ejecutará la orden de actualizar los valores de ese registro en la base.

Así que todo proceso constará de tres páginas:

  1. El listado con enlaces (listado.php)
  2. La pagina que mostrar un formulario con los datos del registro que se modificará ya cargados, listos para que el usuario escriba, borre o reemplace lo que quiera (pagina que podemos llamar modificar.php).
  3. Y una última página, que reciba las variables de ese formulario ya modificado por el usuario, y ejecutará una consulta de actualización en la base (página que llamaremos modificado.php).
Pedido de un formulario con los datos incluidos

Figura. Pedido de un formulario con los datos incluidos, listos para editar.

Una vez modificados en su navegador, los datos se envían nuevamente al servidor.

Como de costumbre, en la página a la que se llega desde el listado, validaremos que esté llegando un código y que no esté vacio.

A continuación, haremos un SELECT, tal como los que hicimos en el tema anterior con el objetivo de traer desde la tabla solamente el registro completo que se desea modificar.

Una vez obtenidos esos datos, deberemos "escribirlos" dentro de los atributos value de los campos de un formulario HTML. Para esto, crearemos una función propia, que podamos reutilizar con ligeras variantes en otros proyectos.

Veamos como hace esta función necesaria para el archivo modificar.php, paso a paso.

Para seleccionar solamente el registro indicado, aplicaremos el mismo filtro que hemos usado recientemente en la orden DELETE: un condicional WHERE.

Envío de datos modificados

Figura. Se enviaran los datos modificados y se actualizan en la base de datos.

Esta consulta, una vez ejecutada con la función consultar que creamos con el objetivo de ejecutar ordenes SELECT (algo muy sencillo a estas alturas) nos traerá datos de una solo fila de tabla, los que deberemos asignar a un "paquete" que llamaremos típicamente $datos.

El código de esta página denominada modificar.php hasta este punto, podrá ser el siguiente:

<?php
// Incluimos los datos de conexión y las funciones:
include("conexion.php");
include("funciones.php");

// Verificamos la presencia del codigo esperado:
if (isset($_GET["codigo"]) and $_GET["codigo"]<>""){
$codigo = $_GET["codigo"];

// Nos conectamos:
if (conectarBase ($host,$usuario,$clave,$base) ){
$consulta = "SELECT * FROM empleados WHERE id='$codigo'";

if ( $paquete = consultar($consulta)){
// Aqui llamaremos a una función que muestre esos datos dentro de atributos value de un formulario
}
else {
echo "<p>No se encontraron datos</p>";
}
} else {
echo "<p>Servicio interrumpido</p>";
}
} else {
echo "<p>No se ha indicado cuál registro desea modificar.</p>";
}
echo '<p>Regresar al <a href="listado.php">listado</a></p>';
?>

Ahora, crearemos una función que llamaremos editarRegistro, cuya tarea consistirá en cargar los valores de cada campo del registro seleccionado dentro de atributos value de campos de un formulario.

Para ello, la función necesitara recibir como parámetro el paquete de datos denominado $paquete, y deberá extraerlo a una matriz (que típicamente llamaremos $fila), usando la conocida función mysql_fetch_array, tal como lo hicimos en el listado inicial, pero con una ligera variante: esta vez no será necesario un bucle, ya que la consulta sin duda traerá "un solo registro" (es importante guardar dos o más registros con el mismo id en una tabla cuyo campo id fue declarado como clave primaria).

Por lo cual, ejecutaremos lo que sigue una sola vez:

$fila = mysql_fetch_array($paquete);

Y ya tendremos cargada la matriz $fila con los datos completos de ese registro, tal como estaban guardados en la tabla.

Podríamos ir declarando las tareas básicas de esta nueva función editarRegistro:

<?php
function editarRegistro($datos){

// Extraeremos a $fila el registro:
if ($fila =mysql_fetch_array($datos)){

// Aqui acumularemos en $codigo cada dato de $fila ubicado dentro de atributos value de campo
} else {
$codigo = false;
}
return $codigo;
}
?>

Ahora viene la parte más complicada: nuestra función debe generar un formulario HTML que dentro de sus campos muestre escritos todos los datos que actualmente están dentro de la matriz $fila.

Veamos cómo hacerlo.

La forma más cómoda de creas este formulario es generar su código mediante un editor de HTML, cuidado que su atributo action apunte hacia una página (que todavía no hemos creado) que llamaremos modificado.php.

Este formulario contendrá cinco campos input de tipo text (no cuenta el campo id por que no permitiremos que sea modificado), y un botón para enviar.

En cuanto hayamos creado con nuestro editor el código HTML de este formulario, lo pegaremos dentro de nuestra función editarRegistro, inmediatamente después de haber traspasado a $fila el contenido de $datos.

Pegaremos el código del formulario dentro de la variable $codigo, cuyo valor lo delimitaremos con comillas simples (debido a las abundantes comillas dobles que deben envolver los valores de los atributos en el código HTML). Nuestra función por ahora va quedando así:

<?php
function editarRegistro($datos){

// Extraeremos a $fila el registro:
if ($fila =mysql_fetch_array($datos)){

// Aqui acumularemos en $codigo cada dato de $fila ubicado dentro de atributos value de campos
$codigo = '<form action="modificado.php" method="post">

<fieldset><legend>Puede modificar los datos de este registro:</legend>
<p>
<label>Nombre:
<input name="nombre" type="text" />
</label>
</p>
<p>
<label>Apellido:
<input name="apellido" type="text" />
</label>
</p>
<p>
<label> Edad:
<input name="edad" type="text" />
</label>
</p>
<p>
<label>Pais:
<input name="pais" type="text" />
</label>
</p>
<P>
<label>Especialidad:
<input name="especialidad" type="text" />
</label>
</p>
<p>
<input type="submit" name="Submit" value="Guardar cambios" />
</p>
</fieldset>
</form>';
} else {
$codigo = false;
}
return $codigo;
}
?>

Esto es apenas un código básico como para comenzar.

No nos olvidemos que este formulario debe mostrar escritos, dentro de cada campo, los valores del registro que se modificará, que ya los tenemos almacenados dentro de la matriz $fila.

Si queremos, podemos probar de incluir una llamada a esta función dentro de nuestra pagina modificar.php, así vemos como muestra el formulario (aunque vacio), este será el código definitivo de la pagina denominada modificar.php:

<?php
// Incluimos los datos de conexión y las funciones:
include("conexion.php");
include("funciones.php");

// Verificamos la presencia del codigo esperado:
if (isset($_GET["codigo"]) and $_GET["codigo"]<>"" ){
$codigo = $_GET["codigo"];

// Nos conectamos:
if (conectarBase ($host,$usuario,$clave,$base)){
$consulta = "SELECT * FROM empleados WHERE id='$codigo'";

if ( $paquete = consultar($consulta)) {
// Aquí llamaremos a una función que muestre esos datos dentro de atributos value de un formulario:
$resultado = editarRegistro ($paquete);
echo $resultado;

} else {
echo "<p>No se encontraron datos</p>";
}
} else {
echo '<p>No se ha indicado cuál registro desea modificar.</p>';
}
echo '<p>Regresar al <a href="listado.php">listado</a></p>';
?>

Si en el listado pulsamos alguno de los enlaces que dicen MODIFICAR, por ahora veremos el formulario vacio:

Formulario de edicion

Figura. El formulario de edición, sin los datos aún.

Volvemos a nuestra función editarRegistro.

Para escribir los datos que faltan dentro del formulario, debemos ir concatenando los distintos campos de $fila dentro de los atributos value de capa input.

Antes de hacerlo, los traspasaremos a variables locales, para evitar problemas con las comillas; de paso, codificaremos en UTF-8 los datos traídos de la base:

$nombreActual = utf8_encode($fila["nombre"]);
$apellidoActual = utf8_encode($fila["apellido"]);
$edadActual =$fila["edad"]; //La edad es un numero
$paisActual = utf8_encode($fila["pais"]);
$especialidadActual = utf8_encode($fila["especialidad"]);

//Remplazaremos la variable $codigo completa por este nuevo codigo donde ya incluimos los datos:
$codigo = '<form action="modificado.php" method="post">
<fieldset><legend>Puede modificar los datos de este registro:</legend>
<p>
<label>Nombre:
<input name="nombre" type="text" value="'.$nombreActual.'"/>
</label>
</p>
<p>
<label>Apellido:
<input name="apellido" type="text" value="'.$apellidoActual.'"/>
</label>
</p>
<p>
<label>Edad:
<input name="edad" type="text" value="'.$edadActual.'"/>
</label>
</p>
<p>
<label>Pais:
<input name="pais" type="text" value="'.$paisActual.'"/>
</label>
</p>
<p>
<label>Especialidad:
<input name="Especialidad" type="text" value="'.$especialidadActual.'"/>
</label>
</p>
<p>
<input type="submit" name="Sudmit" value="Guardar cambios"/>
</p>
</fieldset>
</form>';

Ahora sí, veremos los datos actuales escritos dentro de cada campo, listos para ser modificados por el usuario:

Formulario de edicion con los datos actuales

Figura. El formulario de edición con los datos actuales cargados en cada campo.

Por este formulario, tal como hasta este momento, sólo enviará hacia modificado.php las variables "nombre", "apellido", "edad", "país" y "especialidad".

¿Cómo sabrá, entonces, la orden SQL que ejecutaremos en esa página final (modificado.php) –que desde ya, contendrá un WHERE-, a cuál registro debe actualizar los datos? Buena pregunta.

Hasta ahora, no tendrá forma de saber que registro hay que actualizar.

Debemos hacer que este formulario envié también el código (id) de registro que se actualizará.

Entonces, agregaremos un campo input más, pero que, a diferencia de los otros, no será completado por un usuario, sino que su valor lo definiremos nosotros mismos dentro de un campo oculto (un input de tipo hidden), al que le pondremos como name "codigo", y cuyo value lo escribiremos usando el valor del código que estamos editando, o sea, el que en esta página tenemos almacenado aun dentro de $fila["id"]).

Añadiremos la siguiente línea en el lugar donde traspasábamos variables locales:

$codigoActual = $fila["id"]

Y añadiremos un input más dentro del código del formulario:

<input name="codigo" type="hidden" value="'.$codigoActual.'"/>

Con esto, nuestra pagina modificar.php queda terminada y, nuestra función editarRegistro, también.

Pasemos ahora a codificar la ultima pagina, modificado.php, que es la que finalmente ejecutará la orden SQL que utilizaran los valores actuales y los cambiara por los nuevos valores ingresados por el usuario en el formulario que acabamos de crear.

La orden UPDATE del lenguaje SQL

En la última pagina de este proceso, modificado.php, junto con las demás variables del formulario, nos estará llegando el código que pasamos mediante input oculto, por lo que estamos listos para ejecutar la actualización (por supuesto, validaremos si realmente llego cada dato, y si no está vacio).

Esta es la sintaxis de la orden SQL que realiza la actualización de los valores de un registro:

UPDATE tabla SET campo='valor' WHERE campo'valor';

Atención:
De la misma manera que en la orden DELETE, es fundamental especificar un WHERE, ya que, de no hacerlo, los valores ingresados por el usuario serán aplicados a todos los registros de la tabla y quedaran todos iguales.

En nuestro ejemplo, luego de traspasar a variables locales todos los datos que se hayan recibido de la matriz $_POST, la orden UPDATE quedara así:

UPDATE empleados SET nombre='$nombre', apellido='$apellido', edad='$edad', especialidad='$especialidad' WHERE id='$codigo';

Por esta razón, el código completo de la última pagina (modificado.php) de nuestro sistema de altas, bajas y modificaciones, será:

<?php
// Incluimos los datos de conexion y las funciones
include ("conexion.php");
include ("funciones.php");

// Verificamos la presencia de los datos esperados(deveriamos validar sus valores, aunque acá no lo hagamos para abreviar):
if (isset($_POST["nombre"], $_POST["apellidos"], $_POST["edad"], $_POST["especialidad"], $_POST["codigo"]) ){

// Nos conectamos:
if (conectarBase($host,$usuario,$clave,$base)){

// Evitamos problemas con codificaciones:
@mysql_query("SET NAMES 'utf8'");

// Traspasamos a variables locales para evitar problemas con comillas:
$nombre = $_POST["nombre"];
$apellido = $_POST["apellido"];
$edad = $_POST["edad"];
$pais = $_POST["pais"];
$especialidad = $_POST["especialidad"];
$codigo = $_POST["codigo"];
$consulta = "UPDATE empleados SET nombre='$nombre', apellidos='$apellidos', edad='$edad', pais='$pais', especialidad='$especialidad' WHERE id='codigo'";

if ( mysql_query($consulta)){
echo"<p>Registro actualizado.</p>";
}
else {
echo"<p>No se pudo actualizar</p>";
} else {
echo"<p>Servicio interrumpido</p>";
}
} else {
echo '<p>No se ha indicado cual registro desea modificar.</p>';
}
echo '<p>Regresar al <a href="listado.php">listado</a></p>';
?>

A partir de este momento, ya estamos preparados para interactuar desde cualquiera de nuestra página PHP con información almacenada en bases de datos, realizando las cuatro operaciones básicas: leer, agregar, borrar o modificar datos.

Radiografía de un sistema con back-end y front-end

Pensemos en cualquiera de los sistemas o aplicaciones Web que usamos a diario: un sistema de comercio electrónico, un home banking, un weblog para publicar noticias, un campus virtual, una red social.

Todos estos sistemas tienen una arquitectura común: están compuestos por una doble interfaz, es decir, tiene dos "zonas" completamente diferenciadas: una zona de páginas para uso de los clientes/alumnos/etc., y otra serie de páginas para uso privado del dueño/administrador del sistema.

Desde ya que todos los contenidos de este tipo de sitios Web dinámicos, están almacenados en una base de datos son el núcleo del sistema.

La cadena de la producción de los contenidos de la base de datos, será normalmente:

Administrador → Base de datos → Usuarios

Aunque también podría ser que los mismos usuarios aporten datos:

Usuarios → Base de datos → Usuarios

Y por qué no:

Usuarios → Base de datos → Administradores

(Podría ser que los usuarios escribieran mensajes de soporte o consulta para los administradores).

La herramienta con la que interactuarán estos administradores para cargar contenidos en la base de datos, será una serie de páginas protegidas con contraseña, desde la cual elegirán ver un listado de contenidos (productos, cuentas, alumnos, cursos, noticias, etc.) y usarán formularios como los que aprendimos en este artículo para dar de alta nuevos contenidos, modificarlos o borrarlos (tareas de ABM).

Este es el back-end (el "detrás de la escena" del sitio).

Por otro lado, los usuarios interactuarán con la misma información, pero desde otra serie de páginas, que pueden ser públicas o de acceso restringido, pero en las cuales las acciones permitidas son mucho más limitadas: cada usuario solo podrá ver "su" información (sus compras, saldos, cursos, comentarios, etc.) y únicamente podrá agregar aquella información que "le pertenece" (sus pedidos, sus mensajes, sus tareas, etc.).

Este es el front-end. Las páginas por las que navega el usuario.

Vamos a tomar como ejemplo para analizarlo paso a paso (sin codificarlo) un sistema de pedidos, en esta ocasión, para el sitio web de una Pizzería.

Será muy fácil reutilizarlo con ligeros cambios para otros tipos de negocio, ya que el circuito de recepción de un pedido suele tener muy pocas variantes entre un negocio y otro.

Necesitamos comenzar haciendo un listado de las tareas que cada tipo de usuario realizará (podemos mostrarlas visualmente como diagramas de caso de uso).

Luego, de estos casos de uso deduciremos que páginas será necesario crear para navegar por cada caso de uso, y cuáles serán las principales funciones que será preciso definir.

Deduciremos cuantas tablas tendremos que crear en la base y cuáles serán los principales campos y sus tipos de dato.

Front-end: el punto de vista del usuario

Imaginemos ante todo las tareas de ese cliente que intentará comprar algo utilizando este sistema.

Para ello, pongámonos del lado del cliente (comprador):

¿Qué procesos son necesarios para que nos envíen pizza a nuestra casa?

El proceso podría consistir en recorrer el listado de productos para elegir los que más nos gusten, y luego trasmitir nuestro nombre, domicilio, un teléfono, el detalle del pedido –las cantidades de cada producto, bebidas, postres etc.-y algún comentario extra que consideremos necesario agregar (por ejemplo: "tocar el timbre rojo").

Puede ser que, a continuación, se nos confirme el importe total del pedido, y se nos pregunte con cuánto pagaremos (para llevar el vuelto o cambio justo).

De esta manera, nos indicarán que ya está tomado el pedido y, tal vez, hasta nos den un código de pedido, con el cual podríamos consultar el estado del pedido en caso de demoras.

Resumiendo, podríamos encontrar estas tareas:

  • Ver listado deproductos.
  • Completar formulario de pedido.
  • Recibir código de pedido.
  • Revisar estado del pedido

Si pensamos en las páginas que permitirán realizar esas tareas:

  • listado.php
  • formulario.php
  • agregar.php
  • pedir-estado.php
  • ver-estado.php

Y si pensamos en las funciones que serán necesarias, podríamos imaginar al menos las siguientes:

  • conectarBase
  • consultar
  • tabular
  • verEstado

Releyendo la lista de páginas, vemos que con las tres primeras funciones, podremos ver el listado de productos en venta.

Luego, para mostrar el formulario de pedido no precisamos ninguna función (salvo que quisiéramos crear una para validar los datos ingresados, lo cual seguramente sería muy práctico).

Para agregar el pedido a la base tampoco se precisa una función, y lo mismo para ingresar el código del pedido en un formulario y consultar su estado, aunque si se precisaría la función verEstado para que nos entreguen el estado del pedido solicitado.

Todas estas funciones interactuaran con la base de datos.

Por lo tanto, tenemos que descubrir cuáles son los conceptos claves de lo que tendremos que mostrar o almacenar información.

En este sistema, podemos identificar dos grandes conceptos: el de los productos que se mostraran a la venta, y el de pedidos que se recibirán.

Estas serán entonces las dos tablas que podría tener el sistema (desde ya que podría tener más, como una tabla de usuarios registrados, etc. Pero decidimos mantenerlo simple para ir razonando más fácilmente que es necesario y que es accesorio).

La tabla de productos podría contener campos como:

tabla productos

Y la tabla de pedidos podría contener:

tabla pedidos

Pensando técnicamente que parte del proceso de ABM realizara el usuario de un formulario de pedido, primero vera la lista de productos.

Para ello, realizara un SELECT. Luego vera un formulario y, al enviarlo, realizara un INSERT en la tabla de pedidos. Dara de alta un registro.

Después, si desea consultar el estado de su pedido, entrará a un formulario y, al enviarlo, hará un SELECT.

Lo podemos esquematizar mediante un diagrama de cosas de uso:

Diagrama cliente

Figura. Diagrama de caso de uso del cliente.

En este diagrama, incluimos la tarea de consultar el estado del pedido, cosa que realizará el usuario en las páginas pedir-estado.php y ver-estado.php, introduciendo en la primera de ellas el código que le fue generado al realizar el pedido.

Pasemos ahora al otro lado del mostrador.

Listado de tareas del administrador

Por el otro lado, un operador (administrador) será el encargado de recibir un aviso (podría ser un correo electrónico que se envié automáticamente al realizarse un pedido nuevo), imprimirá el pedido y lo pasará en mano al empleado o cocinero que preparará físicamente la caja con el pedido.

En ese momento, podría ingresar al sistema y cambiar el estado de ese pedido, que en un principio era "recibido"; indicando que ahora está en "preparación" (y un correo electrónico automático le podría avisar al usuario de este cambio).

Una vez que sale de la cocina el pedido y se entrega al chico de la moto, podría cambiarse el estado del pedido a "en camino".

Cuando regrese la moto confirmando que fue entregado, le cambiemos el estado a "entregado". Si por algún motivo se tuviera que cancelar el pedido, le cambiara el estado a "anulado".

Todos estos cambios de estado los podrá realizar el administrador dese una serie de páginas de acceso restringido, donde se le solicite usuario y clave, y se utilicen para validar el acceso.

Para el operador del sistema, sus tareas consistirán en agregar productos nuevos (o eliminarlos), actualizar precios, ver listado de pedidos (ordenados del más reciente al más antiguo, o aquellas que tengan como estado "en espera") y cambiar el estado de un pedido.

Diagrama administrador

Figura. Diagrama de casos de uso del administrador.

Es decir, técnicamente, solicitará listados (consultas SELECT), realizará actualizaciones (UPDATE) y dará de alta nuevos productos (INSERT) o los eliminará (DELETE).

Una vez comprendida la lógica subyacente en este sistema, fácilmente podremos extrapolaría a casi cualquier otro sistema que se nos pueda ocurrir.

La lógica siempre es la misma agregar datos a la base, modificarlos, borrarlos y mostrar la totalidad o solo parte de esos datos.

Este es el esquema de la mayoría de los proyectos de software libre: todos ellos con su back-end y su front-end. Ahora, antes de conocer cuáles son los más útiles de estos sistemas.

Compártelo:
Siguiente ⇒
Aprender PHP y MySQL

Profesor de la Universidad de Guadalajara

Hugo Delgado Desarrollador y Diseñador Web en Puerto Vallarta

Profesional en Desarrollo y Posicionamiento Web desde hace más de 10 años continuos.
Contamos con más de 200 constancias y reconocimientos en la trayectoria Académica y Profesional, incluidos diplomados certificados por Google.

ARTÍCULOS RELACIONADOS:

0 Comentarios

 

Deja un Comentario

Recomendado para ti:

La vida útil de un sitio WebLa vida útil de un sitio Web

Un buen sitio Web no es uno que consulte una vez y después olvide, es aquel que puede añadir a sus marcador...

Síguenos en Facebook