Desarrollo Web Con PHP y MySQL

314
Este libro sigue estando dedicado a ya sabéis quiénes, incluso aunque las personas en cuestión no lo sepan. A ver si logramos mantener el secreto otro libro más.

Transcript of Desarrollo Web Con PHP y MySQL

Page 1: Desarrollo Web Con PHP y MySQL

Este libro sigue estando dedicado a ya sabéis quiénes,incluso aunque las personas en cuestión no lo sepan.

A ver si logramos mantener el secreto otro libro más.

Page 2: Desarrollo Web Con PHP y MySQL

Agradecimientos

Son muchas las personas con las que tengo una deudade gratitud pero poco el espacio disponible para pagarles;toca generalizar. Gracias a todas aquellas personas que meestán ayudando a apreciar las cosas sencillas como, porejemplo, los momentos que puedo compartir con ellas.

Y claro, le tengo que dar las gracias a Ignacio Cerro porponer prólogo a esta obra y ponerla en perspectiva, y aGuadalupe Torres por darle un toque de color y de estilo allibro con una portada tan maravillosa.

Por cierto, quizá en la dedicatoria no ha quedado del todoclaro que este libro va para toda la familia de Guille, que tanbien se está portando con él.

Page 3: Desarrollo Web Con PHP y MySQL

Introducción

¿Revolución? No, realidad.

Está usted leyendo la introducción de un libro quecontiene las claves para convertir sus páginas Web enaplicaciones Web, cuyo contenido se obtiene a partir deuna base de datos, y que permite a sus usuarios almacenarinformación en esa misma base de datos.

Y si tiene usted esta guía en sus manos no hace faltaque le convenza (al menos, no mucho) de la formidablepareja que hacen MySQL y PHP. Éste es un mundo dedescubrimientos. Y de maravillas. Y está en continuocambio.

Fue en el año 1990 cuando comenzó todo, de mano delinvestigador Tim Berners-Lee, el padre de la criatura. Noha pasado tanto tiempo desde entonces, ¿verdad? Y sinembargo, han pasado tantas cosas que parece casiincreíble.

En primer lugar, están las páginas Web, escritas enleguaje HTML. Este lenguaje permite describir la ubicaciónde diferentes elementos en una página, además de suspropiedades (tamaño, color, etc.). Salvando las distancias,sería una tarea similar a la de un pintor trabajando con unlienzo. No en vano la tarea de crear páginas HTML se dejaen manos de los diseñadores, los artistas de la Web.

Estas páginas reciben el calificativo de estáticas porque,una vez publicadas, su contenido permanece inalterable.Hasta que decidamos modificarlas, claro está, pero en estecaso se trataría de otra página. Y es aquí donde aparecePHP.

PHP es un lenguaje, como HTML, pero con unadiferencia notable: tanto los elementos de una páginacomo su ubicación dentro de ella pueden variardependiendo de las condiciones que creamos oportunas.Esto permite crear contenidos totalmente flexibles. Unasencilla aplicación de las posibilidades de PHP consiste enincluir detalles de la fecha y la hora actuales en laspáginas aunque, obviamente, esto no se queda ahí. Puedevariar el contenido de las páginas dependiendo del clienteWeb que se esté utilizando para ver las páginas. Así, siutiliza Firefox, puede mostrar la página de una manera y siutiliza Internet Explorer de otra totalmente diferente.

Por otro lado están las bases de datos, presentes enmultitud de aspectos de la vida cotidiana: en el móvil, en elbanco, en el supermercado. Sin que seamos conscientesde ello, convivimos con estos sistemas. Inicialmente, sualto coste no hacía previsible esta expansión. Pero lasituación ha cambiado considerablemente porque hoy endía podemos encontrar sistemas gestores de bases dedatos que utilizar libremente. Entre ellos destaca uno,MySQL, el más utilizado de los de su clase.

Y por último, está su unión. Para que se haga una idea

Page 4: Desarrollo Web Con PHP y MySQL

del potencial que la combinación de estas tecnologíastiene, suponga que quiere poner a disposición de todo elmundo, en su propio servidor Web, información sobre sucolección de películas. Normalmente esto significaría crearuna página por cada película. Sin embargo, utilizandoMySQL y PHP juntos, podrá crear una única página cuyocontenido variará dependiendo de la película que quieraseleccionar. En esta guía aprenderá a hacerlo.

La unión hace la fuerza, nada más cierto. Combinandolas tecnologías necesarias para ofrecer páginas Web, paraadministrar bases de datos y el lenguaje de páginasdinámicas PHP, podrá poner a disposición de todosaquellos que tengan acceso a Internet un catálogo deproductos o cualquier otra información que desee mostrar.

Y las posibilidades no se limitan a Internet. La red localde su empresa puede ser también el medio de difusiónideal, ya se trate de una aplicación para la gestión de lastareas asignadas a cada departamento o de un boletín denoticias privadas. El límite lo marca su imaginación.

Estamos hablando de medios de difusión, equiparandouna red de ordenadores con una red de periódicos, detelevisión o de radio, porque es así. Las principalescadenas de radio del mundo emiten en Internet desdehace tiempo, los periódicos más importantes tienen suversión digital, e incluso las televisiones se intentan abrirhueco.

Muchos asisten perplejos al nacimiento de un nuevosistema de comunicación de noticias basado en el mismoesquema: un servidor de bases de datos que almacena lasnoticias y un servidor Web que, gracias al uso de lenguajescomo PHP, las ofrece a todos los que quiera leerlas opublicarlas. Muchos de estos sistemas, conocidos comoblogs (de Web Logs) utilizan PHP y MySQL para sufuncionamiento.

Hemos empezado diciéndole que estamos frente a unarealidad y hay varios hechos que lo constatan. El mássignificativo de ellos es la aparición, sin pausa, de versióntras versión de PHP, cada una de ellas incorporandointeresantes novedades, haciéndolo aún más potente ycapaz de lo que ya era.

Si a esto unimos la madurez en la que se encuentraMySQL tras el lanzamiento de su versión 5.1 (que bienpodría haber sido llamada la versión 6), no podemosequivocarnos: PHP y MySQL es la pareja ganadora.Decidirse por ellos es unirse a una de las mayorescomunidades de desarrolladores de nuestro planeta, unagran ventaja, ya que se cuenta con mucha experienciaacumulada que puede ser de utilidad.

Acompáñenos en lo que le prometemos será un viaje dedescubrimientos y de maravillas. No le defraudaremos.

Page 5: Desarrollo Web Con PHP y MySQL

Cómo usar este libro

El objetivo de esta guía es que, a su fin, sea capaz dedesarrollar aplicaciones para la Web basadas en MySQL yPHP. Tanto si ya ha trabajado con ellos por separado oconjuntamente como si éste es su primer contacto, está enbuenas manos.

En primer lugar queremos que sepa exactamente qué eslo que logrará si sigue con nosotros durante el resto delviaje. Para ello hemos preparado un primer capítuloequiparable a una terapia de choque. Durante este capítuloconfigurará un completo sistema de desarrollo y aprenderáqué son un servidor Web, un servidor de bases de datos ydónde encaja PHP dentro de todo esto. Para ilustrar estaexplicación nada mejor que un sencillo ejemplo. Alterminar este capítulo debería tener una visión de conjuntode todas las tecnologías que va a utilizar.

El segundo capítulo es una introducción al lenguaje PHPpara aquellos que aún no lo conozcan: desde ladeclaración de variables y sus posibles tipos hasta lasinstrucciones de control.

En la misma línea que el anterior, el tercer capítulo sededica al sistema gestor de bases de datos MySQL.Hablaremos sobre sus características, veremos qué sonbases de datos y tablas y los tipos de datos que podemosalmacenar.

Los capítulos cuarto y quinto están dedicados a ampliarlos conocimientos adquiridos en el segundo y el tercero.De nuevo están dedicados a PHP y MySQL, pero aaspectos que aún no se han tratado y cuya importancia esfundamental. En concreto, funciones y programaciónorientada a objetos en lo que se refiere a PHP y diseño debases de datos con respecto a MySQL, ya que antes deentrar en el meollo de la cuestión, diseñaremos la base dedatos con la que vamos a trabajar.

En el sexto capítulo aprenderá a utilizar el lenguaje SQLpara obtener la información que desee de una base dedatos, así como para modificarla.

La verdadera acción comienza en el capítulo séptimo. Enél MySQL y PHP unen sus fuerzas. Para acceder a basesde datos de MySQL desde PHP utilizaremos la nuevainterfaz entre ambos que PHP presentó en la versiónanterior a la actual, la 5. Veremos con detalle el ejemploexpuesto durante el primer capítulo, combinado con labase de datos diseñada en el capítulo anterior, y loampliaremos.

En el capítulo octavo hablaremos sobre los formulariosen HTML y JavaScript. Hasta ahora se habrá limitado aobtener información de una base de datos y mostrarla enuna página Web, pero con lo que aprenda en este capítuloserá capaz de permitir que el usuario de sus aplicacionesWeb también pueda guardar datos. Entre otros usos,JavaScript le ayudará a comprobar que estos datos son

Page 6: Desarrollo Web Con PHP y MySQL

correctos, ahorrándole trabajo en sus páginas PHP yevitando posibles errores.

El noveno capítulo está dedicado a uno de los aspectosque más se descuidan durante la creación de un programaen PHP: la gestión de errores. Verá cómo configurar PHP yMySQL en este aspecto, y cómo crear sus propios gestoresde error.

A estas alturas de la guía ya habrá visto lo complicadoque es mantener dos lenguajes como PHP y HTML en unúnico archivo. Lo ideal es que el trabajo de diseño y el deprogramación se puedan hacer de forma independiente.Esto es posible gracias al uso de plantillas, que veremosdurante el capítulo décimo.

Los capítulos decimoprimero, decimosegundo ydecimotercero están dedicados a los procedimientosalmacenados, los desencadenadores y las vistas,respectivamente. Se trata de características avanzadas deMySQL que le resultarán extremadamente útiles.

Esta guía se cierra con un capítulo dedicado a XML, unestándar con el que tanto MySQL como PHP puedentrabajar. En dicho capítulo veremos cómo utilizar suscaracterísticas de forma conjunta.

En un mundo que evoluciona tan rápido como el de lainformática, no hay nada peor que un libro que noevoluciona al mismo paso. Por ello hemos puesto a sudisposición la página Web:

http://enreas.com/amp/

Los productos que utilizamos en este libro dan el nombrea la página: Apache, MySQL y PHP (AMP).

En ella podrá encontrar los ejemplos del libro, contactarcon el autor de esta guía y mucho más.

Page 7: Desarrollo Web Con PHP y MySQL

Prólogo

Perspectiva. La velocidad a la que se suceden losacontecimientos en nuestros días nos dejan, en muchoscasos, carentes de perspectiva para entenderlos.

En el día de ayer mi hijo de nueve años se acercó alfrigorífico de la casa y sacó un batido. Estaba frío, que es loque se espera cuando uno saca una bebida del frigorífico. Acontinuación, se sentó delante de un portátil que sueleestar en la cocina y abrió Spotify. Eligió su lista decanciones favoritas y comenzó a escuchar música.

La música estaba donde debía y hacía lo que seesperaba que hiciese. Todo ocurrió con la mismacoherencia y trasparencia que cuando tomó el batido ensus manos. Todo según lo esperado.

En apenas 30 segundos, dos electrodomésticos leofrecieron lo que él buscaba. Con naturalidad, con claridad,sin interrogantes y sin perspectiva.

Nos estamos convirtiendo, con el paso del tiempo y conla ayuda de las nuevas tecnologías, en auténticosdevoradores. Devoradores de datos, de imágenes, deopciones, de contactos. A veces tiendo a imaginarme loque Internet ofrece como un ente físico, con estructura yvida propia, con extremidades copadas de conocimientos yansioso por atravesar el umbral de la puerta de mi casa.

Qué difícil es parar y cargar una dosis de perspectiva.Perspectiva para entender que las cosas no sucedenporque sí, que el fruto de muchos años de trabajo puedehacer que algo parezca evidente pero es la consecuenciade horas y horas con muchos interrogantes y pocasrespuestas. Qué difícil es entender que nuestra obligaciónpasa tanto por respetar lo que hay como por arrasarlo paraconstruir algo nuevo. Recibir y ofrecer.

En esta dirección he debido hacer un ejercicio deautocrítica. Parar y pensar un poquito. Pensar sin muchosdatos. Yo solito, sin Google, sin Wikipedias a mi alcance.Pensar en lo que hago cada día. Cuestionarme por quéestá frío el batido, por qué usaron ese plástico paradistribuirlo, por qué el color del envase coincide con el delcontenido, por qué tiene ese tamaño si suelo quedarmecon ganas de coger otro. No dar nada por supuesto. Noaceptar nada porque exista desde hace tiempo.

Y en esta senda me topo con algo que uso a diario parami trabajo, que me ofrece información, herramientas,soluciones. Algo que nunca me paré a mirar y que formaparte de mi día a día como si de un grifo se tratase. Lo abroy allí está la respuesta. Comienza mi jornada delante delordenador y algunos actos se suceden a lo largo del día, undía tras otro: consulto una enciclopedia, accedo a un foro,comento en un blog, publico en otro, relleno un formulario.Me siento como un funcionario del control de aduanas deAndorra. Veo pasar todo ante mí fluyendo sin aparenteesfuerzo.

Page 8: Desarrollo Web Con PHP y MySQL

Pero ¿qué hay detrás de todo eso? ¿Qué es lo que losostiene?

No puedo negar que últimamente me siento fuertementeatraído por eso que llaman software libre. Lo reconozcocon cierta vergüenza, pues durante muchos años me fuemuy ajeno. Pero es que no puedo dejar de imaginarme auna legión de programadores, semejante en número yconstancia a un piélago de orcos camino del Abismo deHelm, levantándose cada día para hacer que todo sigafuncionando.

Ahora está pasando las primeras páginas de un libro quepretende mostrar algunas de las cualidades de dos deestos hermanitos que dan de comer a la legión quenombramos anteriormente: PHP y MySQL. Si he de sersincero, para mí no son más que un conjunto de letrasreunidas con poca gracia, pero ya advertí que era elmomento de parar y pensar.

Muchas de las tareas que realizo a diario estánsoportadas por bases de datos construidas con MySQL yse muestran en páginas programadas con PHP. Pero a míme da igual y, aunque hoy lo que pretendo es rendir unpequeño homenaje a aquellos que hacen posible que estosiga creciendo, lo que me dejan es su eficiencia. Suengranaje es sublime. ¿Quien los puso a todos de acuerdopara que la máquina funcionara? ¿Cuál fue el origen?¿Qué puerta hay que cruzar para dejar de ser un devoradory formar parte de la legión? ¿Dónde está la clave para darsoporte y ánimo al grupo?

El software libre se nos ha metido en casa. Lo usamos adiario con la misma naturalidad que tenemos al coger elmando a distancia de la televisión. Entenderlo un poco nosayudaría a respetarlo. Conocerlo nos permitiría hacerlocrecer. Creer que está a nuestro alcance el participar de labatalla no es algo insensato. Por este motivo les invito aque, conmigo, sigan pasando páginas y que puedanencontrar en lo que viene a partir de este momento almenos una respuesta a tanto interrogante.

Les dejo ahora con uno de esos disciplinados orcos. Doyfe de que no es mala compañía.

Ignacio Cerro

Page 9: Desarrollo Web Con PHP y MySQL

1

MySQL y PHP

Para el impaciente.

Este capítulo está pensado para aquel lector que no estámuy seguro de lo que podrá encontrar en este libro.Durante las siguientes páginas crearemos una pequeñaaplicación Web que muestre el contenido de una base dedatos en una página HTML, utilizando PHP como unión.

Veremos que es posible tener una base de datos, extraerlos datos almacenados en ella y mostrarlos en una páginaWeb. Y veremos que, si cambia alguno de los datos de unatabla, el contenido de la página Web cambiará sin que porello tenga que cambiar ni una sola línea de la página PHP.No se preocupe si muchos de los conceptos que sepresenten durante este capítulo le son desconocidos:profundizaremos en todos ellos durante el resto del libro.

Antes de que el lector pueda comenzar a realizar suspropios desarrollos será necesario que pasemos poralgunos capítulos que le mostrarán las característicasprincipales de MySQL y PHP. No queremos engañarle, hayque tener paciencia para contener los deseos de avanzarcapítulos sin prestar la debida atención a los pilaresfundamentales del desarrollo de páginas Web decontenido dinámico.

Una vez tenga esos conocimientos básicos, aprenderá autilizar de forma conjunta ambas tecnologías. MySQL yPHP son grandes productos por sí solos, pero juntosforman una de las parejas más formidables del mundo delsoftware libre.

Plantéese la lectura de este capítulo como la de unanovela: le narraremos una historia que habla del futuro, desu futuro, de las maravillas que podrá construir tras eltrabajo que supondrán los capítulos siguientes a éste.

La primera aplicación

¿Cuál es nuestro objetivo? Construir una aplicación quemuestre el contenido de una base de datos en una páginaWeb. Pero es mejor concretar un poco más.

Vamos a desarrollar una pequeña aplicación Web quepermita gestionar nuestra videoteca. Sería muy ambiciosopor nuestra parte comenzar esta guía con un trabajo detales características, así que iremos por partes: noslimitaremos a crear una aplicación para realizar elmantenimiento de una lista de géneros cinematográficos.Este trabajo formará luego parte de la aplicación quegestionará nuestra videoteca.

Las aplicaciones Web que veremos se componen devarias partes:

Page 10: Desarrollo Web Con PHP y MySQL

Un servidor de bases de datos: MySQL ha sido laelección lógica, debido a su potencia y a que es uno delos más utilizados.Una base de datos: Contiene las tablas y los datoscon los que queremos trabajar. Puede modificar elcontenido de la base de datos y ver cómo el contenidode las páginas Web de su aplicación cambia sin quetenga que alterar una sola línea de código.Un servidor Web: Aunque podríamos escogercualquier servidor Web que permita la ejecución dePHP, nos decantamos por Apache por varios motivos.Entre ellos, que se trata del servidor Web más utilizadoen el mundo y es libre, por lo que todos podemosutilizarlo en Windows, Linux o Mac OS X.PHP: El nexo de unión entre la base de datos y losclientes potenciales de nuestra aplicación Web.Clientes: Los clientes son los usuarios de nuestraaplicación Web. Sea un desarrollo hecho para nuestropropio disfrute o para el de los demás, si nadie(persona o máquina) va a utilizarlo quizá su existenciacarezca de sentido.

La figura 1.1 muestra las relaciones existentes entre losdiferentes elementos que acabamos de enumerar.

Figura 1.1. Aplicaciones Web

Por lo tanto, el primer paso será disponer de todos losservicios necesarios: MySQL para las bases de datos yApache (con PHP) para las páginas Web. Tras ello,podremos comenzar con a trabajar.

Nuestro desarrollo va a comenzar con la creación de labase de datos. Posteriormente poblaremos dicha base dedatos con las tablas y los registros necesarios.Continuaremos con la programación en PHP de la páginaque mostrará el contenido de una de las tablas de la basede datos. Al terminar podremos contemplar algo parecido alo que se puede ver en la figura 1.2.

Page 11: Desarrollo Web Con PHP y MySQL

Figura 1.2. Nuestro objet ivo

Nota: No preste atención al diseño de la página, a su aspecto, y concéntrese enel contenido de la misma, en que todo funciona como se espera. En el capítulodedicado a Smarty aprenderemos a separar la lógica (funcionamiento,programación) de la representación (aspecto, diseño).

XAMPP

Como acabamos de comentar, para que se pueda ponermanos a la obra necesita disponer de un sistema conApache, PHP y MySQL instalados y en funcionamiento.Francamente, haría falta un libro como éste sólo paracomenzar a explicar cómo instalar y configurarcorrectamente estos tres componentes en los tressistemas operativos más utilizados del mercado (Windows,Linux y Mac OS X).

Pues, aunque le parezca mentira, existe una formarápida y sencilla de instalar y configurar todo esto, de unplumazo, en cualquiera de los sistemas operativos antesmencionados: XAMPP. Puede encontrarlo en la página:

http://apachefriends.org/

Nota: XAMPP son las siglas de X, Apache, MySQL, PHP y Perl. Se ut iliza una Xpara representar al sistema operat ivo y no una W (de Windows) o una L (deLinux), como en WAMP o LAMP. En este libro no ut ilizaremos esa últ ima P.

Un par de aclaraciones. En primer lugar, XAMPP es idealpara entornos de desarrollo. Sin embargo, la opciónrecomendada para un servidor de producción (es decir,aquel en el que se encontrarán las aplicaciones Web unavez concluido su desarrollo) sigue siendo la más compleja:la instalación, configuración y mantenimiento de cada unode los componentes de forma individual. Obviamente, setrata de un trabajo que es necesario dejar en manos deexpertos capaces de garantizar la seguridad y elrendimiento del servidor.

En segundo lugar, XAMPP no es algo único. Existenmuchas otras soluciones para instalar Apache, PHP yMySQL con facilidad. La razón por la que lo utilizaremos eneste libro es múltiple:

Está a su disposición ya utilice Windows, Linux o Mac

Page 12: Desarrollo Web Con PHP y MySQL

OS X.El equipo responsable de su desarrollo se preocupa demantenerlo actualizado para que ofrezca la últimaversión de cada componente.Incluye multitud de herramientas como, por ejemplo,phpMyAdmin, una aplicación Web para laadministración de bases de datos MySQL.Proporciona una interfaz de usuario muy fácil deutilizar para poner en marcha y detener los servicios,de forma individual.

No es obligatorio que use XAMPP, podrá seguir losejemplos de este libro siempre y cuando disponga de unequipo con Apache, PHP y MySQL correctamenteinstalados y configurados.

Puesta en marcha de XAMPP

Independientemente del sistema operativo, lainstalación de XAMPP es prácticamente idéntica: tendráque descargar un archivo, extraer su contenido y ejecutaruna orden para poner en marcha los servicios necesarios.

Puesta en marcha en Windows

La forma más sencilla de disponer de la versión paraWindows de XAMPP es utilizar el asistente para lainstalación disponible en la siguiente dirección:

http://apachefriends.org/en/xampp-windows.html

Cuando termine de descargar el instalador haga dobleclic sobre él y siga los pasos del mismo. Como podrácomprobar, se trata de un proceso muy simple. El máscomplejo de ellos, que puede ver en la figura 1.3, consisteen seleccionar la ruta en la que se instalará XAMPP.

Figura 1.3. Instalación de XAMPP en Windows

Advertencia: ¿Por qué es el paso más complejo? Porque, según se comenta enla página dedicada a la versión para Windows de XAMPP, la mejor forma de evitarproblemas con los permisos de la carpeta de archivos de programa si se instalaen Windows Vista es ut ilizar una carpeta que se encuentre en la raíz del discocomo, por ejemplo, C:\xampp.

Page 13: Desarrollo Web Con PHP y MySQL

Las opciones predeterminadas de los pasos delasistente serán las más adecuadas en la mayoría de loscasos.

Cuando el proceso de instalación concluya se le ofrecerála opción de ejecutar el panel de control de XAMPP.Responda que sí: podrá ver un cuadro de diálogo similar alque muestra la figura 1.4.

Figura 1.4. Panel de control de XAMPP

En lo que a esta guía respecta sólo nos interesarán losbotones asociados a Apache y a MySQL. Haga clic en Startpara poner en marcha un servicio. Cuando esté enfuncionamiento aparecerá una etiqueta a su derecha con eltexto Running y el nombre del botón cambiará por Stop.Utilícelo para detener el servicio correspondiente cuandolo desee.

El panel de control de XAMPP se encuentra dentro delmenú Inicio, haciendo clic en Programas o Todos losprogramas y, a continuación, en ApacheFriends>XAMPP>XAMPP Control Panel.

Puesta en marcha en Linux

La instalación y puesta en marcha de XAMPP en Linuxno podría ser más sencilla:

1. Descargue la versión para Linux de XAMPP, que seencuentra en la página:http://apachefriends.org/en/xampp-linux.html

2. Inicie una sesión como administrador del sistema outilice la orden su para obtener sus privilegios.

3. Utilice la siguiente orden para extraer su contenido,sustituyendo X e Y por los números correspondientes ala versión de XAMPP que haya descargado: tar xvfzxampp-linux-X.Y.tar.gz -C /opt

4. Como resultado, XAMPP se encontrará en dentro de lacarpeta /opt.

5. Por último, ejecute la orden /opt/lampp/lampp startpara poner en marcha XAMPP y /opt/lampp/lamppstop para detenerlo.

Consejo: Póngase en contacto con el administrador de su sistema Linux si t ienedificultades para seguir las anteriores instrucciones o si el resultado obtenido no

Page 14: Desarrollo Web Con PHP y MySQL

es el deseado, algo que puede ocurrir si en su equipo ya están instalados y enfuncionamiento Apache o MySQL.

Puesta en marcha en Mac OS X

De nuevo, al igual que en los dos apartados anteriores,dedicados a Windows y Linux, es necesario decir que lainstalación de XAMPP en Mac OS X es muy sencilla:

1. Descargue la versión para Mac OS X de XAMPP, que seencuentra en la página:http://apachefriends.org/en/xampp-macosx.html

2. Haga doble clic sobre el archivo DMG descargado.3. Una vez la imagen de disco se monte haga doble clic

sobre el archivo XAMPP for MacOS X.pkg y siga lospasos del instalador.

4. Cuando el proceso de instalación concluya sólo restaráponer en marcha los servicios. Para ello abra unterminal y ejecute la orden sudo/Applications/XAMPP/xamppfiles/mampp start.Podrá ver algo parecido a lo que muestra la figura 1.5.

Figura 1.5. Puesta en marcha de XAMPP en Mac OS X

6. De igual forma, para detener los servicios deberáejecutar, también desde un terminal, la orden sudo/Applications/XAMPP/xamppfiles/mampp stop.

Con independencia del sistema operativo que utilice,XAMPP estará disponible a través de la direcciónhttp://localhost/. Vaya allí con su cliente Web favorito;podrá ver una página de presentación con diferentesenlaces, uno por cada idioma disponible. La figura 1.6muestra el resultado de hacer clic sobre Español y,después, sobre Estado en la parte izquierda de la página.

Page 15: Desarrollo Web Con PHP y MySQL

Figura 1.6. Estado de los servicios de XAMPP

El aspecto de estas páginas es prácticamente idénticoen Windows, Linux y Mac OS X.

Ahora que ya tiene XAMPP instalado asegúrese de queApache y MySQL estén en funcionamiento antes de pasaral siguiente apartado, donde nos pondremos manos a laobra.

Trabajando con MySQL

Nuestro primer paso, siempre que comencemos eldesarrollo de una aplicación Web que trabaje con MySQL,debería ser diseñar la base de datos. Existen herramientasque pueden ayudarnos a realizar esta tarea. De entretodas ellas, le recomendamos MySQL Workbench,disponible para Windows, Linux y Mac OS X.

Pero antes de utilizar herramienta alguna hemos detener claro qué información debe contener la base dedatos. Para ello, nada mejor que el diálogo con aquellosque lo sepan. Si vamos a desarrollar una aplicación parauna empresa, hemos de hablar todo lo que sea necesariocon aquellos que tengan más información al respecto, quede verdad sepan cómo debe funcionar.

En nuestro caso lo tenemos más fácil: sabemos lo quequeremos, puesto que durante este aprendizaje seremosnuestro propio jefe. Vamos a guardar en una tabla dentrode una base de datos de MySQL información sobregéneros cinematográficos. Posteriormente utilizaremosestos géneros conjuntamente con otras tablas, quecontendrán información sobre películas.

Creación de la base de datos

Page 16: Desarrollo Web Con PHP y MySQL

Aunque existen herramientas en línea de órdenes pararealizar operaciones con MySQL, dejaremos esa opciónpara aquellos lectores que lo encuentren necesario.MySQL pone a nuestra disposición una herramientamucho más amable: MySQL Administrator. Puedeencontrarla en la siguiente página, formando parte delpaquete MySQL GUI Tools:

http://dev.mysql.com/downloads/gui-tools/

Nota: Si instaló XAMPP también podrá ut ilizar phpMyAdmin para realizar estasoperaciones en el servidor de base de datos MySQL de su ordenador.phpMyAdmin estará a su disposición a t ravés del URLhttp://localhost/phpmyadmin/.

La primera vez que se ejecuta MySQL Administrator sepresenta un cuadro de diálogo para conectarse a unservidor, que puede ver en la figura 1.7.

Figura 1.7. Conexión con un servidor MySQL

Este cuadro de diálogo le pedirá todos los datosnecesarios para que se pueda establecer comunicacióncon el servidor MySQL con el que quiere trabajar.

Basta con que introduzca el nombre del servidor en elcuadro de texto Server Host (si se trata del mismo en elque se está ejecutando MySQL Administrator este nombreserá localhost) y el nombre del usuario en Username. Eneste caso, como estamos utilizando XAMPP, este nombreserá root y no tendrá contraseña asignada, algo quesupondría un problema de seguridad en un servidor deproducción pero que permite trabajar mucho máságilmente en un puesto personal.

Por supuesto, si el servidor está en otro ordenador,introduzca su nombre o IP en el cuadro de texto ServerHost, y utilice el nombre de usuario y la clavecorrespondientes para intentar conectarse. Haga clic enOK cuando haya terminado.

La figura 1.8 muestra el aspecto de MySQL Administratortras realizar la conexión con el servidor. En dicha figurapuede observarse que, en el panel de la izquierda, abajodel todo, aparece un nodo llamado Catalogs. Haga clic conel botón izquierdo del ratón sobre ese nodo. Bajo élaparecerá una lista con todos los catálogos (bases de

Page 17: Desarrollo Web Con PHP y MySQL

datos) disponibles. Haga clic con el botón derecho sobreeste nuevo panel y seleccione la opción Create NewSchema del menú desplegable que aparecerá.

Figura 1.8. MySQL Administrator, en funcionamiento

MySQL Administrator le presentará un cuadro de diálogoen el que sólo se le pedirá que introduzca el nombre de lanueva base de datos. Escriba videoteca. Ese será elnombre de la base de datos con la que trabajaremosdurante el resto del libro.

Cuando haga clic en OK el panel que contiene la lista decatálogos mostrará un aspecto similar al de la figura 1.9,donde la base de datos recién creada está seleccionada.

Figura 1.9. Nuestra nueva base de datos

Ésta, videoteca, será la base de datos con la quetrabajaremos a partir de ahora. No preste demasiadaatención al resto de bases de datos que aparecen en estepanel, no las utilizaremos para nada.

Si lo desea, puede crear sus bases de datos a partir descripts SQL. Esta forma de trabajo tiene algunas ventajassobre la que acaba de ver. Por ejemplo, permite repetir laoperación de creación de la base de datos tantas vecescomo sea necesario, tenga acceso a MySQL Administratoro no.

Para ello, una vez conectado con el servidor de bases dedatos, seleccione la opción MySQL Query Browser delmenú Tools, lo que ejecutará otra de las herramientas deMySQL, pensada para la ejecución de consultas.

Page 18: Desarrollo Web Con PHP y MySQL

MySQL Query Browser permite dar órdenes al servidorMySQL utilizando el lenguaje SQL. Por ejemplo, para crearla base de datos videoteca podría utilizar las siguientesinstrucciones:

DROP DATABASE IF EXISTS videoteca;

CREATE DATABASE videoteca;

La primera de estas líneas borra la base de datosvideoteca en caso de que exista. La segunda, la crea. Deesta forma evitará que ocurran errores si intenta crear labase de datos cuando ésta ya existe. Tenga presente, sinembargo, que si existe la borrará y perderá todos los datosque contenga.

Para ejecutar las instrucciones anteriores seleccione laopción New Script Tab del menú File. Aparecerá unanueva ficha con el título Script 1. Escriba las dos líneasanteriores en el área central de MySQL Query Browser yhaga clic en el botón Execute, que se encuentra en labarra de herramientas (es de color verde y tiene algo asícomo un rayo en el centro). La figura 1.10 muestra elaspecto de este programa tras ejecutar las dosinstrucciones anteriores. El puntero de ratón está sobre elbotón Execute. Ahora que tiene la base de datos necesitacrear la tabla que contendrá los detalles de cada género.

Figura 1.10. SQL para crear una base de datos

Creación de la tabla

¿Qué detalles queremos guardar de cada género? Poruna parte, vamos a guardar su descripción. Estadescripción define el género cinematográfico de formacompleta: ciencia ficción, aventuras, drama, etc. Tambiénpuede ser de utilidad guardar una abreviatura de dichadescripción. Por último, vamos a guardar un identificadornumérico que será único para cada género. Utilizaremoseste identificador para relacionar cada película con el

Page 19: Desarrollo Web Con PHP y MySQL

género cinematográfico correspondiente.

Ya sabe los detalles que debe guardar de cada género.Ahora decida el tipo de datos que tendrá cada uno de ellos.El identificador será un número. Vamos a limitar la longituddel nombre que le damos a ese género, su abreviatura, ados caracteres, mientras que su descripción podrá tenerhasta 32. La figura 1.11 muestra el aspecto que podríatener esta tabla una vez la cree utilizando MySQLWorkbench.

Figura 1.11. La tabla de géneros

Nota: El diseño de bases de datos es una tarea fundamental e importante.Puede encontrar algunos consejos al respecto en el capítulo 5.

La figura 1.11 muestra la tabla de géneros después dediseñarla utilizando MySQL Workbench. Este programanos permite crear tablas y relacionarlas de forma muysencilla. En la figura 1.12 vemos el panel de MySQLWorkbench con el que hemos creado la tabla de géneros.

Figura 1.12. Diseñando la tabla de géneros

Pero lo mejor de todo es que puede obtener el códigoSQL necesario para crear esta tabla de forma automática,tras realizar el diseño. Sólo ha de hacer clic con el botónderecho sobre la tabla que acabamos de crear en MySQLWorkbench y seleccionar la opción Copy SQL toClipboard del menú contextual que aparecerá. Abra sueditor de texto favorito (el bloc de notas, por ejemplo) ypegue el contenido del portapapeles utilizando lacombinación de teclas Control-V.

Por ejemplo, el siguiente es el código necesario paracrear la tabla de géneros:

CREATE TABLE genero (

id INT UNSIGNED NOT NULL AUTO_INCREMENT,

nombre VARCHAR(2) NOT NULL,

descripcion VARCHAR(32) NOT NULL,

PRIMARY KEY (id)

);

En el apartado anterior vimos cómo ejecutar código SQL

Page 20: Desarrollo Web Con PHP y MySQL

utilizando MySQL Query Browser. Vamos a utilizar esatécnica de nuevo para crear la tabla de géneros. En primerlugar seleccione la opción New Script Tab del menú File,dentro de MySQL Query Browser. Se abrirá una ficha conun título similar a Script 1 (el número final puede variar,dependiendo de si existen o no otras fichas del mismotipo). Escriba la siguiente instrucción en el área central deMySQL Query Browser y haga clic en el botón Execute:

USE videoteca;

A partir de ese momento, todas las operaciones querealice estarán referidas a dicha base de datos. Así,cuando creemos la tabla de géneros lo haremos en la basede datos videoteca. Vamos a ello: escriba en la ventana deconsultas la instrucción para creación de tabla que vimosanteriormente y haga clic en el botón Execute. Si todo haido bien dispondrá de una base de datos y de una tabla,más que suficiente para comenzar a introducir datos.

Existen otras formas de crear tablas, utilizando otrasherramientas, pero no podemos dejar de mencionar una deellas, que seguro será de utilidad para aquellos quequieran permanecer lo más alejados que sea posible deSQL.

Consejo: Desde aquí queremos recomendarle que aprenda SQL si aún no t ienesoltura con este lenguaje. Le aseguramos que todo el t iempo que emplee endicho aprendizaje será una inversión que comenzará a ser rentable en un periodode t iempo muy breve. Garant izado.

Igual que utilizó la interfaz de usuario de MySQLAdministrator para crear la base de datos, puede utilizarlapara crear tablas. Sólo tiene que hacer clic sobre la base dedatos videoteca en el panel de catálogos, que aparece enla parte inferior izquierda cuando se selecciona el nodoCatalogs. En la parte derecha parecerá un panel que,entre otros elementos, contiene un botón llamado CreateTable. Haga clic sobre él. MySQL Administrator mostraráuna nueva ventana desde la que podrá crear tablas consólo rellenar los huecos. En la figura 1.13 puede ver cómola hemos rellenado para crear la misma tabla de génerosque obtuvimos con MySQL Workbench.

Page 21: Desarrollo Web Con PHP y MySQL

Figura 1.13. Crear tablas con MySQL Administrator

Cuando haga clic en el botón Apply Changes, sobre elque está el puntero del ratón en la figura 1.13, se lepreguntará que confirme la ejecución de la instrucción SQLcorrespondiente. Para ello, haga clic en Execute.

Tanto si creó la tabla con SQL como si se ayudó de lainterfaz de MySQL Administrator, el aspecto de este últimoal seleccionar el nodo Catalogs y, posteriormente,videoteca, debe ser similar al que puede verse en la figura1.14.

Figura 1.14. Nuestra nueva tabla

Ya puede realizar las primeras inserciones de datos.

Inserciones

Page 22: Desarrollo Web Con PHP y MySQL

El último paso que tiene que dar antes de comenzar atrabajar con PHP es poblar la tabla de géneros con algunasentradas. Por ejemplo, puede añadir los valores necesariospara representar los géneros de ciencia ficción, aventurasy drama.

Si utiliza SQL puede escribir las siguientes instruccionesen una nueva ficha del tipo Script (recuerde: File>NewScript Tab) dentro de MySQL Query Browser y hacer clicen el botón Execute:

USE videoteca;

INSERT INTO genero(nombre, descripcion)

VALUES('CF', 'Ciencia Ficción');

INSERT INTO genero(nombre, descripcion)

VALUES('A', 'Aventuras');

INSERT INTO genero(nombre, descripcion)

VALUES('D', 'Drama');

De nuevo, además de SQL, tiene la opción de utilizar lasherramientas de MySQL Administrator. Seleccione el nodoCatalogs en el panel de la izquierda, haga clic sobre labase de datos videoteca y, por último, haga clic con elbotón derecho sobre la tabla de géneros y seleccione laopción Edit Table Data del menú desplegable queaparecerá. ¡Oh, sorpresa! Se ha abierto MySQL QueryBrowser pero, en lugar de una ficha del tipo Script hay unadel tipo Resultset con una consulta ya introducida yejecutada. Puede verlo en la figura 1.15. Haga clic sobre elbotón Edit, que aparece en la parte inferior de la ventanade MySQL Query Browser (el puntero del ratón está sobreél en la figura 1.15).

Figura 1.15. Inserción de datos en MySQL Query Browser

Page 23: Desarrollo Web Con PHP y MySQL

Nota: Las fichas de t ipo Script de MySQL Query Browser permiten ejecutarinstrucciones SQL que no devuelven resultados como, por ejemplo, las decreación de tablas o inserción de datos. Ut ilice las fichas de t ipo Resultset pararealizar consultas en los datos contenidos en las tablas de una determinada basede datos.

MySQL Query Browser entrará en el modo de inserciónde datos, lo que le permitirá escribir directamente losvalores de las columnas que desee añadir con sólo hacerdoble clic sobre el hueco del campo correspondiente. Porejemplo, en la figura 1.16 se está insertando el primero delos géneros.

Figura 1.16. Insertando registros

Nota: No es necesario que se introduzca el ident ificador del género (campo id).MySQL se encarga de asignar ese valor automát icamente debido a que uno delos modificadores de su t ipo es AUTO_INCREMENT. Para saber más al respectoconsulte el capítulo 5, "Diseño de bases de datos".

Esta característica de MySQL Query Browser no sólo lepermite insertar nuevos registros, también editar losexistentes.

Cuando termine de introducir los datos de los géneroshaga clic en el botón Apply Changes, que se encuentrajusto a la derecha del botón Edit (el que tuvo que pulsarpara comenzar a añadir registros en la tabla de géneros).La figura 1.17 muestra el aspecto de la ventana deconsultas después de introducir los tres nuevos géneros.

Page 24: Desarrollo Web Con PHP y MySQL

Figura 1.17. Los t res géneros de part ida

Cierre MySQL Query Browser. Puede hacerlo pulsando lacombinación de teclas Control-F4 o seleccionando laopción Exit del menú File.

Hemos completado el primer paso de nuestro pequeñoproyecto. Dispone de una base de datos, videoteca.Dentro de ella, en una tabla llamada genero, tiene tresregistros, cada uno de ellos con un nombre, unadescripción y un número que los identifica de forma única.

El siguiente paso consiste en utilizar PHP para accederal contenido de esta tabla y poder mostrar su contenido enuna página Web. Realmente, no queda mucho por hacer,tan solo utilizar las herramientas que PHP nos ofrece paraconectar con el servidor de bases de datos. Así que abra sueditor de textos favoritos: ¡vamos a programar!

Trabajando con PHP

La anterior versión de PHP, la 5, incorporaba novedadesrealmente interesantes. La mayor parte de ellas estabanrelacionadas con la programación orientada a objetos, dela que hablaremos detenidamente en posteriorescapítulos.

Una de las novedades que no estaba relacionada con laprogramación orientada a objetos nos resulta ahoraespecialmente interesante: el acceso mejorado a MySQL.

Nota: Aunque quizá sí hay relación, ya que esta nueva interfaz mejorada deacceso a MySQL viene en dos sabores: funcional y orientado a objetos. Por ahorasólo veremos la primera.

Esta nueva forma de acceder tiene nombre: MySQLi. La ilatina final viene de improved (mejorado). Y tiene unalimitación: sólo permite acceder a servidores MySQLmodernos. Aunque gracias a esta restricción el equipo dedesarrolladores de PHP ha podido crear un conjunto defunciones cuyo rendimiento y forma de funcionamientosuperan en muchos aspectos a las interfaces de accesoanteriores.

Acceder a MySQL a través de esta interfaz es tarea muysencilla. En primer lugar, ha de establecer una conexióncon el servidor. Para ello utilice la funciónmysqli_connect().

Nota: Todas las funciones de la interfaz de acceso a MySQL que vamos a vercomienzan con el prefijo mysqli_. De esta forma es sencillo reconocer a lasfunciones de este grupo.

La función mysqli_connect() recibe como parámetros ladirección en la que se encuentra el servidor (o su nombre),el nombre de usuario, la clave de acceso y el nombre de la

Page 25: Desarrollo Web Con PHP y MySQL

base de datos con la que queremos conectar.

Si todo ha funcionado correctamente, el resultado deesta función nos permitirá realizar operaciones en elservidor de base de datos. En caso de error, el resultado dellamar a esta función es FALSE.

Dicho esto, puede utilizar el siguiente código pararealizar la conexión:

<?php

$conexion = mysqli_connect(

'localhost',

'root',

'',

'videoteca'

);

if ($conexion == FALSE){

echo('Error en la conexión.');

exit();

}

...

En el código anterior suponemos que el servidor está enel mismo ordenador en el que estamos trabajando(localhost), que el nombre de usuario es root y que notiene clave (un claro problema de seguridad pero, como yahemos comentado anteriormente, se trata delfuncionamiento predeterminado de XAMPP). Sustituya lascredenciales de acceso por las correspondientes a suentorno de trabajo. El nombre de la base de datos tieneque ser videoteca en este caso.

Tras llamar a mysqli_connect() comprobamos si el valorde $conexion es FALSE. Si es así es que la conexión nose ha realizado correctamente, de forma que informamosdel error en la conexión y terminamos el programallamando a exit().

Pero si todo ha ido bien podemos continuar para bingo.El siguiente paso es obtener todos los valoresalmacenados en la tabla genero. Para ello, haga doble clicsobre la base de datos videoteca, en el panel de laderecha, Schemata. Así le indicará a MySQL QueryBrowser que quiere trabajar con esa base de datos. Acontinuación ejecute esta consulta SQL:

SELECT * FROM genero;

En la figura 1.18 puede ver el resultado de ejecutar estaconsulta utilizando MySQL Query Browser.

Page 26: Desarrollo Web Con PHP y MySQL

Figura 1.18. Recuperando todos los registros

Puede utilizar esa consulta desde PHP gracias a lafunción mysqli_query(). Esta función recibe comoparámetros el valor devuelto por mysqli_connect() y unacadena de caracteres que contenga la consulta a ejecutar.El resultado de esta función, como en la función deconexión, es un objeto si se pudo ejecutar la consulta, oFALSE en caso contrario. Podría usarla así:

...

$resultado = mysqli_query(

$conexion,

'SELECT * FROM genero'

);

if ($resultado == FALSE){

echo('Error en la consulta.');

mysqli_close($conexion);

exit();

}

...

Este fragmento de código es muy similar al anterior.Primero llame a la función mysqli_query() con losparámetros necesarios, guardando el valor de respuestaen una variable ($resultado).

A continuación compruebe que $resultado no seaFALSE. Si lo es, es que ha ocurrido un error al realizar laconsulta, así que informe de ello, cierre la conexión (conmysqli_close()) y salga del programa con exit().

Advertencia: Es conveniente dejarlo todo como estaba antes de comenzar elprograma. Si abre una conexión con un servidor MySQL, debe cerrarla antes determinar el programa; si obt iene un conjunto de registros, debe liberar la memoriaque hayan ocupado.

Page 27: Desarrollo Web Con PHP y MySQL

Si no ha ocurrido ningún error, ya dispone de los datosque quiere mostrar: todos los géneros que tienealmacenados en la tabla genero de la base de datosvideoteca. Sólo tiene que mostrarlos.

La función mysqli_fetch_row() le permite recuperar losregistros obtenidos uno por uno, dentro de una matriz, deforma que puede utilizarla en un bucle while:

...

while($fila = mysqli_fetch_row($resultado)){

printf(

"(%u) %s - %s<br/>",

$fila[0], $fila[1], $fila[2]

);

}

...

Es decir, llame a la función mysqli_fetch_row() y guardeel resultado en $fila. Si la función devolvió algún registro,$fila será diferente de FALSE, así que ejecute la funciónprintf(), que muestra en la página los valores de eseregistro.

La siguiente llamada mysqli_fetch_row() devuelve elsiguiente registro, y así hasta que no quede ningúnregistro por mostrar. Cuando ocurre eso, $fila valdráFALSE y saldrá del bucle.

Para terminar, como dijimos, deje todo como estaba,liberando el espacio ocupado por el resultado de laconsulta y cerrando la conexión con la base de datos:

...

mysqli_free_result($resultado);

mysqli_close($conexion);

?>

A continuación, el código de este ejemplo, completo:

<?php

$conexion = mysqli_connect(

'localhost',

'root',

'',

'videoteca'

);

if ($conexion == FALSE){

echo('Error en la conexión.');

exit();

}

$resultado = mysqli_query(

$conexion,

'SELECT * FROM genero'

);

Page 28: Desarrollo Web Con PHP y MySQL

);

if ($resultado == FALSE){

echo('Error en la consulta.');

mysqli_close($conexion);

exit();

}

while($fila = mysqli_fetch_row($resultado)){

printf(

"(%u) %s - %s<br/>",

$fila[0], $fila[1], $fila[2]

);

}

mysqli_free_result($resultado);

mysqli_close($conexion);

?>

Guarde esta página en la carpeta htdocs, que seencuentra dentro de aquella en la que haya instaladoXAMPP, con el nombre generos.php. Entonces, visite lapágina http://localhost/generos.php. El resultado puedeverse en la figura 1.19.

Figura 1.19. Los géneros, en PHP

Y ahora un detalle curioso: nuestra primera página PHPno ha tenido más que una etiqueta HTML, la que indicanueva línea: <br/>.

Pero eso podemos solucionarlo, vuelva a escribir el buclewhile, pero ahora use tablas. Sustituya el código del buclepor el siguiente:

...

?>

<table border="1">

<tr>

<th>id</th>

<th>nombre</th>

<th>descripcion</th>

</tr>

<?php

while($fila = mysqli_fetch_row($resultado)){

printf('<tr>');

Page 29: Desarrollo Web Con PHP y MySQL

printf('<tr>');

printf(

"<td>%u</td><td>%s</td><td>%s</td>",

$fila[0], $fila[1], $fila[2]

);

printf('</tr>');

}

?>

</table>

<?php

...

El código completo de esta nueva página, que debeguardar con el nombre generos2.php en la mismaubicación que generos.php, es el siguiente:

<?php

$conexion = mysqli_connect(

'localhost',

'root',

'',

'videoteca'

);

if ($conexion == FALSE){

echo('Error en la conexión.');

exit();

}

$resultado = mysqli_query(

$conexion,

'SELECT * FROM genero'

);

if ($resultado == FALSE){

echo('Error en la consulta.');

mysqli_close($conexion);

exit();

}

?>

<table border="1">

<tr>

<th>id</th>

<th>nombre</th>

<th>descripcion</th>

</tr>

<?php

while($fila = mysqli_fetch_row($resultado)){

printf('<tr>');

Page 30: Desarrollo Web Con PHP y MySQL

printf('<tr>');

printf(

"<td>%u</td><td>%s</td><td>%s</td>",

$fila[0], $fila[1], $fila[2]

);

printf('</tr>');

}

?>

</table>

<?php

mysqli_free_result($resultado);

mysqli_close($conexion);

?>

El resultado de cargar esta nueva página puede verse enla figura 1.20. El contenido es el mismo, pero la aparienciacambia. Gracias a este ejemplo hemos podido comprobarde primera mano lo complejo que puede llegar a ser incluircódigo HTML dentro del código PHP. En el capítulodedicado a las plantillas, veremos algunas de las opcionesque tenemos para separar la lógica de la representación,facilitando la tarea tanto a programadores como adiseñadores.

Figura 1.20. Nuestro ejemplo, con tablas

Y ahora, por fin, lo más espectacular: contemplar cómocambia la página PHP cuando añadimos algún nuevoregistro a la tabla genero, sin necesidad de cambiar elcódigo. La siguiente instrucción SQL inserta un nuevoregistro:

INSERT INTO genero(nombre, descripcion)

VALUES('T', 'Terror');

Utilice MySQL Query Browser para ejecutar el códigoanterior. El resultado es que nuestra tabla tendrá un nuevoregistro, como puede ver en la figura 1.21.

Page 31: Desarrollo Web Con PHP y MySQL

Figura 1.21. Un nuevo género

Este cambio en la tabla se reflejará en la página sivuelve a cargarla. El resultado debería ser algo parecido alo que puede ver en la figura 1.22.

Figura 1.22. Un nuevo género, en PHP

Impresionante, ¿verdad? Y esto no ha hecho más queempezar.

Page 32: Desarrollo Web Con PHP y MySQL

2

PHP

Aunque se utiliza para crear páginas Web dinámicas,PHP está más cerca de lenguajes como C++ o Java que delpropio HTML. Se trata de una excelente combinación delas mejores características de los lenguajes deprogramación más utilizados, con un único objetivo: que laprogramación de páginas dinámicas sea pan comido.

Durante este capítulo nos concentraremos en lascaracterísticas de PHP como lenguaje de programación,así que no tenga el más mínimo reparo en pasar alsiguiente capítulo si cree que tiene los conocimientosnecesarios.

Por el contrario, si decide quedarse con nosotros, notenga miedo, será entretenido. Repasaremos losconceptos básicos de programación tal y como losentiende PHP, intentando evitar en lo posible la jerga delos programadores, aunque en ocasiones no nos quedarámás remedio. Veremos cómo guardar valores en variablesy de qué tipo pueden ser. Después manipularemos esosvalores, realizando operaciones sobre ellos (sumas, restas,etcétera).

Usaremos el resultado de esas manipulaciones paratomar decisiones, como qué acciones debemos realizar.Estas decisiones las realizaremos utilizando instruccionescondicionales. También utilizaremos instruccionesiterativas, que permitirán realizar la misma acción variasveces. Entre estas acciones puede estar el mostrar o noinformación en una página Web.

Al terminar este capítulo tendrá las nociones básicasnecesarias para comprender cualquier programa escrito enPHP y, lo que es más importante, avanzará un poco máshacia el objetivo final: combinar la potencia de MySQL conla flexibilidad de PHP.

Introducción

¿Qué es PHP? A estas alturas ya sabrá que es unlenguaje de programación y que está muy vinculado conlas páginas Web que, a su vez, se escriben en el lenguajeHTML.

HTML son unas siglas que significan "lenguaje demarcas de hipertexto" (Hypertext Markup Language). Estelenguaje sirve para describir las propiedades y la ubicaciónde una serie de elementos dentro de una página Web,como texto, imágenes, etcétera.

Truco: ¿Asustado por la cant idad de siglas que se nos vienen encima? No tema,todas ellas encuentran su traducción en ht tp://www.acronymfinder.com/.

Page 33: Desarrollo Web Con PHP y MySQL

Por ejemplo, el siguiente es un fragmento de código enlenguaje HTML.

<html>

<head>

<title>Prueba</title>

</head>

<body>

<h1>Esto es una página HTML.</h1>

</body>

</html>

Este código describe una página muy sencilla. Si laguarda con el nombre prueba.html y la pone en la carpetade archivos del servidor Web, podrá ver lo que aparece enla figura 2.1.

Figura 2.1. Una página HTML muy sencilla

Nota: Si leyó el capítulo anterior y decidió seguir nuestra recomendación deut ilizar XAMPP, la carpeta de archivos del servidor Web es htdocs y seencuentra dentro de aquella en la que decidiese instalar XAMPP.

En este ejemplo puede comprobar que el lenguaje HTMLutiliza etiquetas. Estas etiquetas se distinguen del restoporque están entre los símbolos menor que (<) y mayorque (>). También puede ver cómo estas etiquetas definenla posición de los elementos: si un determinado texto estáentre las etiquetas head y title aparecerá en la barra detítulo del cliente Web que esté utilizando, mientras que laetiqueta h1 permite indicar que el texto será unencabezado de nivel 1.

Consejo: Se supone que si está leyendo esta guía es porque ya t iene unasnociones básicas de HTML. Si no es el caso, no se preocupe, puede seguirleyendo sin miedo a perderse.

Como ya sabrá, una de las características másinteresantes de las páginas HTML es la posibilidad dehacer referencia a otras páginas mediante hiperenlaces(hyperlinks), a los que abreviadamente se les llamaenlaces. Mediante estos enlaces podemos vincular unaspáginas con otras que pueden estar en nuestro sitio Web oen otro diferente. Independientemente de la calidad delcontenido de una página, de su interés, son estasrelaciones entre diferentes páginas las que hacen de laWeb una herramienta verdaderamente única.

Muy por encima, hemos visto qué son las páginas HTML:

Page 34: Desarrollo Web Con PHP y MySQL

archivos de texto con unas etiquetas especiales quedeterminan la posición y el formato de sus elementos.¿Cómo encaja PHP en todo esto?

PHP son también unas siglas, que vienen de PHP:Hypertext Preprocessor (preprocesador de hipertexto). Sonunas siglas recursivas: están dentro de la definición, unchiste de informáticos que difícilmente hace gracia al restodel mundo. La figura 2.2 muestra el reconocible logotipo dePHP.

Figura 2.2. El logot ipo de PHP

Como su propio nombre indica, PHP es un preprocesadorde hipertexto. Es decir, con PHP puede crear programascuyo resultado sea código HTML. Ese resultado puedevariar en función de la lógica del programa. Comoconsecuencia, el resultado de una misma página PHPpuede ser distinto dependiendo de algunos factores.

Un ejemplo puede ayudarnos a entender mejor para quésirve PHP. Y nada más sencillo que crear una página quemuestre la hora. El siguiente código realiza esta tarea:

La hora es: <?= date('H:i:s') ?>.

El resultado se puede ver en la figura 2.3.

Figura 2.3. La hora, con PHP

Si recarga la página, pulsando F5, comprobará que lahora ha cambiado. El contenido de la página depende de lahora a la que ésta se cargue. Por eso a las páginas PHP selas conoce como páginas dinámicas, frente a las páginasHTML, que son estáticas.

Nota: Aunque vamos a concentrarnos en las capacidades de PHP para producirpáginas Web, tenga presente que no es lo único que puede hacer. Por poner unejemplo, PHP también puede usarse para crear aplicaciones de escritorio. Puedevisitar ht tp://gtk.php.net/ si desea más información al respecto.

Vamos a intentar aclarar aún más las diferencias quehay entre HTML y PHP.

Como ya sabrá, cuando utiliza un cliente Web (comoInternet Explorer o Firefox) para ver una página hay treselementos en juego: usted, el medio (Internet) y el servidorWeb. Seguramente lo primero que hace es escribir la

Page 35: Desarrollo Web Con PHP y MySQL

dirección de la página que quiere ver (su URL) y, acontinuación, pulsar la tecla Intro.

En ese momento, a través de Internet, se envía lapetición al servidor. Éste localiza esa página y la devuelvetal y como la encuentra. La figura 2.4 ilustra el proceso.

Figura 2.4. Una página estát ica

El proceso es ligeramente diferente si se trata de unapágina PHP. Todo es igual hasta que el servidor localiza lapágina que le pedimos. El servidor se da cuenta de que suextensión no es la de una página HTML. Sabe que tieneque procesarla antes de devolverla, así que invoca alpreprocesador de PHP y le pasa el control.

Este preprocesador busca algunos caracteres especiales.Allí donde los encuentre, realizará las operaciones que elcreador de la página haya indicado. Cuando termine deprocesar la página, devolverá el resultado, que será lo queel servidor Web envíe como respuesta a quien le hayapedido la página PHP. Algo parecido a lo que podemos veren la figura 2.5.

Figura 2.5. Una página dinámica

Sólo hay una diferencia entre las figuras 2.4 y 2.5, perocomo sabe se trata de una muy importante.

Ahora que hemos abierto boca, seguro que tiene ganasde más. En un momento iremos a ello, pero antes vamos abuscar algunas herramientas que puedan ayudarle en latarea.

Editores

Page 36: Desarrollo Web Con PHP y MySQL

Para programar en PHP sólo hace falta un editor detexto, como el bloc de notas de Windows, vi en Linux oTextEdit en Mac OS X. Sí, también hace falta un servidorde páginas Web, pero se supone que ya contamos con él.

Aunque estos son ejemplos de editores de textodecentes, son precisamente eso y sólo eso, editores detexto. Y nada más. Existen otras herramientasdesarrolladas exclusivamente para editar PHP que puedenser de mucha más ayuda en las tareas de programación.Un editor de estas características no es sólo un editor: esun entorno de desarrollo o IDE (Integrated DevelopmentEnvironment, entorno integrado de desarrollo).

Como es costumbre en el mundo del software libre, lasalternativas son muchas. Posiblemente el más completode todos sea Zend Studio. Si puede permitirse pagar loscasi 400 euros que cuesta, no lo dude: evalúelo y adquierauna copia si lo encuentra satisfactorio.

Pero, como decimos, existen muchas otras alternativas.Nuestra recomendación es que utilice Eclipse PDT (enconcreto, la versión 2), un producto multiplataforma libreque puede encontrar en la dirección:

http://eclipse.org/pdt/

Nota: Repet imos, existen muchas otras alternat ivas tanto a Zend Studio como aEclipse PDT. Entre, por sólo mencionar algunas, están NetBeans, Aptana PHP,Codelobster o Nusphere PhpED. Pero no se limite a estas, una búsqueda enGoogle bastará para que encuentre más editores de PHP. Más que la potenciadel editor, la clave es que encuentre uno con el que se sienta cómodo.

Casi todos los IDE tienen muchas características encomún. Si el IDE que va a utilizar no es ninguno de los quele hemos recomendado, asegúrese de que, como mínimo,le proporciona las siguientes herramientas:

Resalte de sintaxis: Las palabras clave del lenguaje,las cadenas de texto, los comentarios, cada diferenteelemento del código fuente de un archivo PHP, tendráun color diferente, algo de gran ayuda para encontrardeterminadas secciones de código, localizar errores,etcétera. Aunque más avanzado el capítulo veremosejemplos en los que el resalte de sintaxis será másobvio, queremos enseñarle en la figura 2.6 el aspectoque tiene el fragmento de código que dio comoresultado la página que pudimos ver en la figura 2.3.Fíjese en que el color de las etiquetas <? y ?> y de loque aparecen entre comillas simples es diferente delresto.

Figura 2.6. Resalte de sintaxis

Page 37: Desarrollo Web Con PHP y MySQL

Asistente de código para nombres de función: Elnúmero de funciones que PHP pone a su disposiciónes, a falta de mejores palabras, realmente asombroso.Y una memoria asombrosa hace falta para recordar elnombre de todas ellas. A medida que escriba, unasistente de código permitirá ver en una listadesplegable cuántas funciones comienzan con loscaracteres que ha escrito, como puede verse en lafigura 2.7, donde aún sin haber terminado de escribir elnombre de la función date(), el IDE ya le muestra sunombre completo. Esta característica no hacenecesario saber el nombre exacto de una función,basta con saber al menos cómo empieza para obteneruna lista de la que seleccionar la que desee. El númerode errores que cometa al escribir su código será menorsi utiliza esta característica cuando no esté seguro deun nombre.

Figura 2.7. Lista de funciones

Asistente de código para argumentos de función: Deforma similar al asistente para nombres de función, elde argumentos muestra la lista de argumentos queadmite una función, nada más escribir el paréntesis acontinuación de su nombre. Bueno, la verdad es queaún no hemos visto qué es una función, pero no sepreocupe que sus preguntas tendrán respuesta. Porahora baste con decir que las funciones permitenobtener valores o realizar tareas concretas. En elejemplo con el que mostramos la hora en una páginaWeb utilizamos la función date(). La figura 2.8 muestraun asistente de código para argumentos en plenaacción con dicha función. Podrá ver tanto losargumentos como el valor que devuelve la función.

Figura 2.8. Argumentos de una función

Ayuda integrada: Los dos asistentes para funcionesson muy útiles. A medida que programe con PHP leresultarán hasta imprescindibles. Pero no hay nada

Page 38: Desarrollo Web Con PHP y MySQL

que pueda sustituir a un buen sistema de ayudaintegrada en el entorno de desarrollo. Este sistema lepermite obtener ayuda sobre PHP (sintaxis, funciones,etc.) sin tener que vagar por la documentación en líneade PHP. Por ejemplo, en Eclipse PDT bastaría consituar el putero del ratón la función date() para obtenertoda la ayuda disponible en la documentación sobredicha función, precisamente como muestra la figura2.9.

Figura 2.9. Ayuda integrada

Nota: Por supuesto, cualquier otra ayuda a la programación será bienvenida.Pruebe todo aquello que pueda hacer más product ivo su trabajo, juegue contodas las característ icas que el IDE con el que trabaje le proporcione, personaliceel entorno de trabajo hasta que lo sienta como suyo propio.

Ahora que ya dispone de un editor de códigomedianamente decente para trabajar con PHP ¡comienzala diversión!

Estructura de un archivo PHP

Un archivo PHP no es más que un archivo de texto. Noes necesario compilarlo, puede leerse con cualquier editorde texto.

Lo primero que tiene que saber sobre un archivo PHP esque podría contener sólo HTML y seguiría siendo unarchivo PHP válido. Como vio en el anterior apartado,cuando alguien pida una página de estas características, elservidor Web se la pasará al preprocesador de PHP. Éstebuscará fragmentos de código PHP. Al no encontrarninguno, el resultado será la página PHP tal y como larecibió el preprocesador.

Por lo general, éste no será el caso. Lo normal es que enuna misma página coexistan HTML y PHP. Pero, ¿cómo sediferencia el código PHP del código HTML?

Escapar de HTML

Parece el título de una película, pero no lo es. Se diceque estamos "escapando de HTML" cuando escribimos unaserie de caracteres que le indican a PHP que lo queaparece a continuación será código PHP.

Como ya sabe, el preprocesador deja pasar tal cual eltexto en formato HTML, pero ejecuta las instrucciones

Page 39: Desarrollo Web Con PHP y MySQL

texto en formato HTML, pero ejecuta las instruccionesPHP. Cuando escapa de HTML entra en PHP.

Ya hemos visto un ejemplo de cómo escapar de HTMLen el primer fragmento de código PHP de este capítulo:

La hora es: <?= date('H:i:s') ?>.

En la anterior instrucción, PHP deja pasar tal cual todo eltexto hasta llegar a los caracteres <?. Sabe que todo lo queencuentre desde ese momento hasta que aparezca lapareja de caracteres ?> será PHP. Y esta operación serepite hasta llegar al final del archivo.

Existen varias formas de escapar de HTML, peronosotros sólo vamos a comentar dos:

1. <?php ... ?>2. <? ... ?>

De estas dos, la más recomendable es la primera, porvarias razones:

Con independencia de la configuración de PHP,siempre debería ser posible escapar de PHP de esaforma, algo que no es cierto para la segunda, quepuede estar desactivada.Una página PHP que utilice la primera forma es,además, una página que cumple el estándar XHTML,algo que puede ser útil en determinadas situaciones.

Por ello, en adelante, utilizaremos la primera vía deescape de HTML: <?php ... ?>.

De forma que una página PHP puede ser como unapágina HTML normal y corriente, con una salvedad: enaquellas partes en las que quiera introducir algún valor quese genere de forma dinámica, escapará de HTML paraentrar en PHP.

Nota: Con el paso de las páginas, descubrirá que mientras mayor sea el proyectopara el que esté empleando PHP, más complicado será t rabajar mezclando HTMLy PHP, sobre todo si el grupo de trabajo lo conforman varios programadores ydiseñadores. El capítulo dedicado a las plant illas propone algunas solucionesinteresantes que le recomendamos.

Funciones de salida

Aunque hablaremos de las funciones en general conposterioridad, vamos a ver ahora las que se utilizan paramostrar información en la página HTML resultante deprocesar una página PHP, ya que nos serán de muchautilidad.

Ya hemos utilizado una de ellas: <?= es una forma máscorta de escribir <? echo. Por lo tanto, estas dos líneas decódigo son equivalentes:

La hora es: <?= date('H:i:s') ?>.

La hora es: <? echo date('H:i:s') ?>.

Page 40: Desarrollo Web Con PHP y MySQL

De igual forma puede utilizar la función print() para queel parámetro que le pase se muestre en la página HTMLresultante:

La hora es: <? print(date('H:i:s')) ?>.

Aunque existen otras funciones para mostrarinformación, dejaremos para otro momento hablar de ellas.

Comentarios

PHP nos permite escribir texto que el preprocesadorignorará, lo que se conoce como comentarios. Loscomentarios son útiles para explicar qué intentamos hacera lo largo de un determinado programa. Algo que hoy nosparece obvio puede ser difícil de entender cuandovolvamos a ver el código pasados unos meses.

Existen dos tipos de comentarios: de línea y de párrafo.Si comenzamos una línea con la pareja de caracteres //,esa línea será tomada por PHP como un comentario.

No nos cuesta ningún esfuerzo modificar el programaque muestra la hora para añadir comentarios de estaforma:

<?php

// El siguiente programa muestra la hora

// actual.

//

// La función date() recibe como parámetro el

// formato en el que se mostrará. La hora se

// representa como H y los segundos como s,

// pero atención que para los minutos se

// utiliza i y no m.

//

// Las horas, los minutos y los segundos se

// separarán con dos puntos.

?>

La hora es: <?= date('H:i:s') ?>.

La página HTML resultante del código anterior esexactamente la misma que se puede ver en la figura 2.3, apesar de la existencia de comentarios al comienzo.

Los comentarios de párrafo comienzan con la pareja decaracteres /* y terminan con */. Todo lo que PHP encuentreen medio lo considerará un comentario, así que podemosvolver a escribir el código anterior así:

<?php

/*

El siguiente programa muestra la hora actual.

La función date() recibe como parámetro el

formato en el que se mostrará. La hora se

representa como H y los segundos como s, pero

atención que para los minutos se utiliza i y

no m.

Page 41: Desarrollo Web Con PHP y MySQL

Las horas, los minutos y los segundos se

separarán con dos puntos.

*/

?>

La hora es: <?= date('H:i:s') ?>.

El resultado seguirá siendo el mismo. El resalte desintaxis también tiene en cuenta los comentarios,mostrándolos de un color diferente al del resto del código.El último fragmento de código se puede ver resaltado en lafigura 2.10.

Figura 2.10. Comentarios resaltados

Truco: Lo más probable es que su IDE permita cambiar los colores de resalte decada t ipo de elemento del código PHP. Le recomendamos que seleccione un colorlo más apagado posible para los comentarios, pero que sea legible. De esta forma,podrá ignorarlos sin dificultad cuando no le sean necesarios, pero podrá leerlos silo desea.

Otra costumbre saludable es comenzar sus programascon un encabezado común. Este encabezado podríacontener el nombre del autor del código, la fecha en la quecomenzó a escribirlo y una breve descripción del objetivode dicha página. Cuando usted, o cualquier otra personavuelva a trabajar con esa página sabrá sólo con echar unvistazo al encabezado contra el trabajo de quién va aluchar, la antigüedad del mismo y podrá partir con ventajaal conocer de mano del autor algo sobre el funcionamientode la página.

Podemos modificar la página PHP de prueba para queincluya ese encabezado. El resultado podría ser elsiguiente:

<?php

/*

Autor:

Juan Diego Gutiérrez Gallardo

Fecha:

miércoles 24 de junio de 2009

Descripción:

El siguiente programa muestra la hora

actual.

Se trata de un ejemplo de página

Page 42: Desarrollo Web Con PHP y MySQL

Se trata de un ejemplo de página

dinámica muy sencillo.

La función date() recibe como parámetro el

formato en el que se mostrará. La hora se

representa como H y los segundos como s,

pero atención que para los minutos se

utiliza i y no m.

Las horas, los minutos y los segundos se

separarán con dos puntos.

*/

?>

La hora es: <?= date('H:i:s') ?>.

Nota: Quizá le interese echar un vistazo a PHPDoc, un estándar para ladocumentación de PHP con el que Eclipse PDT es compat ible. Su página Web seencuentra en la dirección ht tp://phpdoc.org/. Por cierto, ésta ha sido la últ ima vezque ut ilizamos la forma abreviada de escapar de HTML.

Hemos comentado que a partir de una sola página PHPpuede obtener diferentes páginas HTML, dependiendo delas circunstancias. En el ejemplo anterior, como el tiempova pasando, los segundos avanzando, cada vez que carguela página el resultado será diferente.

Nuestras posibilidades estarían muy limitadas si esofuese todo lo que podemos hacer en PHP.

A continuación veremos qué son las variables y de quétipo las hay. Gracias a ellas nos acercaremos aún más adescubrir el verdadero potencial que hay tras PHP.

Variables

Los datos no son etéreos, es necesario almacenarlos enalgún lugar. Una variable es el lugar en el que vamos aguardar los valores que necesitaremos más adelante, yasea para consultarlos o para modificarlos. En la jerga delos programadores, reservar el espacio necesario paraguardar dichos valores se conoce como "declarar unavariable". Este espacio se encuentra en la memoriaprincipal del ordenador, es decir, en la RAM.

Una variable tiene un nombre, un tipo y un valor. Paradiferenciar las variables de otros elementos dentro dePHP, el nombre de éstas comienza siempre con el símbolodel dólar ($). El primer carácter a partir del $ debe ser unaletra o un carácter de subrayado (_). Después puede incluirnúmeros.

Advertencia: Y mucho cuidado: PHP diferencia entre mayúsculas y minúsculas.

Para declarar una variable en PHP sólo tiene que escribirel nombre de la variable y asignarle un valor. Por ejemplo:

<?php

Page 43: Desarrollo Web Con PHP y MySQL

<?php

$hora = date('H:i:s');

?>

Advertencia: Es posible que se haya fijado en que aparece un punto y coma alfinal de la línea en la que se asigna un valor a la variable $hora. En PHP, unalínea de código se diferencia de la siguiente ut ilizando precisamente dichocarácter. Se trata de algo muy importante, recuerde ut ilizar dicho separador.

El código anterior almacena en la variable $hora la horatal y como la mostrábamos en los ejemplos anteriores. Lassiguientes líneas son ejemplos de declaraciones correctas:

$hora = date('H:i:s');

$Hora = date('H:i:s');

$_hora = date('H:i:s');

$_1hora = date('H:i:s');

Sin embargo, esta declaración es incorrecta, ya que sunombre comienza con un número:

$1hora = date('H:i:s');

En una variable, su tipo determina la naturaleza de losdatos que almacena. ¿Qué tipos de datos nos ofrece PHP?

Tipos de datos

PHP dispone de varios tipos de datos. De todos ellosvamos a ver los que más útiles le pueden ser durante elcomienzo de su aprendizaje: tipos booleanos, enteros,decimales, cadenas y matrices.

Nota: A diferencia de otros lenguajes de programación, en PHP el t ipo de unavariable no se declara de forma explícita, sino que lo determina el valor que se leasigna para crear la variable.

Booleanos

Una variable de tipo booleano puede tener dos posiblesvalores: verdadero o falso. PHP se reserva dos palabraspara indicar esos valores: TRUE (verdadero) y FALSE(falso). Puede utilizar cualquier combinación demayúsculas y minúsculas para escribir estos valores: PHPsiempre los reconocerá.

Para declarar una variable de este tipo sólo tiene queescribir su nombre y asignarle el valor correspondiente. Enel siguiente fragmento de código declaramos dos variablesde tipo booleano:

$millonario = false;

$hipotecado = true;

Internamente, un valor booleano FALSE equivale alcero, mientras que cualquier otro valor numérico seríaequivalente al valor booleano TRUE.

Enteros

En una variable de tipo entero puede almacenar valores

Page 44: Desarrollo Web Con PHP y MySQL

enteros positivos y negativos, incluido el cero. Por ejemplo:

$i = 20;

$j = -40;

$k = 0;

Existen límites en cuanto a los valores que puedealmacenar en una variable de tipo entero. Dicho límitedepende del sistema operativo en el que PHP estéinstalado. Si intenta asignar a una variable de tipo enteroun valor superior al límite, PHP transformará de formaautomática esa variable al siguiente tipo de datos quevamos a ver, el decimal.

Decimales

Una variable de tipo decimal puede contener cualquiernúmero en coma flotante. De esta forma, la siguienteinstrucción nos sirve para declarar una variable de tipodecimal:

$pi = 3.14;

Nota: Paradójicamente, lo que llamamos número en coma flotante ut iliza comoseparador de decimales un punto. Se trata de un convenio que varía entrepaíses.

Cadenas

Y llegamos a las cadenas, posiblemente el tipo de datosque más vamos a utilizar en PHP. Esto se debe a que lamayoría de la información que se va a mostrar en unapágina HTML es de este tipo.

Una cadena de texto no más que una secuencia decaracteres. PHP permite definir cadenas de tres formasdiferentes:

1. Con comillas simples.2. Con dobles comillas.3. En bloque.

Las cadenas más sencillas son las que se especificanentre comillas simples:

$cadena = 'Esta es una simple cadena.';

Si quiere incluir una comilla simple dentro de una cadenade este tipo, debe incluir una barra invertida antes delcarácter, así:

$cadena = 'Esto es una comilla simple: \'.';

Las cadenas entre comillas dobles tienen unacaracterística añadida que las hace muy interesantes: sicontienen el nombre de una variable existente, PHPsustituirá la variable por su valor. Por ejemplo:

$i = 12;

$cadena = "Un año tienen $i meses.";

Tras ejecutar estas dos líneas, el contenido de la

Page 45: Desarrollo Web Con PHP y MySQL

variable $cadena será "Un año tiene 12 meses.".

Otra diferencia entre las cadenas con comillas simples ylas cadenas con comillas dobles son los caracteres deescape, una serie de caracteres especiales que comienzancon la barra invertida. Igual que para incluir una comillasimple utilizábamos \' en el primer tipo de cadenas,utilizaremos \" en el segundo.

Pero también puede incluir retornos de línea con \n,tabuladores con \t, el símbolo del dólar con \$, y algunosotros. Le recomendamos que consulte la documentaciónde PHP si desea más información al respecto de estoscaracteres de escape.

Truco: No se deje llevar por la tentación de rodear siempre sus cadenas entrecomillas dobles porque sean más flexibles. Esas ventajas t ienen un inconveniente:PHP tardará más en procesarlas. Ut ilice comillas simples siempre que no seanecesario ut ilizar sust itución de variables.

Pero ¡atención! Si incluye un retorno de línea en unacadena de texto y luego muestra esa cadena en la páginaWeb, no verá retorno alguno. Esto se debe a que HTMLignora los retornos de línea. Para separar su texto endiferentes líneas ha de utilizar la etiqueta <br/>. Loveremos en algunos de los ejemplos posteriores.

El tercer tipo de cadenas, en bloque, es muy similar alsegundo tipo. La diferencia principal está en la forma deutilizarlas. Se trata de la sintaxis más adecuada paracadenas de gran longitud. Y nada mejor que utilizar unejemplo para explicar cómo utilizar este tipo de cadenas:

$i = 12;

$cadena = <<<CADENA

Esto es una cadena

definida en bloque.

Podemos utilizar variables como

en las cadenas de dobles comillas.

Esto es un ejemplo: $i.

CADENA;

Podríamos haber definido esa cadena utilizando doblescomillas, así:

$i = 12;

$cadena = "Esto es una cadena\n

definida en bloque.\n

Podemos utilizar variables como\n

en las cadenas de dobles comillas.\n

Esto es un ejemplo: $i.\n";

Es mucho más sencillo manejar este tipo de cadenas enbloque que con las dobles comillas, principalmente porqueno es necesario utilizar caracteres especiales para indicarlos retornos de línea.

Si conoce algún otro lenguaje de programación, habráobservado el trabajo con cadenas con PHP es mucho más

Page 46: Desarrollo Web Con PHP y MySQL

flexible, con más posibilidades. Esto es aún más ciertopara las matrices.

Matrices

Imagine que quiere guardar en variables el número depelículas que ha visto cada mes del año. Con lo aprendidohasta ahora podría hacerlo así:

$peliculas_enero = 9;

$peliculas_febrero = 12;

$peliculas_marzo = 21;

En otra parte del código podría utilizar estasinstrucciones para mostrar dichos valores:

echo <<<PELICULAS

Películas vistas:<br/>

- en enero: $peliculas_enero.<br/>

- en febrero: $peliculas_febrero. <br/>

- en marzo: $peliculas_marzo. <br/>

PELICULAS;

Las matrices le permiten tener esa información muchomás organizada, pudiendo acceder a través de una solavariable y utilizando un índice como modificador.

La siguiente es una de las posibles formas de declararuna matriz que contenga los tres valores anteriores:

$peliculas = array(9, 12, 21);

Hemos creado una matriz con tres elementos: el primeroes 9, el segundo 12 y el tercero 21. Al utilizar la palabrareservada array para asignar valores a la variable$peliculas, PHP comprende que queremos crear unamatriz. Examinará entonces cuántos elementos aparecenentre los paréntesis, reservando el espacio necesario parapoder guardarlos.

Para acceder a estos elementos sólo necesita indicar elíndice de cada elemento tras el nombre de la variable,entre corchetes. Podría mostrar las películas vistas encada mes con el siguiente código:

echo <<<PELICULAS

Películas vistas:<br/>

- en enero: $peliculas[0].<br/>

- en febrero: $peliculas[1]. <br/>

- en marzo: $peliculas[2]. <br/>

PELICULAS;

Nota: El primer elemento disponible en una matriz es el cero (0). Es muyimportante tenerlo en cuenta para no cometer errores al t rabajar con matrices.

Puede añadir nuevos elementos a una matriz despuésde haberla creado. Por ejemplo, para añadir el número depelículas vistas en abril:

$peliculas[] = 17;

Page 47: Desarrollo Web Con PHP y MySQL

PHP se encargará automáticamente de crear el cuartoelemento de la matriz. Para ver el contenido de la matriztras añadir este nuevo elemento, puede utilizar unafunción muy útil: print_r(), que recibe como argumento unamatriz. El código resultante podría ser el siguiente:

<?php

$peliculas = array(9, 12, 21);

$peliculas[] = 17;

print_r($peliculas);

?>

El resultado lo puede ver en la figura 2.11.

Figura 2.11. Matriz, nuevo elemento y contenido

La función print_r() nos presenta los datos que contienela matriz de una forma muy curiosa. En primer lugar nosdice que se trata de una matriz con la palabra Array. Acontinuación y entre paréntesis podemos ver loselementos que componen la matriz.

Entre corchetes aparece el índice del elemento y acontinuación, tras los caracteres =>, el valor del elemento.Así podemos ver que en la posición cero está el 9, en launa el 12, en la dos el 21 y en la tres el 17.

En realidad, tras las matrices en PHP hay mucho másque lo que parece a primera vista. Más que matrices,podríamos considerar que PHP nos proporcionadiccionarios, con los que podemos traducir de un valor aotro. En nuestro ejemplo de películas podríamos decir quequeremos traducir el 0 por un 9, el 1 por un 12 y asísucesivamente, aunque en realidad lo que queremos estraducir enero por un 9, febrero por un 12, etc. ¿No seríafantástico poder hacer esa traducción, en lugar de tenerque utilizar números? Pues podemos.

La declaración de una matriz que hemos utilizadoanteriormente es la versión simplificada de la misma, en laque sólo se asignan valores. PHP crea los índices de formaautomática, comenzando por el 0. Pero puede indicar losíndices usted mismo y no limitarse a los números.

Por ejemplo, esta sería una forma igualmente válida dedeclarar la misma matriz:

$peliculas = array(

'enero' => 9,

'febrero' => 12,

'marzo' => 21,

'abril' => 17

);

Page 48: Desarrollo Web Con PHP y MySQL

El resultado de utilizar print_r() con la matriz anteriorpuede verse en la figura 2.12.

Figura 2.12. Índices no concordantes

Nota: En algunos textos puede encontrar que a este t ipo de matriz se le llamamatriz asociat iva, porque permite asociar dos valores entre sí .

Ha de ser cauto con los índices al añadir nuevoselementos a una matriz. Si no indica índice alguno, PHPutilizará el siguiente que esté disponible, el que él creamás adecuado. Considere las siguientes instrucciones:

$peliculas = array(

'enero' => 9,

'febrero' => 12,

'marzo' => 21,

'abril' => 17

);

>$peliculas[] = 14;

Ya sabe que la última línea añade un nuevo elemento ala matriz, pero ¿qué índice tendrá ese elemento? La figura2.13 nos muestra el resultado de utilizar print_r() condicha matriz.

Figura 2.13. Matriz asociat iva

Como no hemos utilizado índice alguno, PHP haconsiderado que el más adecuado es el primero libre, elcero. Esta decisión, totalmente correcta, puede sinembargo dar lugar a confusiones, puesto que nosotrosesperaríamos que el índice del mes de mayo fuese el 5.Para evitar este tipo de situaciones, asigne nuevoselementos a una matriz ya creada indicando el índice delos mismos, utilizando la siguiente sintaxis:

$peliculas['mayo'] = 14;

Otra de las peculiaridades de las matrices de PHP frentea las de otros lenguajes es que no todos sus elementosdeben ser del mismo tipo. La matriz con la que hemosestado jugando hasta ahora sólo contenía números

Page 49: Desarrollo Web Con PHP y MySQL

enteros, pero perfectamente podríamos haber añadido unnuevo elemento de tipo cadena.

Advertencia: Que algo sea posible no quiere decir que deba hacerlo. Aunque endeterminadas circunstancias esta característ ica puede serle út il, lerecomendamos que sea ordenado y metódico al programar. Si una matrizcont iene valores enteros representando el número de películas vistas durante losmeses del año procure que todos sus elementos sean enteros.

Hemos hecho un repaso de los tipos básicos de lasvariables con las que va a trabajar en los programas dePHP. Veamos ahora cómo realizar operaciones sobre ellas.

Operadores

Por sí sola, una variable tiene utilidad. Puede asignarleun valor (por ejemplo, la hora en un formato determinado)y luego mostrarla como respuesta a quién vea su página.Pero ya sabe que puede obtener el mismo resultado sinutilizar variables.

El verdadero potencial de las variables se descubrecuando aprendemos a realizar operaciones sobre ellas. Nose trata de nada que no conozca ya: si sabe sumar, restar ymultiplicar, ya sabe qué son los operadores.

Nota: Tenga presente que PHP ofrece más operadores de los que vamos a veren esta sección. Sólo los que vamos a ver son más que suficientes para realizar lamayoría de las tareas del resto del libro. Si está interesado en aprender mássobre los operadores que veremos y los que no veremos, no dude en consultar ladocumentación de PHP.

Operador básico de asignación

Ya hemos trabajado con el operador de asignación, elsigno igual. Lo hemos utilizado en expresiones como:

$hora = date('H:i:s');

En dicha expresión, lo que está a la derecha del operadorde asignación, el signo igual, se guarda en lo que está a laizquierda.

Operadores aritméticos

Son los que aprendimos a utilizar en la escuela, parasumar, restar, multiplicar y dividir. De forma bastanteprevisible, dispone de operadores para:

Suma: +.Resta: -.Multiplicación: *.División: /.

Combinando estos operadores con el operador deasignación puede comenzar a realizar tareasverdaderamente útiles. Por ejemplo, puede calcular la

Page 50: Desarrollo Web Con PHP y MySQL

suma de dos números:

$i = 2 + 3;

echo $i;

Igual que suma valores numéricos directamente,también puede guardar esos valores en variables yposteriormente realizar la suma, así:

$i = 2;

$j = 3;

$i = $i + $j;

Existen unos operadores que combinan las asignacionescon los operadores aritméticos. Utilizando uno de estosoperadores podemos volver a escribir el fragmento decódigo anterior de esta forma:

$i = 2;

$j = 3;

$i += $j; // Equivale a $i = $i + $j.

Lo mismo puede aplicarse al resto de operadoresaritméticos, con lo que dispone de -=, *= y /=. Podríamosconsiderarlos como operadores extendidos de asignación.

Operadores de comparación

Permiten comparar dos valores. Como veremos másadelante, en el apartado dedicado a las instrucciones decontrol, nos basaremos en estas comparaciones paratomar decisiones en nuestro código. El resultado de utilizareste operador es un valor booleano (verdadero o falso), enfunción de si la comparación se satisface o no.

Para realizar comparaciones dispone de variosoperadores, que puede ver resumidos en la tabla 2.1.

Tabla 2.1. Operadores de comparación

Operación Descripción

$i == $j TRUE si son $i es igual que $j.

$i != $j (o <>) TRUE si son $i no es igual que $j.

$i < $j TRUE si $i es menor que $j.

$i > $j

TRUE si $i es mayor que $j.

$i <= $j TRUE si $i es menor o igual que $j.

$i >= $j TRUE si $i es mayor o igual que $j.

Operadores lógicos

Operan con valores booleanos, devolviendo TRUE oFALSE dependiendo de si se cumple una condición o no.Veremos cuatro operadores lógicos: and, or, xor y not.

and

El resultado de utilizar este operador sobre dos valoressólo es TRUE si los dos valores sobre los que se estárealizando la operación son TRUE. Suponiendo que lasvariables $i y $j son de tipo booleano, la tabla 2.2 muestralas posibles combinaciones.

Tabla 2.2. Posibles combinaciones de and

Page 51: Desarrollo Web Con PHP y MySQL

$i $J $i and $j

FALSE FALSE FALSE

FALSE TRUE FALSE

TRUE FALSE FALSE

TRUE TRUE TRUE

or

A diferencia del operador and, el resultado de utilizar orsobre dos valores sólo es FALSE si los dos valores sobrelos que se está realizando la operación son FALSE. Denuevo suponga que las variables $i y $j son de tipobooleano; la tabla 2.3 muestra las posibles combinaciones.

Tabla 2.3. Posibles combinaciones de or

$i $j $i or $j

FALSE FALSE FALSE

FALSE TRUE TRUE

TRUE FALSE TRUE

TRUE TRUE TRUE

xor

Devuelve TRUE cuando los dos valores son distintos.Puede verlo en la tabla 2.4.

Tabla 2.4. Posibles combinaciones de xor

$i $j $i xor $j

FALSE FALSE FALSE

FALSE TRUE TRUE

TRUE FALSE TRUE

TRUE TRUE FALSE

not

El operador not es un operador unario, puesto que seaplica a una sola variable, en contraste con el resto deoperadores lógicos que hemos visto, que son binarios. Enla tabla 2.5 puede ver los posibles valores que obtiene alaplicar este operador a una variable booleana.

Tabla 2.5. Posibles combinaciones de not

$i ! $i

FALSE TRUE

TRUE FALSE

Operadores de incremento

Y también de decremento. Gracias a estos operadorespuede simplificar operaciones como éstas:

$i = $i + 1;

$i = $i - 1;

Que son equivalentes a las siguientes:

$i++;

$i--;

Aunque ayudan a simplificar, en ocasiones pueden

Page 52: Desarrollo Web Con PHP y MySQL

complicarlo todo. PHP le deja situar estos operadoresantes y después de la variable a la que modifican, perodependiendo de dónde los coloque el resultado puedevariar. Comprobarlo es muy sencillo:

$i = 1;

$j = $i; // Tanto $i como $j valen 1.

echo $i++;

echo '<br/>';

echo ++$j;

Mientras que el resultado de la primera expresión desalida es uno, el de la segunda es dos. Esto es así porquePHP entiende que si sitúa el operador de incrementodespués del nombre de la variable, querrá realizar laoperación después del resto de operaciones (en este caso,una operación de salida), mientras que situarla antes delnombre de la variable da prioridad al incremento, que serealiza antes de cualquier operación. Por lo tanto, presteespecial atención a este tipo de operadores: puede queobtenga resultados imprevisibles si no anda con cuidado.

Concatenación de cadenas

La operación más importante que puede realizar sobreuna cadena es la concatenación: unir dos cadenas paraformar una sola. Para ello PHP ofrece un operador quepuede ver en funcionamiento a continuación:

$cadena1 = 'Esto es';

$cadena2 = 'una cadena.';

$cadena3 = $cadena1.' '.$cadena2;

echo $cadena3;

El resultado de esta operación es la cadena "Esto es unacadena.". Como habrá podido observar, el operador deconcatenación es un punto que habrá que situar entre lascadenas que quiera unir.

Igual que en las operaciones aritméticas, puedecombinar una concatenación con una asignación parasimplificar el código, así:

$cadena1 = 'Esto es';

$cadena2 = 'una cadena.';

$cadena1 .= ' '.$cadena2;

echo $cadena1;

El resultado será el mismo en ambos casos.

Precedencia de operadores

Debe estar siempre seguro del orden en el que PHPrealizará las operaciones que le indique. ¿Lo está ahora?¿Cuál será el resultado de esta operación, qué contendrá$i?

$i = 2 + 3 * 2;

¿Contendrá 10? ¿Contendrá 8? Depende de laprecedencia que tengan los operadores. En este casoconcreto, el resultado será 8, porque el operador de

Page 53: Desarrollo Web Con PHP y MySQL

multiplicación tiene prioridad sobre el de suma.

Pero ¿y si quisiera que la suma se realizase antes que lamultiplicación? Puede modificar la precedencia de losoperadores utilizando paréntesis para envolver lasoperaciones que quiera realizar antes. La operaciónanterior puede ser modificada para obtener 10 comoresultado:

$i = (2 + 3) * 2;

PHP realizará primero la operación que está entreparéntesis, cuyo resultado es cinco. A continuaciónmultiplicará ese valor por dos, y el resultado, diez, loalmacenará en $i.

Cambios de tipo

Como resultado de las diferentes operaciones querealice sobre las variables, es posible que modifique el tipode alguna de ellas. Sí, pero es normal. Imagine que realizala siguiente operación:

$i = 100; // Una variable de tipo entero.

$cadena = 'veces'; // Una cadena.

// Concatenamos el número y la cadena.

$i .= ' '.$cadena;

echo $i;

¿Cuál será el resultado de estas operaciones? En lapágina Web resultante podrá leer el texto "100 veces". ¿Haocurrido algo más? Vamos a ayudarnos de la funcióngettype(). Esta función recibe como argumento el nombrede una variable y devuelve una cadena de texto quecontiene el tipo de la variable pasada.

Cambiemos el código anterior por el siguiente:

$i = 100; // Una variable de tipo entero.

$cadena = 'veces'; // Una cadena.

echo 'Tipo de $i: ' . gettype($i) . '<br>';

// Concatenamos el número y la cadena.

$i .= ' ' . $cadena;

echo $i;

echo '<br/>';

echo 'Tipo de $i: ' . gettype($i);

Como puede comprobar, antes de la concatenación $i esde tipo entero (integer), pero después pasa a ser de tipocadena (string). Para liar aún más las cosas, resulta quetambién podemos hacer esto otro:

$cadena = 'Soy una cadena';

echo gettype($cadena) . '<br>';

$cadena = 20;

echo gettype($cadena);

Y hemos cambiado el tipo de una variable que era unacadena a un entero.

¿Qué está pasando?

Page 54: Desarrollo Web Con PHP y MySQL

PHP no permite que declare el tipo de una variable. Ensu lugar, es el contexto el que determina su tipo. Así, siasigna un valor numérico a una variable, su tipo seránumérico. Si posteriormente concatena ese valor con unacadena, el tipo resultante será una cadena.

Esta flexibilidad es muy útil, ya que permite realizarconcatenaciones entre números y cadenas sin necesidadde realizar conversiones de tipo de forma explícita. Lacontrapartida: ha de ser muy cauto si no quiere obtenerresultados imprevisibles. Si lo necesita puede comprobar eltipo de las variables utilizando la función gettype(),aunque también puede aprovecharse de otra de lascaracterísticas de PHP y forzar el tipo de las variables.

Puede obligar a que una variable de un tipo determinadose comporte como una de otro tipo con solo indicar entreparéntesis y antes de la variable el tipo que desea. Así,puede conseguir que una variable de tipo cadena secomporte como una de tipo entero:

$cadena = '10';

$entero = (integer) $cadena;

echo gettype($cadena);

echo '<br/>';

echo gettype($entero);

Lo mismo puede aplicarse al resto de tipos, cuyosnombres en inglés puede consultar en la documentaciónde PHP.

Tenga precaución, sin embargo. En el ejemplo anterior$entero contendrá el valor entero 10, pero si $cadenahubiese contenido la cadena "texto", el resultado seríaque $entero contendría el valor 0:

$cadena = 'texto';

$entero = (integer) $cadena;

echo $entero;

Por regla general, si la conversión entre tipos no resultaposible, PHP asignará valores predeterminados, como elcero o una cadena vacía.

Hay que reconocer que, hasta ahora, lo que hemos vistoen este capítulo no ha sido muy divertido. Peroprometemos que esto va a cambiar, porque en lossiguientes apartados vamos a examinar las instruccionesde control, que utilizan las variables que acabamos de verpara conseguir que el contenido de la página HTMLresultante de procesar la página PHP sea dinámico.

Instrucciones de control

En un programa escrito en PHP las instrucciones decontrol constituyen las herramientas más importantespara hacer que sus páginas sean dinámicas. Son estasinstrucciones las que le permiten evaluar el contenido delas variables y tomar decisiones en consecuencia.

Page 55: Desarrollo Web Con PHP y MySQL

Sí, hemos visto cómo crear una página en la que apareceun elemento que cambia en cada llamada, la hora. Pero¿no sería mucho más interesante poder cambiar elcontenido de la página dependiendo de la hora? Porejemplo, podríamos mostrar un mensaje de saludo. Estemensaje podría decir "Buenos días" si la hora está entrelas 8 y las 14, "Buenas tardes" desde las 14 hasta las 19 y"Buenas noches" de las 19 hasta las 8.

Pues esto y mucho más es lo que vamos a conseguir conlas instrucciones de control, de las que existen dos tipos:las condicionales y las iterativas.

Instrucciones condicionales

Como su propio nombre indica, permiten determinar quéacciones realizar en función de una condición. La mássimple de este tipo de instrucciones es if, que en suexpresión más sencilla tiene este aspecto:

if (condición)

acción

PHP evalúa la condición. Si el resultado de estaevaluación es TRUE, la acción asociada se ejecutará. Encaso contrario, la acción se ignora y no se ejecuta.

Por ejemplo, puede almacenar la hora en una variable.Ya sabe cómo hacerlo. Después puede comparar ese valorcon uno en concreto, algo que también sabe hacer graciasal trabajo que ha realizado con los operadores. Y,entonces, si ambos valores coinciden, realizará la acciónque haya escrito.

Concretando aún más, si la hora es menor que las 12,escriba un mensaje indicando que aún no es mediodía.Algo así:

<?php

$hora = date('H');

if ($hora < '12')

echo 'Aún no es mediodía.';

?>

El resultado del código anterior variará dependiendo desi vemos la página antes o después de las 12. De hecho, sila vemos después de las 12, la página estará en blanco.Puede mejorar este pequeño programa utilizando elsejunto con if. Así podrá indicar la acción a seguir en caso deque la condición no se cumpla:

<?php

$hora = date('H');

if ($hora < '12')

echo 'Aún no es mediodía.';

else

echo 'Ya es mediodía.';

?>

¡Esto marcha! Ahora el que vea la página siempreobtendrá un mensaje... aunque no se trata de un mensaje

Page 56: Desarrollo Web Con PHP y MySQL

muy exacto si lo ve pasadas las 12, digamos a las 8 de latarde. A esa hora ya no es mediodía, ¿verdad?

Para ser más precisos en nuestros mensajes, vamos autilizar una nueva instrucción condicional, elseif, quepermite evaluar una nueva condición en caso de que laanterior no se cumpliese. Podemos entonces ejecutarinstrucciones cuando aún no sean las 12, cuando ya hayanpasado las 12 y (el caso que no cubríamos) cuando seanlas 12 en punto:

<?php

$hora = date('H');

if ($hora < '12')

echo 'Aún no es mediodía.';

elseif ($hora == '12')

echo 'Ya es mediodía.';

else

echo 'El mediodía ya pasó.';

?>

Las instrucciones condicionales pueden anidarse, esdecir, pueden escribirse unas dentro de otras, gracias a loque podemos volver a escribir el código anterior así:

<?php

$hora = date('H');

if ($hora < '12')

echo 'Aún no es mediodía.';

else

if ($hora == '12')

echo 'Ya es mediodía.';

else

echo 'El mediodía ya pasó.';

?>

Ahora, una pregunta con trampa. Examine estefragmento de código y díganos el resultado si se ejecutaantes de las 12 del mediodía:

<?php

$hora = date('H');

if ($hora < '12')

echo 'Aún no es mediodía.';

else

echo 'Es mediodía.';

echo '¡Queda menos para ir a comer!';

?>

Si su respuesta fue que sólo veremos el texto "Aún no esmediodía", ¡la respuesta no es correcta! Aunque el fallo noserá por desconocimiento, si no porque no le hemos dichoque a cada parte de la condición sólo se asocia unainstrucción. Es decir, la última línea, la que nos avisa quequeda menos para ir a comer, se ejecuta siempre, secumpla o no se cumpla la condición.

Para solucionar ese problema puede utilizar las llaves({}), que permiten asociar grupos de líneas a cada parte dela condición. Su respuesta sería correcta si volviésemos a

Page 57: Desarrollo Web Con PHP y MySQL

escribir el código anterior así:

<?php

$hora = date('H');

if ($hora < '12'){

echo 'Aún no es mediodía.<br/>';

}else{

echo 'Es mediodía.<br/>';

echo '¡Queda menos para ir a comer!<br/>';

}

?>

Nota: Le recomendamos que siempre ut ilice llaves con sus instruccionescondicionales if, aunque a cada parte sólo asocie una línea de código. Podríaolvidar incluirlas si más adelante decide añadir una línea más alguna de las partesde la condición, lo que podría provocar un fallo en la lógica de su programa.

Utilizando instrucciones if y else puede complicar elprograma anterior todo lo que quiera; por ejemplo,comprobando la hora y escribiendo mensajes en funciónde la misma. Así, para informar de que a las 9 de lamañana entra a trabajar, a las 14 sale a comer, a las 16vuelve a entrar y a las 19 se va para casa escribiría elsiguiente código:

<?php

$hora = date('H');

if ($hora == '9'){

echo 'Bienvenido al curro.';

}elseif ($hora == '14'){

echo 'Que aproveche.';

}elseif ($hora == '16'){

echo 'Lástima de siesta...';

}elseif ($hora == '19'){

echo 'Hasta mañana.';

}

?>

PHP nos proporciona otra instrucción condicional quepermite escribir un programa equivalente al anterior, perode forma más clara: la instrucción switch. El resultado deutilizarla sería el siguiente:

<?php

$hora = date('H');

switch ($hora){

case '9':

echo 'Bienvenido al curro.';

break;

case '14':

echo 'Que aproveche.';

break;

case '16':

echo 'Lástima de siesta...';

break;

case '19':

echo 'Hasta mañana.';

Page 58: Desarrollo Web Con PHP y MySQL

echo 'Hasta mañana.';

break;

}

?>

Como puede comprobar, le indicamos a la instrucciónsobre qué variable se realizarán las comparaciones.Después escribimos las instrucciones asociadas a cadacaso. PHP recorrerá cada instrucción case, comparando elvalor de $hora con el valor correspondiente. Si soniguales, ejecutará las instrucciones asociadas con ese casey terminará de ejecutar la instrucción switch.

Nota: La instrucción break es la que marca la salida del switch. De ellahablaremos más adelante.

Incluso puede indicar qué hacer en caso de que no secumpla ninguna de las condiciones, es decir, cuando nohaya un case que satisfaga la igualdad. Puede utilizar lainstrucción default, con lo que el código resultantemostraría un mensaje de su elección cuando la página sevea a una hora que no esté contemplada:

<?php

$hora = date('H');

switch ($hora){

case '9':

echo 'Bienvenido al curro.';

break;

case '14':

echo 'Que aproveche.';

break;

case '16':

echo 'Lástima de siesta...';

break;

case '19':

echo 'Hasta mañana.';

break;

default:

echo 'A trabajar.';

}

?>

Instrucciones iterativas

Estas instrucciones permiten ejecutar un bloque decódigo tantas veces como sea necesario, mientras secumpla una determinada condición.

Bucle For

La primera que vamos a ver es la instrucción for, quepermite ejecutar un bloque de instrucciones un númeroconcreto de veces. La sintaxis de esta instrucción es lasiguiente:

for (expresión1; expresión2; expresión3)

acción

Page 59: Desarrollo Web Con PHP y MySQL

Cuando PHP encuentra una de estas instrucciones, loprimero que hace es evaluar expresión1. Esto sólo sehace la primera vez.

Cada vez que se dé una vuelta en la instrucción deiteración, se evaluará expresión2. Las iteracionescontinuarán mientras se evalúe como TRUE. Cada vez quese termine una vuelta en la instrucción de iteración seevaluará expresión3.

Resumiendo:

expresión1: Sólo una vez, al comienzo del bucle.expresión2: Antes de comenzar cada iteración.expresión3: Al terminar cada iteración.

El siguiente fragmento de código contiene un bucle forque se ejecuta tres veces. Cada vez que lo hace, escribe elmismo texto:

<?php

for ($i = 1; $i <= 3; $i++){

echo 'Probando un bucle for...<br/>';

}

?>

Cuando PHP encuentra el bucle for, asigna 1 a lavariable $i. Sólo lo hace la primera vez. A continuación,comprueba que $i no sea mayor que 3. Como $i contiene1, la condición se cumple, así que ejecuta la instrucciónecho().

Al encontrar el cierre de llave descubre que la primeraiteración ha terminado, así que vuelve al comienzo delbucle y evalúa la tercera de las expresiones, queincrementa en uno el valor de $i.

Segunda iteración: comparamos el valor de $i con 3,pero como $i vale 2, después de haber sido incrementada,la condición se cumple. Volvemos a ejecutar la instrucciónecho(), a incrementar el valor de $i, a compararlo con 3 y aejecutar la instrucción echo.

La cuarta vez que pasemos por la comparación, $i valdrá4, la comparación se evaluará como FALSE y habráterminado la ejecución del bucle for. El resultado deejecutar este código puede verse en la figura 2.14.

Figura 2.14. Ejecución de un bucle for

El siguiente es un ejemplo mucho más vistoso de bucle

Page 60: Desarrollo Web Con PHP y MySQL

for:

<?php

for ($i = 1; $i <= 3; $i++){

echo '<h'.$i.'>Bucle for</h'.$i.'>';

}

?>

En la figura 2.15 puede ver el efecto del código anterior.

Figura 2.15. Encabezados dinámicos

Un bucle for puede utilizarse para recorrer todos loselementos de una matriz y mostrar su contenido. Esamatriz podría ser, por ejemplo, la que contenía laspelículas vistas durante cada mes:

<?php

$peliculas = array(

'enero' => 9,

'febrero' => 12,

'marzo' => 21,

'abril' => 17

);

// ¿Cuántos meses hay en la matriz?

$meses = count($peliculas);

for ($i = 1; $i <= $meses; $i++){

echo $i . ': ' . $peliculas[$i] . '<br/>';

}

?>

Vaya, el resultado de ejecutar este bucle no es elesperado. Claro, resulta que los índices utilizados no sonnúmeros, son cadenas de texto. Vamos a solucionarloutilizar otra instrucción de iteración: foreach.

Bucle For Each

Traducido como "para cada", con foreach puede recorrertodos los elementos de una matriz sin necesidad de sabercuántos elementos la componen.

Puede utilizar este bucle así:

foreach (matriz as $valor)

acción

El bucle se ejecutará tantas veces como elementostenga la matriz. En cada iteración, se avanzará al siguienteelemento, cuyo valor se irá guardando dentro de $valor.

Page 61: Desarrollo Web Con PHP y MySQL

Dentro del bloque de código asociado al bucle puederealizar operaciones con ese valor.

Pero también puede ejecutar el bucle foreach de estaotra forma:

foreach (matriz as $clave => $valor)

acción

Con esta segunda forma también tendrá acceso al valordel índice asociado con el valor. Esto le puede ser demucha utilidad en el ejemplo de las películas por mes:

<?php

$peliculas = array(

'enero' => 9,

'febrero' => 12,

'marzo' => 21,

'abril' => 17

);

foreach ($peliculas as $mes => $vistas){

echo

'En ' . $mes .

' vi ' . $vistas . '.<br/>';

}

?>

Puede ver el resultado de usar foreach en la figura 2.16.

Figura 2.16. Uso de foreach

Las dos instrucciones de iteración que acabamos de verse ejecutan un número determinado de veces, que puedeser conocido previamente. PHP ofrece otras dosinstrucciones de control que iteran mientras se cumplanuna serie de condiciones: los bucles while y do while.

Bucles While

En su forma más sencilla, el bucle while sigue lasintaxis:

while (condición)

acción

Es decir, mientras se cumpla la condición, ejecutamos laacción. Esta acción puede ser un bloque de instruccionesenvuelto entre llaves. La acción puede modificar losfactores que se evalúan en la condición para que, en unmomento dado, la condición no se cumpla y se pueda salirdel bucle.

Page 62: Desarrollo Web Con PHP y MySQL

Por ejemplo, puede crear un bucle de este tipo quemantenga el control mientras el segundo de la hora en laque nos encontremos no sea cero:

<?php

$segundo = date('s');

while($segundo != '0'){

$segundo = date('s');

}

echo 'Comienza un nuevo minuto.';

?>

Este sencillo programa guarda en la variable $segundoel segundo en el que se encuentra. A continuación,comienza el bucle while. Compara el segundo actual concero. Si no es cero, entre en el cuerpo del bucle, dondevuelve a obtener el valor del segundo.

PHP vuelve a comparar el contenido de la variable$segundo con cero y sigue iterando mientras se cumpla lacondición. Pero tarde o temprano no se cumplirá. Cuandoeso ocurra, terminará la ejecución del bucle y llegará a lainstrucción echo, que le muestra un mensaje.

La otra variante de este bucle sigue la siguiente sintaxis:

do

acción

while(condición)

Este bucle sigue las mismas premisas que el anterior,pero con algunas salvedades que comprenderemos mejorcon un ejemplo:

<?php

do{

$segundo = date('s');

}while($segundo != '0');

echo 'Comienza un nuevo minuto.';

?>

El resultado de este bloque de código es ligeramentediferente al anterior, aunque buscamos el mismo objetivo.Dejando a parte diferencias de sintaxis, el cuerpo del bucledo while se ejecuta al menos una vez, mientras que en elbucle while podría darse el caso de que el cuerpo del bucleno se ejecutase ninguna si $segundo valiese cero desdeel principio.

Por lo tanto, debe utilizar do while cuando quiera que elcuerpo del bucle se ejecute al menos una vez y while encaso contrario.

Advertencia: Asegúrese de que siempre exista un camino de salida de estosbucles. En caso contrario PHP no podría terminar la ejecución del bucle y elprograma se ejecutaría indefinidamente. Como consecuencia, la página Webnunca le sería devuelta al que desee verla.

Salida de bucles

Page 63: Desarrollo Web Con PHP y MySQL

Es posible alterar el flujo de la ejecución de un buclemediante algunas instrucciones especiales. Una de ellasya la vio cuando aprendió a utilizar la instrucción switch:se trata de break.

break

Puede utilizar esta instrucción para detener la ejecuciónde los bucles for, foreach, while y do while. Cuando PHPencuentra esta instrucción dentro del cuerpo de códigoasociado al bucle entiende que quiere salir de él ycontinuar con el resto de líneas del programa.

Podría utilizar esta instrucción en un bucle do while delque quiera salir antes de que se cumplan todas lasiteraciones. En el ejemplo anterior, suponga que no quiereestar esperando demasiado tiempo a que acabe el minuto.Si está en los primeros diez segundos del minuto y noquiere permanecer dentro del bucle el código resultantesería el siguiente:

<?php

do{

$segundo = date('s');

if ($segundo <= '10'){

break;

}

}while($segundo != '0');

echo 'Comienza un nuevo minuto.';

?>

continue

Utilice continue cuando quiera saltarse el resto delíneas de código asociadas a un bucle y continuar con lasiguiente iteración. Podría utilizarlo en el ejemplo de laspelículas vistas cada mes. Si en alguno de los meses no sevio ninguna película se continuará con la siguienteiteración y no se mostrará información alguna. Hemosmodificado el mes de marzo para que el número depelículas sea cero:

<?php

$peliculas = array(

'enero' => 9,

'febrero' => 12,

'marzo' => 0,

'abril' => 17

);

foreach ($peliculas as $mes => $vistas){

if ($vistas == 0){

continue;

}

echo

'En ' . $mes .

' vi ' . $vistas . '.<br/>';

}

?>

Page 64: Desarrollo Web Con PHP y MySQL

Como resultado, el código anterior sólo mostraráinformación sobre los meses de enero, febrero y abril.

¡Enhorabuena! Acaba de pasar por un intenso curso deaprendizaje de PHP, una terapia de choque. Ha sido duro,¿verdad? Y eso que hemos dejado muchos temas en eltintero, como la escritura de funciones o cómo reutilizarcódigo.

Page 65: Desarrollo Web Con PHP y MySQL

3

MySQL

El mundo de los sistemas gestores de bases de datos haestado reservado a una élite desde el principio. Susadministradores eran considerados poco menos quemagos, dueños de sortilegios para desfacer cualquierentuerto.

Tras muchos años la situación ha cambiadoradicalmente, pero para ello han tenido que coincidir milcircunstancias.

Cuando se es nuevo en el mundo de las bases de datos,lo más complicado es llegar a entender de qué se nos estáhablando, qué es una base de datos. Y eso es algo que nose puede aprender con teoría. Es necesario pasar a laacción.

Considere este tercer capítulo como una unidadautosuficiente en la que creará su primera base de datos,que verá funcionando y sobre la que aprenderá a realizaroperaciones de inserción (para incorporar nuevos datos),consulta (para extraer información), modificación (paracambiar los datos almacenados) y borrado (para eliminardatos obsoletos o incorrectos).

En resumen, lo que veamos en este capítulo le servirápara tener una visión de conjunto de las operacionesnecesarias para manejar un sistema gestor de bases dedatos, desde los cimientos hasta los procedimientos máscomplejos. En capítulos sucesivos profundizaremos enestos conocimientos, hasta completar todas las tareas quedebería controlar o, al menos, conocer, para desempeñarsu trabajo con MySQL y PHP.

Acompáñenos en el descubrimiento de las bases dedatos y, en concreto, de la más utilizada en el mundo delsoftware libre.

Bases de datos

Una base de datos es una buena forma de organizar ycompartir información. Le permite mantener todos losdatos que nos interesan en un formato tabular unificado,con diferentes tablas para cada grupo de datos concaracterísticas comunes.

Las tablas que mantienen datos que tienen que verentre si están agrupadas en un mismo contenedor: la basede datos. Quienes necesiten extraer información de esosdatos sólo tienen que realizar una consulta a la base dedatos. La figura 3.1 simboliza las relaciones entre estoselementos.

Page 66: Desarrollo Web Con PHP y MySQL

Figura 3.1. Tablas, base de datos y consulta

Nota: Fí jese en la diferencia entre datos e información. En el caso de un actor,los datos representan hechos acerca de él (su nombre, su fecha de nacimiento,etcétera). Sin embargo, la información se extrae a part ir de esos datos: en quépelículas ha part icipado, cuántas son en total, etc.

Existe un lenguaje especialmente diseñado para realizarconsultas a bases de datos. Este lenguaje, llamado SQL,es común para la mayoría de sistemas gestores de basesde datos que existen hoy en día. SQL son las siglas delenguaje estructurado de consultas (Structured QueryLanguage). Gracias a este lenguaje podemos realizarpreguntas a los servidores de bases de datos.

Desde la aparición de las redes informáticas, el modelorepresentado en la figura 3.1 se ha extendido, pudiendorealizarse varias consultas de forma simultánea y desdediferentes ubicaciones geográficas, como intentarepresentar la figura 3.2.

Page 67: Desarrollo Web Con PHP y MySQL

Figura 3.2. Consultas remotas simultáneas

Más aún, se ha desarrollado la tecnología necesaria parapublicar bases de datos a través de medios muyasequibles para el público en general. La tabla 3.1 muestralos datos de un determinado actor, John Cleese, más omenos como estarían almacenados dentro de una base dedatos. En la figura 3.3 podemos ver cómo se mostrarían enuna página Web. En concreto, se trata de la páginadedicada a ese actor en IMDb (en la direcciónhttp://imdb.com/). La publicación Web puede verse comouna forma más de permitir consultas simultáneas a travésde redes.

Tabla 3.1. Los datos de John Cleese

Campo Valor

Nombre John

Apellidos Cleese

Fecha de nacimiento 1939-10-27

Ubicación de la foto /fotos/actores/john_cleese.jpg

Page 68: Desarrollo Web Con PHP y MySQL

Figura 3.3. John Cleese en IMDb

Como puede comprobar, la página Web muestra lasreferencias que la base de datos tiene del actor, perodistribuidas de manera que sean legibles por un serhumano, presentadas de una forma más atractiva, lo quefacilita la localización de los datos que más interesantes.

Además de poder utilizar una interfaz Web para laconsulta de la información también se puede utilizar parala introducción de los datos. Este modelo de trabajo esmuy versátil: los encargados de la tarea pueden estar endiferentes ubicaciones geográficas, trabajando sobre lamisma base de datos.

Es precisamente en este tipo de aplicaciones dondeMySQL tiene mayor aceptación, en el grupo deaplicaciones conocido como LAMP: Linux, Apache, MySQLy PHP, Python o Perl, aplicaciones desarrolladas sobreLinux, con el servidor de páginas Web Apache, que utilizancomo el enlace entre las bases de datos y la Web algunode los lenguajes antes mencionados.

Nota: Apache, MySQL y los lenguajes mencionados pueden funcionar sobreWindows, lo que permite hablar también de WAMP. De hecho, a lo largo de laspáginas de este libro ut ilizaremos principalmente el sistema operat ivo deMicrosoft . La razón por la que se ha escogido Windows en lugar de Linux o MacOS X es, sencillamente, que aún sigue siendo el sistema operat ivo más ut ilizadodel mundo, lo que hace mucho más probable que usted, lector, tenga acceso a él.Sin embargo, podrá aprovechar lo que vea en este libro sin ningún esfuerzo tantoen Mac OS X como en Linux. Se lo dice alguien que trabaja con los t res a diario.

¿Qué es una tabla?

Page 69: Desarrollo Web Con PHP y MySQL

En el mundo de las bases de datos, una tabla es un"lugar" en el que se almacenan una serie de datos desimilares características. En el mundo de la carpintería esotra cosa.

Los datos pertenecientes a un mismo elemento estánorganizados en campos o columnas, cada una de undeterminado tipo. Se llama registro a cada una de las filasde una tabla.

En la figura 3.4 podemos ver un ejemplo de tabla.

Figura 3.4. Una tabla, sus campos y sus registros

Todos los datos pertenecientes a la misma columna deuna tabla (el título de las películas, por ejemplo) son delmismo tipo. En este caso concreto se trata de informaciónde texto, con una longitud máxima de 64 caracteres.

Antaño, este "lugar" con el que nos hemos referido a unatabla era un archivo y dentro de este archivo seorganizaban los datos. Hoy en día no es correctoestablecer una relación directa entre tabla y archivo, nientre base de datos y archivo ya que por cuestiones derendimiento y aprovechamiento de espacio, una base dedatos y una tabla pueden estar dispersos en variosarchivos, incluso en varios ordenadores diferentes.

Base de datos de ejemplo

Quien más y quien menos tiene alguna película en sucasa. La mayoría tiene más de una. Incluso los hay quetienen un verdadero videoclub en el salón. Si su caso eseste último seguro que no tendrá dificultad paracomprender la utilidad de una base de datos de películas:mantener un control sobre cuáles tiene en su colección,poder pasar una lista de las mismas a otros videoadictos ocontrolar a quiénes ha prestado alguna.

Estas posibilidades, ya de por sí, son interesantes. Perogracias a organizar los datos de las películas en una base

Page 70: Desarrollo Web Con PHP y MySQL

de datos obtendrá otras ventajas de forma automática,como poder consultar cuáles de sus películas fuerondirigidas por un determinado director, cuáles lasprotagoniza un determinado actor, cuáles son de undeterminado año, en definitiva, poder hacer preguntas yconseguir respuestas.

Comenzaremos la creación de la base de datos deejemplo de forma muy sencilla, almacenando sólo el títulode la película, el nombre del director y el de uno de losactores. La figura 3.5 muestra el diseño de esta tabla: elnombre de la misma en la parte superior, y una líneadescribiendo cada columna de la tabla, con el nombre a laizquierda y el tipo de datos a la derecha.

Figura 3.5. Nuestra tabla de películas

Nota: No se preocupe en absoluto por el significado de los t ipos de datos. Elobjet ivo de este ejemplo es que comprenda lo que se puede hacer con una basede datos. Más adelante veremos dichos t ipos de datos.

En esta tabla guardará los datos de las películas de sucolección. Son pocos datos, pero cubren a la perfección lonecesario para este ejemplo.

A continuación crearemos la base de datos quecontendrá los datos de las películas y, dentro de ella, latabla de películas.

Herramientas de consulta

Vamos a utilizar la más sencilla de las herramientas deconsulta a nuestra disposición, una que funciona igual encualquier sistema operativo: la consola. Para ello, si estáutilizando el sistema operativo Windows, deberá hacer clicen Inicio>Todos los programas>Accesorios>Símbolodel sistema. Si está utilizando Linux tendrá que abrir unterminal. El terminal de Mac OS X se encuentra en lacarpeta de utilidades.

Cuando tenga acceso a la consola, escriba:

mysql -u root -p

Pulse la tecla Intro. Se le pedirá que introduzca lacontraseña del usuario root. Si está utilizando XAMPPbastará que pulse la tecla Intro de nuevo, puesto que dichousuario no tiene contraseña alguna asignada. Puede verloen la figura 3.6.

Page 71: Desarrollo Web Con PHP y MySQL

Figura 3.6. Cliente de MySQL

Cuando introduzca la contraseña correcta, el programaesperará que se le indique qué órdenes desea ejecutar.

Lamentablemente, XAMPP no incluye las órdenes deMySQL en la ruta del sistema. Si utiliza Windows tendráque modificar las variables de entorno de su sistema,añadiendo la ruta en la que se encuentre MySQL instalado(por ejemplo, C:\xampp\mysql\bin\) a la variable Path. EnWindows Vista podrá llegar al cuadro de diálogocorrespondiente haciendo clic con el botón derecho sobreEquipo, en el explorador de archivos, y seleccionando laopción Propiedades del menú desplegable que aparecerá.A continuación haga clic en Configuración avanzada delsistema, en el panel de la izquierda del cuadro de diálogoque aparecerá. Podrá ver el cuadro de diálogoPropiedades del sistema. Active la ficha Opcionesavanzadas, haga clic en Variables de entorno y accederáal cuadro de diálogo Variables de entorno, que lepermitirá modificar la variable Path. Añada al final la nuevaruta y guarde los cambios realizados.

En Linux o Mac OS X, si MySQL se encontrase instaladoen /usr/local/mysql/, la orden para conectar el servidor debases de datos sería:

/usr/local/mysql/bin/mysql -u root -p

Hemos tenido que escribir la ruta completa de la ordenpara poder conectar con el servidor de bases de datos.

Si no quiere tener que escribir la ruta completa de cadauna de las órdenes de MySQL que necesite ejecutar tendráque modificar la ruta del sistema. Para ello, abra unterminal (utilizando la aplicación del mismo nombre que seencuentra en la carpeta de utilidades), escriba la ordennano .profile estando en su carpeta personal (por logeneral, es aquella en la que estará al abrir el terminal) ypulse la tecla Intro. Podrá ver una línea similar a ésta:

export PATH=/opt/local/bin:/opt/local/sbin:$PATH

Añada /usr/local/mysql/bin al final, antes de $PATH:

export PATH=/opt/local/bin:/opt/local/sbin:

/usr/local/mysql/bin:$PATH

Guarde los cambios realizados y cierre el terminal. La

Page 72: Desarrollo Web Con PHP y MySQL

próxima vez que vuelva a abrir un terminal tendrá acceso alas órdenes de MySQL sin necesidad de escribir la rutacompleta de acceso.

Creación de la base de datos

Es el primer paso, la creación de la base de datos.Aunque existen varios métodos para crear bases de datoscon MySQL, el más versátil consiste en la utilización descripts.

Un script es un fragmento de texto con instruccionespara MySQL. Por lo general, estos scripts se guardan enarchivos de texto con la extensión SQL, aunque mientrasel contenido del archivo sea correcto, la extensión no esdemasiado importante. La extensión SQL se utiliza porqueel lenguaje utilizado para escribir estos scripts esprecisamente ese, SQL, del que hablaremos con detallemás adelante.

El nombre de la base de datos que vamos a crear serávideoteca. De ello se encargan las dos primeras líneas deeste script:

DROP DATABASE IF EXISTS videoteca;

CREATE DATABASE videoteca;

USE videoteca;

DROP TABLE IF EXISTS pelicula;

CREATE TABLE pelicula (

titulo VARCHAR(64),

director VARCHAR(128),

actor VARCHAR(128)

);

Sin entrar a comentar el significado de cada línea deeste script, ya se puede apreciar que parece que estemosdando órdenes en inglés. Si ha trabajado con algúnlenguaje de programación verá que éste no se parece aninguno que conozca, está mucho más próximo al lenguajenatural que a uno de programación.

Nota: Habrá notado que estamos escribiendo pelicula y no película, es decir,omit imos el acento. La razón es que no todas las herramientas de acceso a datosse comportan igual con los caracteres internacionales, como los acentos, por loque evitaremos ut ilizarlos en los nombres de bases de datos y tablas siempre quesea posible. Esto no es aplicable a los datos que luego contendrán, sólo a losnombres de bases de datos y tablas.

También se habrá fijado en que las palabras reservadasdel lenguaje que utilizamos para dar órdenes a MySQLestán en mayúsculas, mientras que los nombres de basesde datos, tablas y campos están en minúsculas. Se tratade un convenio ampliamente aceptado que permitediferenciar de un vistazo las diferentes partes de estasinstrucciones.

¿Qué quieren decir las dos líneas dedicadas a la

Page 73: Desarrollo Web Con PHP y MySQL

creación de la base de datos? Con la primera de ellas se ledice a MySQL que borre la base de datos videoteca encaso de que exista. Suponga que ha utilizado en más deuna ocasión estas líneas porque está volviendo a probarlos ejemplos que acompañan este libro. Si intentase crearla base de datos y ésta ya existiese, MySQL le diría que noes posible llevar a cabo la acción, porque la base de datosya existe, algo no deseable si quiere comenzar con losejemplos desde cero.

Traduciendo del inglés, la primera línea le dice a MySQLalgo así como: "Borra la base de datos videoteca en casode que exista".

La segunda línea es la que se encarga de la creación:"Crea la base de datos videoteca". Tras la ejecución de lasegunda línea, la base de datos habrá sido creada.

Llegó el momento: vamos a crear nuestra primera basede datos. Escriba en el símbolo del sistema las dos líneasque acabamos de comentar y pulse la tecla Intro alterminar. La figura 3.7 muestra el aspecto de dichaventana tras ejecutar las instrucciones.

Figura 3.7. SQL para crear una base de datos

¡Vaya, qué decepción! El resultado no es demasiadoespectacular. Los mensajes indican que las consultas sehan ejecutado correctamente. ¿Es posible que hayamosconseguido nuestro objetivo? Para comprobarlo basta conque ejecute la siguiente instrucción:

SHOW DATABASES;

En la figura 3.8 puede ver que una de las bases de datosexistentes es, precisamente, la que acabamos de crear:videoteca. Enhorabuena.

Figura 3.8. Nuestra primera base de datos

Para que la base de datos sea realmente útil, es decir,para que pueda almacenar datos que posteriormentepodamos consultar, es necesario crear tablas dentro deella. Precisamente lo siguiente que haremos. Vuelva aexaminar las instrucciones anteriores:

DROP DATABASE IF EXISTS videoteca;

Page 74: Desarrollo Web Con PHP y MySQL

CREATE DATABASE videoteca;

USE videoteca;

DROP TABLE IF EXISTS pelicula;

CREATE TABLE pelicula (

titulo VARCHAR(64),

director VARCHAR(128),

actor VARCHAR(128)

);

Al igual que con las dos primeras instrucciones, sólonecesita traducir al castellano línea por línea. La terceralínea permite indicarle a MySQL la base de datos con laque debe trabajar: "Utiliza la base de datos videoteca". Deesa forma, MySQL sabrá que las siguientes instruccionesque reciba irán referidas a esa base de datos.

En la cuarta línea se le pide a MySQL que borre la tablapelicula si ya existe. Como puede comprobar, en estainstrucción no se hace referencia a base de datos alguna.Esto es así gracias a la instrucción anterior, en la que seindicó con qué base de datos se iba a trabajar.

Nota: Podríamos haber incluido el nombre de la base de datos antes del nombrede la tabla, separados por un punto, en la instrucción de creación de la tabla:CREATE TABLE videoteca.pelicula. Sin embargo, gracias a la instrucción USEnos lo ahorramos.

Y llega la parte complicada. A partir de la quinta línea seinstruye a MySQL para que cree una tabla nueva, llamadapelicula, dentro de la base de datos videoteca. No sepreocupe demasiado por la sintaxis de estas instrucciones,basta con que sepa que estas instrucciones le indican aMySQL las columnas que tendrá la tabla pelicula y el tipode datos de cada una de ellas. En este caso, todos loscampos contendrán información de texto.

Escriba esas instrucciones y, de nuevo, pulse Introcuando termine. ¿Quiere asegurarse de que la tabla se hacreado? Escriba la siguiente instrucción:

DESCRIBE pelicula;

La figura 3.9 muestra los mensajes que verá tras crear latabla de películas y ejecutar posteriormente la instrucciónDESCRIBE.

Page 75: Desarrollo Web Con PHP y MySQL

Figura 3.9. Creación de la tabla

Ahora tiene una base de datos con una tabla, y la hacreado usted mismo. Con lo aprendido hasta el momentoestamos listos para comenzar a ver las operacionesbásicas de manipulación. Es realizando estas operacionescomo comprenderá para qué sirve realmente una base dedatos.

Pero antes de aprender a realizar estas operacionesbásicas, detengámonos un momento y veamos quéoperaciones se pueden llevar a cabo sobre las propiastablas.

Operaciones sobre tablas

A continuación aprenderá a realizar las operacionesbásicas de creación, modificación y borrado de tablas.Aunque con lo que verá tendrá las nociones mínimasnecesarias, las instrucciones que verá disponen demuchas más opciones de las que comentaremos, por loque le recomendamos que acuda a la documentación deMySQL y complete sus conocimientos sobre ellas si así lodesea.

Para explicar la forma en la que debe utilizar estasinstrucciones recurriremos a la sintaxis que MySQL sigueen su documentación. Así le será más sencillo entenderlacuando acuda a ella en busca de más información. Sólohay que seguir tres normas muy simples:

Aquellos fragmentos incluidos entre corchetes ([]) sonopcionales, lo que quiere decir que no es obligatorioutilizarlos en las consultas.Si encuentra instrucciones entre llaves ({}) separadaspor el símbolo | querrá decir que son alternativas:puede utilizar una u otra, pero ha de utilizar una deellas. Si están entre corchetes, puede utilizar una oninguna de ellas.Por último, para simplificar la forma en la que lasintaxis está expresada, grandes partes de ladescripción pueden sustituirse por un nombre cuyasintaxis se explicará posteriormente.

Verá ejemplos de estas tres normas con la sentencia de

Page 76: Desarrollo Web Con PHP y MySQL

creación de tablas descrita a continuación.

Creación

La creación de una tabla debe hacerse de acuerdo a lasiguiente sintaxis:

CREATE TABLE [IF NOT EXISTS] nombre

[(definición, ...)]

[opciones]

Si lo desea, puede incluir IF NOT EXISTS cuando creeuna tabla. Esto evitará que MySQL le informe del error queocurre al intentar crear una tabla que ya existe.

La descripción de las características de cada columna serealiza en definición:

definición:

columna tipo

[NOT NULL | NULL]

[DEFAULT valor_predeterminado]

Debe incluir una definición por cada columna que deseeutilizar. El tipo de la columna se indica tras su nombre. Másadelante, en este mismo capítulo, hablaremos sobre lostipos de datos. Si lo desea puede incluir un valorpredeterminado. De esa forma, en cada inserción seasignará ese valor a su columna, aunque no hayaespecificado valor alguno. Si indica NULL para unacolumna (o no indica nada, pues NULL es la opciónpredeterminada), MySQL le permitirá insertar registros sinasignar un valor a dicha columna. El valor guardado seráNULL. Si no desea que esto sea así indique NOT NULL.

Entre otras opciones, es posible indicar el tipo de tablaque se desea utilizar:

ENGINE = {

ARCHIVE |

CSV |

FEDERATED |

MEMORY |

InnoDB |

MERGE |

MYISAM |

NDBCLUSTER

}

En breve explicaremos las características de losdiferentes tipos de tabla existentes, centrándonos en losmás utilizados.

Para ver cómo se crea una tabla nada mejor que unejemplo. Vamos a crear una nueva base de datos en la querealizar las pruebas de este capítulo. Es más que probableque MySQL ya disponga de una base de datos de pruebasllamada test, que podríamos utilizar para crear tablas deejemplo. Sin embargo, no va a ser éste el caso. Ejecute lassiguientes órdenes para crear la base de datos pruebas:

DROP DATABASE IF EXISTS pruebas;

Page 77: Desarrollo Web Con PHP y MySQL

DROP DATABASE IF EXISTS pruebas;

CREATE DATABASE pruebas;

Ejecute ahora las siguientes órdenes para crear la tablapersona:

USE pruebas;

CREATE TABLE persona(

id INT NOT NULL,

nombre VARCHAR(16) NOT NULL,

apellidos VARCHAR(64) NOT NULL DEFAULT ''

);

Las instrucciones anteriores crean una tabla siguiendolas normas sintácticas que se vieron anteriormente. Ahorabien, ¿es posible modificar las características de una tablaya existente? La respuesta es sí, como ya sabrá.

Modificación

Las características de una tabla pueden ser modificadasdespués de que haya sido creada, incluso si ya contienedatos. Para ello debe utilizar la instrucción ALTERTABLE, que sigue la siguiente sintaxis:

ALTER TABLE nombre

modificación [, modificación, ...]

A su vez, cada modificación se define de la siguienteforma:

modificación:

ADD definición

| ADD (definición, definición,...)

| MODIFY columna {

SET DEFAULT valor_predeterminado |

DROP DEFAULT

}

| CHANGE columna definición

| DROP columna

| opciones

Por definición se entiende la sintaxis vista en lacreación de tablas. Con esta instrucción se pueden añadirnuevas columnas a una tabla (ADD), modificar lasexistentes (CHANGE), cambiar valores predeterminados(MODIFY) o eliminarlos, eliminar columnas (DROP) ocambiar el tipo de tabla.

Como ejemplo, nada mejor que modificar la tabla creadaen la sección anterior. Vamos a cambiar el tipo del camponombre para que pueda almacenar cadenas de mayorlongitud. Además, añadiremos un nuevo campo quepermitirá guardar la edad. Para lograr ambos objetivosutilice las siguientes instrucciones:

USE pruebas;

ALTER TABLE persona

MODIFY nombre VARCHAR(32) NOT NULL,

ADD edad INT NOT NULL;

Page 78: Desarrollo Web Con PHP y MySQL

También es posible cambiar el nombre de las tablasexistentes:

RENAME TABLE

actual TO nuevo[, actual2 TO nuevo2,...]

El nombre de la tabla actual se cambiaría por el nuevo.Si lo desea, puede cambiar el nombre de más de una tablaa la vez. Las siguientes instrucciones permiten cambiar elnombre de la tabla persona por individuo:

USE pruebas;

RENAME TABLE persona TO individuo;

Borrado

La sintaxis de la instrucción de borrado de tablas es:

DROP TABLE [IF EXISTS] nombre [, nombre, ...]

En dicha sintaxis, nombre es el nombre de la tabla quese quiere eliminar. Como puede ver, es posible borrar másde una tabla a la vez con sólo indicar sus nombresseparados por comas.

Si lo desea, puede incluir IF EXISTS en la consulta deborrado. Esto evitará que MySQL le informe del error quesurge al intentar eliminar una tabla que no existe en labase de datos que esté utilizando en ese momento.

Para borrar la tabla que se ha estado utilizando hastaahora utilice las siguientes instrucciones:

USE pruebas;

DROP TABLE IF EXISTS individuo;

Tipos de tabla

Al contrario que otros sistemas gestores de bases dedatos, MySQL permite utilizar diferentes tipos de tabla,dependiendo de sus necesidades. Si precisa velocidad deproceso puede utilizar tablas que estarán directamente enla memoria RAM del servidor. Si la prioridad es ahorrarespacio de almacenamiento, MySQL puede comprimir lastablas para que ocupen lo menos posible. Es posibleutilizar transacciones si se trata de uno de los requisitosde la aplicación.

Y lo mejor de todo: si sólo necesita un sistema paraalmacenar datos y posteriormente consultarlos, sinquebraderos de cabeza, puede olvidar que existen losdiferentes tipos de tabla que se verán a continuación.

En los siguientes apartados describiremos los tipos detabla más utilizados: MyISAM e InnoDB. Sin embargo,existen muchos otros como, por ejemplo:

ARCHIVE: Permite almacenar grandes cantidades de

Page 79: Desarrollo Web Con PHP y MySQL

información sin utilizar ningún índice. Comoconsecuencia es muy veloz, pero sólo si el propósito dela tabla es archivar información. La recuperación de lamisma será más lenta en la mayoría de los casospuesto que no se podrá utilizar índice alguno paraacelerarla.CSV: Son las siglas de Comma Separated Values(valores separados por comas). Permite almacenardatos en archivos de texto separando los valores concomas.FEDERATED: Permite que se pueda acceder a losdatos de una tabla desde servidores remotos.NDBCLUSTER: Tipo de tabla para entornosdistribuidos y de alta disponibilidad.

Truco: ¿Quiere saber qué t ipos de tabla puede ut ilizar en su servidor MySQL?Realice la consulta SHOW ENGINES;.

Más aún, no dejan de aparecer tipos de tabla nuevospara cubrir todas las necesidades de los usuarios deMySQL.

Nota: Existen un par de t ipos de tablas muy curiosos que no hemos mencionadoaún. El primero de ellos es EXAMPLE (ejemplo). Como su nombre indica, se t ratade un simple ejemplo que no cumple más función que ilustrar el funcionamientointerno de MySQL en su código fuente. El otro t ipo de tabla es BLACKHOLE(agujero negro) y funciona como tal: todo lo que se arroja dentro de una tabla deeste t ipo desaparece y cualquier consulta devuelve un conjunto vacío. Se ut ilizaen entornos en los que no es necesario guardar los datos en el servidor local perosí enviarlos a otros servidores de forma distribuida.

MyISAM

El tipo predeterminado de tablas que MySQL proporcionaes MyISAM, una evolución del tipo de tabla original,conocido como ISAM (ya descatalogado), con mejorascomo un superior aprovechamiento del espacio y másvelocidad en el acceso a datos. El nombre de este tipo detablas viene de la forma en que MySQL accede a susdatos. ISAM son las siglas de método de acceso secuencialindexado (Indexed Sequential Access Method).

Al crear tablas sin indicar de qué tipo serán, MySQLutilizará el tipo MyISAM. Lo mismo hará si no es capaz decrear el tipo de tabla que se indique, para evitarcomplicaciones.

Aviso: Existe una excepción a la afirmación anterior. El t ipo predeterminado delas tablas será InnoDB si ha instalado MySQL en Windows ut ilizando el asistente.Si t iene alguna duda sobre el t ipo de una determinada tabla, ut ilice la instrucciónSHOW CREATE TABLE seguida del nombre de la tabla en cuest ión y busque elvalor que toma ENGINE.

Las tablas de tipo MyISAM pueden, a su vez, ser de trestipos:

Page 80: Desarrollo Web Con PHP y MySQL

Estáticas: De forma automática, si la tabla que estácreando no contiene ningún campo de tipo VARCHAR,VARBINARY, TEXT o BLOB, MySQL hará que sea detipo estático. En una tabla de tipo estático, cadaregistro ocupa siempre el mismo tamaño. Este tipo detablas es el más rápido cuando se trata de leer datosdel disco: para recuperar los de un registro en concretosólo es necesario realizar unos sencillos cálculos. Porel contrario, ocupa más espacio que las tablasdinámicas.Dinámicas: Si crea una tabla con algún campo de tipoVARCHAR, VARBINARY, TEXT o BLOB, MySQL haráque sea de tipo dinámico. Delante de cada registroalmacenará el espacio que ocupa. Como consecuencia,estas tablas ocupan menos espacio que las tablasestáticas. La contrapartida: es necesario más tiempopara acceder a un registro en particular, puesto que senecesita leer antes el espacio ocupado por cadaregistro y hacer los cálculos oportunos.Comprimidas: Si necesita que el espacio ocupado porsus tablas sea mínimo éste es su tipo de tabla. Si sutabla está en este formato sólo podrá leer de ella, porlo que deberá realizar las inserciones en tablas sincomprimir y alterar posteriormente las propiedades dela tabla para comprimirla. Un efecto secundario muyinteresante de este tipo de tablas es que mejora eltiempo de acceso a los datos si están almacenados endispositivos muy lentos, como algunos discosextraíbles u ópticos. Esto se debe a que en cadalectura se pueden recuperar más datos que si la tablano estuviese comprimida, algo recomendable enaplicaciones de bases de datos que funcionen desdeunidades ópticas, como el CD-ROM, por ejemplo.

Por sus características, las tablas MyISAM sonespecialmente útiles cuando los datos no cambian confrecuencia y la operación más utilizada es la de lectura. Silas inserciones de nuevos datos y las modificaciones van aser algo frecuente o necesita utilizar transacciones en susoperaciones con registros, es recomendable que utilicetablas de tipo InnoDB.

InnoDB

Las tablas InnoDB proporcionan bloqueo por registro ycontrol de transacciones, cumpliendo con el estándarACID. Para lograr estos dos objetivos se sacrifica un pocode la velocidad de la que MySQL presume.

MySQL bloquea las tablas de tipo MyISAM cuando serealiza una inserción o una actualización en un registrohasta que la operación termine. Sin embargo, si las tablasson InnoDB, el bloqueo sólo se realiza en el registro que seesté modificando, lo que permite que más usuarios utilicende forma simultánea la base de datos.

Las transacciones son necesarias en multitud desituaciones. El ejemplo más utilizado transcurre en la basede datos de un banco, durante una transferencia entre doscuentas.

Page 81: Desarrollo Web Con PHP y MySQL

Si piensa en esta transferencia en el mundo real, comoun traspaso de dinero de una persona a otra, no verá queexistan problemas: uno le da el dinero a otro y asuntoresuelto. La situación se complica en el entornoinformático, donde el saldo de las cuentas de ambosclientes debe estar almacenado en un registro dentro deuna tabla de una base de datos. Se trata de un valornumérico en coma flotante.

Cree una tabla muy sencilla para los saldos de losclientes del banco dentro de la base de datos de pruebasutilizando las siguientes instrucciones:

USE pruebas;

DROP TABLE IF EXISTS cuenta;

CREATE TABLE cuenta(

idcliente INT NOT NULL,

saldo DOUBLE NOT NULL DEFAULT 0

)

ENGINE = InnoDB;

A continuación, inserte un par de valores para almacenarel saldo de dos clientes:

USE pruebas;

INSERT INTO cuenta VALUES(212, 220.50);

INSERT INTO cuenta VALUES(555, 1200.00);

Para realizar la transferencia han de completarse dospasos: la cantidad transferida debe sumarse en la cuentade destino y restarse de la cuenta que origina latransferencia. Una operación tras la otra:

USE pruebas;

UPDATE

cuenta

SET

saldo = saldo + 300

WHERE

idcliente = 212;

UPDATE

cuenta

SET

saldo = saldo - 300

WHERE

idcliente = 555;

¿En qué situación estaremos si ocurre algún problemaentre el primer y el segundo paso, como un corte desuministro eléctrico, un fallo en el hardware del ordenadorque hospeda el servidor de bases de datos, etcétera? Elimporte a transferir se habrá sumado a la cuenta destino,pero no se habrá restado de la emisora. Para el banco nose trata de algo deseable. Claro que es todo lo contrariopara los clientes.

Page 82: Desarrollo Web Con PHP y MySQL

El estándar ACID se propuso para solucionar este tipode situaciones. ACID son las siglas de atómico,consistente, aislado y duradero (Atomic, Consistent,Isolated, and Durable).

Se dice que uno o más cambios en una base de datoscomponen una operación atómica si forman una unidadindivisible: o todos se completan con éxito, o ninguno lohará.

El estado de una base de datos es consistente mientrascumpla unas reglas, definidas por el diseño. En el ejemplodel banco, una de las reglas de consistencia podría ser quetoda transferencia de capital debe estar correspondida porun ingreso. Al comienzo de una transacción, el estado dela base de datos debe ser consistente. Sin embargo,mientras dure la transacción, es posible que se pierda laconsistencia. Esto es permisible siempre y cuando alterminar la transacción se retorne al estado deconsistencia inicial.

Mientras dure una transacción, las instrucciones que laconforman deben tener la impresión de que sólo ellasestán en funcionamiento, aunque en realidad se puedanestar realizando otras operaciones en la base de datos,incluso otras transacciones.

En último lugar, los cambios realizados por unatransacción deben permanecer cuando ésta termine. Por elcontrario, si la transacción se interrumpe en medio de sutrabajo (por un corte de luz, por ejemplo), ninguno de loscambios que haya realizado se habrán guardado,permaneciendo la base de datos en el mismo estado en elque se encontraba antes de comenzar la transacción.

La gestión de las transacciones se realiza medianteunas instrucciones muy sencillas. Siguiendo con elejemplo, la transferencia se realizaría de la siguienteforma:

USE pruebas;

START TRANSACTION;

UPDATE

cuenta

SET

saldo = saldo + 300

WHERE

idcliente = 212;

UPDATE

cuenta

SET

saldo = saldo - 300

WHERE

idcliente = 555;

Page 83: Desarrollo Web Con PHP y MySQL

COMMIT;

Con la primera instrucción se le dice a MySQL que va acomenzar un bloque de sentencias SQL dentro de unatransacción. Es decir, MySQL no hará efectivo los cambioshasta que encuentre una instrucción COMMIT .

A continuación de esta primera instrucción están lasoperaciones a realizar con los valores dentro de la base dedatos. El bloque termina con la instrucción COMMIT , quefinaliza la transacción.

Si existiese un problema antes de ejecutar la instrucciónCOMMIT , todas las instrucciones anteriores a COMMIT sedescartarían, eliminando el problema de la inconsistencia.Los bancos son muy listos.

Nota: Existe un mot ivo más para ut ilizar tablas del t ipo InnoDB, ya que permitenla existencia de claves externas, algo vital para el funcionamiento de la integridadrelacional. Verá qué quiere decir esto en el capítulo dedicado al diseño de basesde datos.

Tipos de datos

Dependiendo de la naturaleza de los datos quequeramos guardar, el tipo de cada columna debe serdiferente. A continuación veremos cuáles pone MySQL anuestra disposición.

Tipos de texto

En la jerga informática, se utiliza la expresión cadena detexto cuando se hace referencia a una sucesión decaracteres que pueden formar palabras o frases. MySQLdispone de varios tipos de datos diferentes para almacenaresta clase de información:

CHAR: Permite definir cadenas de texto de longitudfija. La longitud se especifica entre paréntesis acontinuación del nombre del tipo y puede estar entre 0y 255 caracteres. Si la columna puede tener veintecaracteres, siempre se ocuparán esos caracteres,aunque el texto a guardar sea menor. En la figura 3.10puede ver cómo almacenaría MySQL los valores de unatabla con una sola columna de tipo CHAR. El tipoCHAR admite el modificador BINARY, que permitedeterminar si en las consultas se diferenciará entremayúsculas y minúsculas. Verá un ejemplo másadelante.

Figura 3.10. Ocupación de CHAR

Page 84: Desarrollo Web Con PHP y MySQL

VARCHAR: Tiene el mismo rango de longitud que elt i po CHAR. Sin embargo, si define una columna deveinte caracteres y guarda una cadena de diez, sólo seocuparán esos diez caracteres más uno para guardar lalongitud. Es decir, para una cadena de diez caracteres,un CHAR ocuparía veinte caracteres, mientras que unVARCHAR sólo once. La figura 3.11 muestra cómoasignaría MySQL el espacio si la única columna de latabla mostrada en la figura 3.10 estuviese creada conun tipo VARCHAR. Compare el espacio ocupado porlos datos en las figura 3.10 y 3.11. Utilizando CHAR setienen cinco filas de 14 caracteres cada una, lo que daun resultado de 70 caracteres. Con VARCHAR tendríaque sumar el número de caracteres de cada fila, entotal 38, más un carácter extra por cada fila; en total,43 caracteres. También VARCHAR admite elm od i f i cado r BINARY para determinar si sediferenciarán mayúsculas de minúsculas en lasconsultas.

Figura 3.11. Ocupación de VARCHAR

Nota: El t ipo CHAR ocupa más espacio, pero la recuperación de los datos alhacer consultas es más veloz. Por ejemplo, MySQL sabe que el tercer elementode la tabla se encuentra t res veces la longitud de la columna a part ir del inicio dela tabla.

BINARY: Equivalente al tipo CHAR, con la salvedad deque las cadenas se almacenan en formato binario, nocomo cadenas de caracteres. No confundir con el tipode datos CHAR BINARY.VARBINARY: Equivalente al tipo VARCHAR, con lasalvedad de que las cadenas se almacenan en formatobinario, no como cadenas de caracteres. No confundircon el tipo de datos VARCHAR BINARY.BLOB: Aunque no se trata de un tipo de textopropiamente dicho, es necesario hablar de él porqueestá íntimamente relacionado con el siguiente, TEXT .El nombre BLOB significa objeto binario de grantamaño (binary large object). Este tipo de columnaspuede utilizarse para guardar información binaria,como el contenido de un archivo JPG, un archivocomprimido con ZIP, etcétera. Y claro está, tambiénpuede utilizarse para guardar texto cuya longitud estépor encima de la permitida por los tipos CHAR oVARCHAR. Las consultas realizadas sobre este tipo decolumnas diferenciarán entre mayúsculas yminúsculas, el mismo comportamiento de CHAR y

Page 85: Desarrollo Web Con PHP y MySQL

VARCHAR cuando se utiliza el modificador BINARY.Los tipos TINYBLOB, MEDIUMBLOB y LONGBLOBson BLOB de diferentes tamaños.

Nota: Aunque es posible almacenar imágenes y cualquier archivo binario en uncampo de t ipo BLOB dentro de una tabla de MySQL, existen otras alternat ivas,como relacionar de alguna manera un archivo en disco con un registro dentro deuna tabla. Por ejemplo, podría guardar la ruta en la que el archivo se encuentra enun campo de t ipo VARCHAR, haciendo menor el espacio ocupado por la base dedatos.

TEXT: Exactamente igual que un BLOB, con lasalvedad de que TEXT no distingue entre mayúsculasy minúsculas en las consultas. Los tipos TINYTEXT ,MEDIUMTEXT y LONGTEXT son TEXT de diferentestamaños.ENUM: La enumeración es una clase especial de tipode cadena. Al definir la columna se indican los posiblesvalores que puede tomar. Posteriormente, en esacolumna sólo se podrá insertar alguno de los valoresdefinidos. Internamente, MySQL sustituye la cadenapor un número, ahorrando espacio en cada inserción.Enseguida veremos un ejemplo.SET: Similar a ENUM, los conjuntos se diferencian enque se pueden insertar varios de los valores definidosal crear la tabla. Con el ejemplo que veremos en brevequedará más claro cómo se insertan estos valores.MySQL utiliza un ingenioso sistema para no tener queguardar las cadenas en la base de datos, ahorrandoespacio.

Cree una nueva tabla llamada texto, la utilizaremos parahacer pruebas con los tipos de texto. Esta tabla estarádentro de la base de datos de pruebas que creamos alprincipio de este capítulo:

USE pruebas;

DROP TABLE IF EXISTS texto;

CREATE TABLE texto(

cadena VARCHAR(32)

);

Inserte algunas cadenas de texto:

USE pruebas;

INSERT INTO texto VALUES('d');

INSERT INTO texto VALUES('a');

INSERT INTO texto VALUES('A');

INSERT INTO texto VALUES('b');

Y realice una consulta a los valores de esa tabla,ordenándolos de forma alfabética:

USE pruebas;

SELECT

*

Page 86: Desarrollo Web Con PHP y MySQL

*

FROM

texto

ORDER BY

cadena;

Puede ver el resultado de esta consulta en la figura 3.12.

Figura 3.12. Ordenación alfabét ica

Ahora, repita los pasos anteriores, pero cree la tabla conlas siguientes instrucciones:

USE pruebas;

DROP TABLE IF EXISTS texto;

CREATE TABLE texto(

cadena VARCHAR(32) BINARY

);

Vuelva a insertar los mismos valores y, de nuevo,selecciónelos ordenados alfabéticamente. Esta vez elresultado será diferente, como puede verse en la figura3.13.

Figura 3.13. Otra ordenación alfabét ica

Como puede comprobar, la primera consulta devuelve losregistros ordenados alfabéticamente, pero no diferenciaentre mayúsculas y minúsculas. Ante la duda, se basa enel orden de inserción, razón por la que a aparece antes queA.

Sin embargo, el resultado de la segunda consulta sí seobtiene diferenciando entre mayúsculas y minúsculas. Porello A aparece antes que a. Téngalo en cuenta cuandodesee obtener listados ordenados alfabéticamente.

Ahora, un ejemplo de enumeraciones. Suponga que

Page 87: Desarrollo Web Con PHP y MySQL

quiere almacenar en un campo de su base de datosdedicada a películas el soporte en el que se encuentran lasgrabaciones. Como sólo dispone de reproductor de vídeoVHS y de DVD le bastará con que la columna tenga esosdos valores.

Es posible crear en la base de datos de pruebas unatabla con una columna dedicada al soporte en el que seencuentra la grabación, de esta manera:

USE pruebas;

DROP TABLE IF EXISTS pelicula;

CREATE TABLE pelicula(

titulo VARCHAR(64),

soporte ENUM(

'VHS',

'DVD'

)

);

Puede insertar valores en esa tabla como si de cadenasde texto se tratasen:

USE pruebas;

INSERT INTO

pelicula

VALUES

('Alien', 'VHS');

INSERT INTO

pelicula

VALUES

('TRON', 'DVD');

El resultado de una consulta de todos los valores de estatabla puede verse en la figura 3.14.

Figura 3.14. Enumeración para soportes de grabación

MySQL no permite insertar valores que no estén dentrode los definidos al crear la tabla. La siguiente insercióngenerará un error:

USE pruebas;

INSERT INTO pelicula VALUES(

'Blade Runner', 'VCD'

);

Puede ver el mensaje devuelto en la figura 3.15.

Page 88: Desarrollo Web Con PHP y MySQL

Figura 3.15. Inserción que no pertenece a la enumeración

Aunque puede simplificar mucho trabajo, el uso deenumeraciones no es una buena idea si queremos permitirla inserción de nuevos formatos de grabación. Siutilizásemos enumeraciones tendríamos que modificar lascaracterísticas de la tabla. En el capítulo dedicado aldiseño de bases de datos veremos cómo permitir que losformatos de grabación puedan ser modificados sin cambiarla estructura de la tabla.

El tipo de datos SET también podría utilizarse en esteejemplo. Suponga que quiere guardar en una columna elgénero al que pertenece una película. Como a veces no esposible encuadrar un título dentro de una única categoríasería interesante poder indicar varías a la vez. Se podríalograr algo similar creando la columna categoria mediantelas siguientes órdenes:

USE pruebas;

DROP TABLE IF EXISTS pelicula;

CREATE TABLE pelicula(

titulo VARCHAR(64),

categoria SET(

'ciencia-ficción',

'terror',

'thriller'

)

);

La inserción de registros en una tabla con una columnade tipo SET se realiza de la siguiente manera:

USE pruebas;

INSERT INTO

pelicula

VALUES(

'Alien',

'ciencia-ficción,terror'

);

INSERT INTO

pelicula

VALUES(

'Blade Runner',

'ciencia-ficción,thriller'

);

Page 89: Desarrollo Web Con PHP y MySQL

INSERT INTO pelicula VALUES(

'Contact',

'ciencia-ficción'

);

El resultado de una consulta sobre los valores insertadosen esta tabla puede verse en la figura 3.16. Lasinserciones de valores no existentes en la definición delcampo de tipo SET darían lugar a la inserción de cadenasvacías.

Figura 3.16. Ut ilización del t ipo SET

Tipos numéricos

MySQL proporciona diferentes tipos de datos para quealmacenemos números en las columnas de nuestrastablas. Como existe una gran variedad, es posibleseleccionar el tipo de datos más adecuado para cada caso.No es lo mismo guardar el número de veces que se havisto una película que su precio. La primera cantidad es unnúmero entero positivo, mientras que la segunda esdecimal.

Por cuestiones relacionadas con la forma en la que losprogramas están construidos y con el hardware en el quese ejecutan, es más costoso almacenar y realizaroperaciones con números decimales que con númerosenteros. Se estarían desaprovechando recursos si seutilizase una columna de tipo decimal para almacenarinformación de tipo entero.

De igual manera, estaríamos perdiendo información (yeso puede ser más grave) si la columna destinada aalmacenar el precio de una película fuese de tipo entero,puesto que la parte de la derecha de la coma, la partedecimal, se perdería.

Números enteros

MySQL proporciona suficiente variedad de tipos paracubrir todas sus necesidades. Existen seis tipos básicospara almacenar enteros, diferenciados por el rango devalores que pueden contener. Cuanto mayor sea el rango,más espacio se ocupará en la base de datos. Estos tiposson:

TINYINT: El más pequeño de los enteros, con un rangoentre -128 y 127 con signo, o de 0 a 255 sin signo.Ocupa un solo byte.SMALLINT: Oscila entre -32768 y 32767. Si no se

Page 90: Desarrollo Web Con PHP y MySQL

incluye signo, puede ir desde 0 a 65535. Dos bytes deespacio.MEDIUMINT: Con signo desde -8388608 a 8388607.Sin signo desde 0 a 16777215. El espacio consumidoes de 3 bytes.INT: El tipo entero más común. Puede ir desde -2147483648 a 2147483647 si utiliza signo, o desde 0hasta 4294967295 si no lo utiliza. Al ocupar 4 bytesestá especialmente indicado si desea aprovechar lascaracterísticas de la mayoría de procesadores delmercado de hoy en día.BIGINT: El mayor de los tipos enteros ocupa 8 bytes.Con signo, puede almacenar valores desde -9223372036854775808 hasta 9223372036854775807,mientras que sin signo el rango está entre 0 y18446744073709551615.

Utilice la base de datos creada en el apartado anteriorpara las pruebas con los tipos de texto. Cree dentro de ellauna tabla con un único campo de tipo INT :

USE pruebas;

DROP TABLE IF EXISTS enteros;

CREATE TABLE enteros(entero INT);

La columna entero de la tabla enteros puede almacenarnúmeros enteros con signo dentro del rango que seencuentra entre -2147483648 a 2147483647.

Advertencia: Aunque es posible realizar inserciones fuera de ese rango, MySQLrecortará el número hasta el límite más cercano sin avisarnos.

Si quisiese almacenar enteros sin signo en ese campodebería cambiar la tercera línea, que se encarga de lacreación de la tabla, añadiendo el modificador UNSIGNED,como puede verse a continuación:

USE pruebas;

DROP TABLE IF EXISTS enteros;

CREATE TABLE enteros(entero INT UNSIGNED);

Como puede comprobar, sólo se ha añadido elmodificador UNSIGNED después del indicador del tipo dela columna, cambiando así el tipo de datos que la columnapodrá guardar.

Existen otros modificadores que, utilizados de formaconjunta, pueden resultarnos interesantes. Con uno deellos, ZEROFILL, se le puede indicar a MySQL que rellenecon ceros a la izquierda el número, hasta los dígitosseleccionados con el segundo modificador. Si se sabe quelos valores de una determinada columna no podrán tenermás de 4 dígitos es posible utilizar otro modificador paraque los números devueltos siempre ocupen esos 4 dígitos,rellenando con ceros a la izquierda aquellos que ocupenmenos.

Page 91: Desarrollo Web Con PHP y MySQL

Puede que un ejemplo sirva para explicar mejor elfuncionamiento de ZEROFILL. La siguiente consultareconstruye la tabla de enteros, cambiando lascaracterísticas de su única columna:

USE pruebas;

DROP TABLE IF EXISTS enteros;

CREATE TABLE enteros(

entero INT(4) UNSIGNED ZEROFILL

);

Como ve, el segundo de los modificadores antesmencionado se añade a continuación del tipo, entreparéntesis. Pruebe a insertar algunos valores paradespués seleccionarlos, y así ver el efecto que tienen enlas consultas. Primero las inserciones:

USE pruebas;

INSERT INTO enteros values(1);

INSERT INTO enteros values(10);

INSERT INTO enteros values(100);

INSERT INTO enteros values(1000);

Y luego la consulta de selección:

USE pruebas;

SELECT * FROM enteros;

La figura 3.17 muestra el resultado de esta consulta.

Figura 3.17. Selección de valores enteros

Como puede comprobar, el tipo de la columna entero esentero relleno de ceros hasta cuatro dígitos, el 1 aparececomo 0001, el 10 como 0010, el 100 como 0100 y el 1000tal cual.

¿Qué ocurriría si se insertase un valor con más dígitosde los indicados al crear la tabla? Pruebe:

USE pruebas;

INSERT INTO enteros VALUES(10000);

Como comprobará, MySQL le permite realizar lainserción sin ningún problema: los modificadores añadidosal tipo de la columna entero sólo afectan a la forma en laque los datos se presentan al consultarlos. Por cierto, ¿quése obtendrá al consultar ahora los datos de la tabla? Véaloen la figura 3.18.

Page 92: Desarrollo Web Con PHP y MySQL

Figura 3.18. Valor con más dígitos

A aquellos valores que estén por debajo del anchoestablecido al definir el tipo del campo se les añadiránceros por la izquierda, mientras que el resto se mostrarántal cual.

Advertencia: Desde aquí queremos recomendarle que sólo ut ilice este t ipo demodificaciones cuando sea estrictamente necesario. Existen otras formas de darformato a los números que no pasan por alteraciones en la definición de lascolumnas de una tabla. Una regla podría ser: mantenga los datos tal como son,modifique su presentación en la aplicación que haga uso de ellos.

Si tiene conocimientos de programación, habrá visto queno se han mencionado otros tipos de datos, como loslógicos o booleanos, al enumerar los tipos existentes.MySQL ofrece diferentes seudónimos para cada tipo dedatos. Puesto que un tipo booleano es el que permitediferenciar entre los estados cierto y falso, en un entero deun dígito tendríamos más que suficiente. El tipoBOOLEAN (o BOOL) es un seudónimo de TINYINT(1).Utilice las constantes TRUE, true, FALSE y false paratrabajar con tipos booleanos. De igual forma, existe unseudónimo llamado BIT para trabajar con bits.

Tras comentar los tipos enteros, continuaremosrepasando los tipos numéricos con los tipos decimales.

Números en coma flotante

Como ya sabrá, los números en coma flotante contienenuna parte entera y una parte decimal. Esta última se utilizapara describir cantidades inferiores a la unidad. El ejemplomás claro: los precios, en los que la parte entera se refierea múltiplos de la moneda, y la parte decimal a la monedafraccionaria.

Por ejemplo, si el precio de un DVD es 29,99 euros, enrealidad cuesta 30 euros menos un céntimo, no se dejeengañar. Pero para lo que interesa ahora mismo, la parteentera es 29 y la parte decimal 99.

Los números en coma flotante se llaman así porque seutiliza una coma para separar la parte entera de la decimal.Sin embargo, en la sintaxis de SQL se utiliza un puntocomo separador. Por ello, al insertar valores en comaflotante éstos se escribirán utilizando el punto. De igualmanera, en el resultado de las consultas verá el puntocomo separador. Sin embargo, fuera del contexto de lasinstrucciones SQL se utilizará la coma como separador.

Page 93: Desarrollo Web Con PHP y MySQL

MySQL proporciona tres tipos básicos para los númerosen coma flotante. A mayor precisión, mayor espacioocupado por el número. Como con los números enteros, esposible utilizar ZEROFILL con idénticos resultados. Por elcontrario, especificar que se trata de números sin signoutilizando UNSIGNED no proporcionará un rango devalores más amplio, simplemente se ignorarán los valoresnegativos. Estos tipos son:

FLOAT: Decimal de precisión simple, permitealmacenar valores entre -3,402823466E+38 y -1,175494351E-38, y 1,175494351E-38 y3,402823466E+38, cero incluido.DOUBLE: Decimal de precisión doble, con valoresentre -1,7976931348623157E+308 y -2.2250738585072014E-308, y 2,2250738585072014E-308 y 1,7976931348623157E+308, incluido el cero.DECIMAL: Los dos tipos vistos anteriormentecodifican la información del número de manera queocupe lo menos posible, utilizando aproximaciones. Sinembargo, este tipo guarda valores exactos. Aunque elrango de valores que puede almacenar es el mismoque el tipo DOUBLE, el espacio ocupado es bastantemayor.

Para estos tres tipos se puede indicar el número dedígitos totales para mostrar y el número de dígitosdecimales, entre paréntesis y a la derecha del nombre deltipo. Por ejemplo, con DOUBLE(6, 2) se estaría indicandoque se quiere una columna que almacene números encoma flotante, con seis dígitos y dos decimales a laderecha de la coma. El rango de valores que se podríanalmacenar en esta columna estaría entre -9999,99 y9999,99: cuatro dígitos antes de la coma y dos tras ellacoma suman seis.

Existe una forma alternativa de crear columnas paraalmacenar valores en coma flotante. Es posible utilizarFLOAT(N), donde N es un valor menor que 53. Si N fuesemenor que 25, los valores de la columna se almacenaríancon precisión simple, mientras que si N está entre 25 y 53lo harían con precisión doble.

Aprovechando que disponemos de una base de datospara pruebas, cree una nueva tabla en la que experimentarcon valores en coma flotante. Para ello, utilice el siguientecódigo:

USE pruebas;

DROP TABLE IF EXISTS decimales;

CREATE TABLE decimales(

precio FLOAT(6,2)

);

Como vimos anteriormente, se pueden insertar valoresentre -9999,99 y 9999,99. Inserte algunos y vea elresultado de una consulta de selección:

USE pruebas;

Page 94: Desarrollo Web Con PHP y MySQL

USE pruebas;

INSERT INTO decimales VALUES(29.99);

INSERT INTO decimales VALUES(30);

INSERT INTO decimales VALUES(199.994);

INSERT INTO decimales VALUES(199.995);

SELECT * FROM decimales;

El resultado puede verse en la figura 3.19. El primer valorinsertado ha sido 29,99.

Figura 3.19. Inserción de valores en coma flotante

El segundo valor insertado fue 30. MySQL añadeautomáticamente dos ceros a la derecha de la coma,puesto que al crear la tabla se le indicó que esa columnatendría dos decimales.

Pero ¿qué ha pasado con el tercer valor? ¡Se insertó199,994, pero la consulta muestra 199,99! Esto se debe alredondeo que MySQL ha realizado. Puesto que tiene quealmacenar el número con 2 decimales, descarta el tercero.

Sin embargo, al examinar el cuarto valor insertado sepuede comprobar que no se trata simplemente dedescartar decimales. MySQL redondea el número. Si eldígito decimal a evaluar está entre 0 y 4, lo descarta. Siestá entre 5 y 9 suma uno al siguiente decimal. Por eso199,995 ha pasado a ser 200,00.

De lo anterior se puede deducir que es muy importantedefinir correctamente la precisión de los decimales, ya queMySQL redondea las cifras que se salen de la definicióndel tipo de la columna.

Para el siguiente ejemplo, cree una nueva tabla:

USE pruebas;

DROP TABLE IF EXISTS decimales2;

CREATE TABLE decimales2(

precio FLOAT(10,5)

);

Inserte un valor:

USE pruebas;

INSERT INTO

decimales2

VALUES(3835.38000);

Page 95: Desarrollo Web Con PHP y MySQL

Ahora, vea lo que se ha insertado en la tabla:

USE pruebas;

SELECT

*

FROM

decimales2;

Como puede comprobar en la figura 3.20, el valormostrado en la consulta no es el mismo que se insertó.Esto se debe a que, internamente, MySQL utiliza precisióndoble para los cálculos en coma flotante. Si utilizacolumnas cuyo tipo sea de precisión sencilla es posibleque experimente problemas al realizar cálculos, porejemplo la aparición de decimales que no ha indicado,como acaba de ver. Por ello, si experimenta problemas deesta índole, es recomendable que utilice el tipo DOUBLEpara almacenar valores en coma flotante.

Figura 3.20. Problemas de redondeo

Como ha podido comprobar, con los tipos numéricos queMySQL pone a nuestra disposición debería tener suficientepara cubrir la mayoría de sus necesidades. MySQL ofreceseudónimos de los tipos aquí presentados. Estosseudónimos no son más que tipos básicos cuyascaracterísticas se han modificado, o simples nombresalternativos. Ya vio el tipo BOOL como ejemplo al hablarde los enteros.

Fechas y horas

MySQL permite utilizar los siguientes tipos de datos paraalmacenar valores relacionados con el tiempo, comofechas y horas:

DATE: Permite almacenar fechas con el formatoAAAA-MM-DD (año, mes y día), entre 1000-01-01 y9999-12-31.TIME: Para guardar horas con el formato hh:mm:ss(horas, minutos y segundos) entre -838:59:59 y838:59:59. Especialmente indicado para almacenartiempos transcurridos entre dos eventos.DATETIME: Combinación de los dos tipos anteriores,primero la fecha y luego la hora. El formato de este tipoes AAAA-MM-DD hh:mm:ss. El rango permitido para laparte de la fecha es el mismo que para el tipo DATE,pero la parte de la hora debe estar entre 00:00:00 y23:59:59. Permite almacenar la fecha y la hora de undeterminado instante.

Page 96: Desarrollo Web Con PHP y MySQL

determinado instante.YEAR: Un año indicado con dos o cuatro dígitos,dependiendo del valor del modificador. Si utiliza dosdígitos, el valor almacenado puede estar entre 1970 y2069, mientras que con cuatro dígitos está entre 1901y 2155. Además se puede almacenar el año 0000.TIMESTAMP: Tipo de datos un poco conflictivo. Sucomportamiento varía dependiendo de la versión deMySQL que se utilice. En líneas generales, se puededecir que una columna de este tipo debería cambiar suvalor cada vez que se produzca una inserción o unaactualización en el registro. De esta forma se puedecontrolar cuándo se creó un registro o cuándo cambiósu valor.

El siguiente es un ejemplo de funcionamiento del tipoTIMESTAMP. Lo utilizaremos para saber la fecha de laúltima modificación de un determinado registro. Vuelva acrear la tabla pelicula de la base de datos de pruebas paraeste ejemplo:

USE pruebas;

DROP TABLE IF EXISTS pelicula;

CREATE TABLE pelicula(

titulo VARCHAR(64),

modificado TIMESTAMP

);

Realice una inserción en esta tabla:

USE pruebas;

INSERT INTO

pelicula(titulo)

VALUES('Alieni');

Al consultar los registros de esta tabla verá que se hainsertado un valor en el campo modificado, aunque noincluyó ninguno en la inserción. Puede comprobarlo en lafigura 3.21.

Figura 3.21. Contenido de una columna TIMESTAMP

La columna modificado contiene la fecha y la hora en laque se realizó la inserción. ¡Vaya, se ha cometido un error!El título de la película es incorrecto. Soluciónelo:

USE pruebas;

UPDATE

pelicula

SET

titulo = 'Alien'

Page 97: Desarrollo Web Con PHP y MySQL

titulo = 'Alien'

WHERE

titulo = 'Alieni';

La figura 3.22 muestra el resultado de una consultasobre la tabla tras la actualización de la columna errónea.Como puede ver, el valor de la columna modificadorepresenta ahora un instante posterior al que podía verseen la figura 3.21, aunque de nuevo no se ha indicado valoralguno para esa columna.

Figura 3.22. TIMESTAMP cambia automát icamente

El repaso a los tipos de datos que MySQL permite utilizaren sus tablas ha concluido. Si desea más informaciónsobre los tipos de datos no dude en acudir a ladocumentación de MySQL, disponible en la siguientepágina Web:

http://dev.mysql.com/doc/mysql/en/column-types.html

Page 98: Desarrollo Web Con PHP y MySQL

4

PHP orientado a objetos

Nuestro tercer encuentro con PHP lo hacemos conbastante ventaja, conociendo las bases del lenguaje yhabiendo programado varios ejemplos. Ahora tenemosmucho más claro qué podemos esperar de unaherramienta como ésta.

Durante este capítulo, el último dedicado al aprendizajede PHP, verá cómo debe escribir sus programas para queese trabajo pueda aprovecharse con posterioridad. Paralograrlo tiene varias opciones.

La primera de ellas consiste en agrupar fragmentos decódigo en unidades funcionales o funciones. Estasfunciones pueden ser invocadas con solo una línea decódigo, quedando oculto el verdadero trabajo que estánrealizando, ya que sólo nos interesa el resultado de utilizarla función.

Otra manera de lograr el mismo objetivo consiste ensituar todo el código PHP común en archivosindependientes. Luego podrá incluir el código de esosarchivos en sus programas, sin necesidad de volver aescribirlo varias veces. Por supuesto, puede combinar eluso de funciones con los archivos externos anteriormentedescritos.

La mayoría de los cambios que la versión 5 introdujoafectaban a la programación orientada a objetos. Veremosqué es esta forma de programación, tal y como la entiendePHP y, de nuevo, cómo podemos aprovecharla para que notengamos que escribir el mismo código dos veces.

Preste especial atención a este capítulo para poder sacarel máximo partido a la versión orientada a objetos de lanueva interfaz de acceso a MySQL.

Funciones

Una función es un fragmento de código agrupado bajo unmismo nombre, que tiene este aspecto:

function nombre ([lista de parámetros]){

instrucciones

}

El nombre de la función debe seguir las mismas reglasque mencionamos en el capítulo 2 para los nombres de lasvariables.

Nota: La lista de parámetros de la función aparece entre corchetes, lo que indicaque su definición es opcional. Es decir, puede crear funciones que no recibanningún parámetro.

Page 99: Desarrollo Web Con PHP y MySQL

Ya hemos utilizado funciones con anterioridad. Porejemplo, printf() en el capítulo 2. Esta función puede recibircomo argumento una cadena de texto que será mostradaen el cliente Web cuando se vea la página.

Internamente, esa función realiza una serie deoperaciones que no es necesario que conozca. Lo únicoque le interesa es saber que la cadena que pase comoparámetro a la función se le mostrará al usuario.

Parámetros

La declaración de la lista de parámetros que una funciónrecibe es similar a la declaración de variables. De hecho,dentro de la función esos parámetros se utilizarán como side variables se tratasen, por lo que sus nombres debenseguir las mismas reglas que definimos en el segundocapítulo. Para declarar más de un parámetro ha desepararlos mediante comas.

Veamos un sencillo ejemplo. Vamos a crear una funciónque reciba como parámetro un número entero y escriba enla página Web si el número es par o impar. Su código es elsiguiente:

function par_impar($numero){

if($numero % 2 == 0){

print('par');

}else{

print('impar');

}

}

El nombre de esta función es par_impar(). La funciónrecibe un solo argumento, $numero. En el cuerpo de lafunción utilizamos una instrucción condicional. Lacondición es que el resto de dividir el número pasado comoargumento entre dos sea cero. Si lo es, escribimos par, encaso contrario, impar.

A continuación puede ver el código de una página PHPen la que se define y utiliza la función anterior:

<?php

function par_impar($numero){

if($numero % 2 == 0){

printf('par');

}else{

print('impar');

}

}

par_impar(7);

?>

Nota: El operador ut ilizado en la función par_impar() devuelve el resto de dividirlos dos operandos, en este caso $numero y dos. Si el resto de dividir un númeroentre dos es cero, significa que ese número es par.

El resultado: una página que muestra el texto impar.

Page 100: Desarrollo Web Con PHP y MySQL

Sólo tiene que cambiar el valor que se pasa por un númeropar (digamos seis) para que la página resultante muestreel texto par.

Valor y referencia

La función par_impar() recibe un número comoparámetro, comprueba que el valor sea par o impar yescribe un mensaje. El valor recibido no sufre alteración.Pero ¿qué pasaría si lo modificásemos? Fíjese en elsiguiente código, no lo escriba en una página paraprobarlo:

<?php

function incrementar($numero){

$numero++;

}

$i = 7;

incrementar($i);

print($i);

?>

¿Qué pasará, qué valor mostrará una página con estecódigo? Claro, si se lo estamos preguntando será porqueno es obvio. Tiene razón. Podría suponer que la páginaresultante mostrará el número ocho, resultado deincrementar el parámetro de la función. La realidad es otra:se muestra el número siete.

PHP permite que los parámetros de una función sepasen de dos formas: por valor y por referencia. Unparámetro se pasa por valor de forma predeterminada, sinnecesidad de hacer nada más, como en nuestra funciónincrementar(). En realidad, a la función le estamospasando una copia de la variable $i. Cualquier modificaciónque hagamos a dicha variable se perderá al terminar lafunción.

Si quiere que los parámetros que pase a la funciónpuedan ser modificados y que esos cambios sobrevivan ala llamada de la función, ha de indicarle a PHP que eseparámetro se va a pasar por referencia. Entonces, en lugarde pasar una copia de la variable, PHP pasará la variableen sí misma.

Para lograrlo, debe volver a escribir la función añadiendoun ampersand (&) al argumento en la definición de lafunción de la siguiente forma:

function incrementar(&$numero){

$numero++;

}

Nota: En la mayoría de los casos, nuestras funciones no necesitan modificar losvalores de los parámetros que recibe. Ut ilice esta técnica sólo cuando tengasoltura con la programación en PHP. Si desea que su función devuelva algúnvalor, consulte el apartado “Devolución de valores”, más adelante.

Parámetros predeterminados

Page 101: Desarrollo Web Con PHP y MySQL

PHP nos permite determinar qué valor debe tener unparámetro si al llamar a una función dicho parámetro no seha proporcionado. Se trataría de este caso:

<?php

function par_impar($numero){

if($numero % 2 == 0){

printf('par');

}else{

print('impar');

}

}

par_impar();

?>

Si intenta cargar la página anterior, PHP le avisará queno se ha pasado argumento alguno a la funciónpar_impar(), como puede verse en la figura 4.1. Sinembargo, al tratarse de un aviso (o warning), el código de lapágina se ejecutará. Puede comprobarlo porque al final dela misma puede leerse el texto par. Efectivamente, el restode dividir cero entre cero es cero, por lo que la funcióndetermina que el número pasado como parámetro es par.

Figura 4.1. Aviso de PHP

Nota: En el mensaje de aviso puede verse la ruta en la que se encuentran laspáginas. La carpeta en la que está instalado Apache en su ordenador puede serotra.

Es muy sencillo evitar el aviso anterior. Sólo tiene queespecificar el valor predeterminado del parámetro, que esel valor que toma cuando ese parámetro no se pasa:

function par_impar($numero = 0){

if($numero % 2 == 0){

printf('par');

}else{

print('impar');

}

}

El comportamiento de la función es idéntico al que teníaantes, con la salvedad de que no se produce ningún aviso.

Argumentos variables

Como hemos comentado, puede crear funciones queacepten más de un parámetro. Pero PHP ofrece unaposibilidad muy interesante: crear funciones que aceptan

Page 102: Desarrollo Web Con PHP y MySQL

un número variable de parámetros.

Para ello, ha de crear una función sin parámetro alguno yluego ayudarse de las funciones de PHP func_num_args(),func_get_arg() y func_get_args().

La primera de estas funciones devuelve el número deargumentos que la función ha recibido, la segunda unargumento en concreto de la lista de argumentos y latercera una matriz con todos los argumentos que se hanpasado a la función.

Gracias al uso de estas funciones podrá crear con muchafacilidad una función que reciba una lista de valores ymuestre en la página el resultado de sumarlos todos:

<?php

function sumatorio(){

$parametros = func_num_args();

for($i = 0; $i < $parametros; $i++){

$resultado += func_get_arg($i);

}

printf($resultado);

}

sumatorio(3, 14, 15);

?>

La función sumatorio(), en primer lugar, guarda en lavariable $parametros el número de argumentos que harecibido. Después, usando un bucle for recupera uno poruno el valor de los parámetros y los suma. Para terminar,muestra el resultado. En este ejemplo, 32.

Utilizando la función func_get_args(), que devuelve unamatriz con todos los argumentos y el bucle foreachpodemos simplificar bastante el código:

<?php

function sumatorio(){

foreach(func_get_args() as $parametro){

$resultado += $parametro;

}

printf($resultado);

}

sumatorio(3, 14, 15);

?>

Como recordará, la instrucción foreach permite iterar portodos los elementos de una determinada matriz. Lavariable $parametro contendrá en cada iteración unelemento diferente de la matriz. Al finalizar todas lasiteraciones, $resultado contendrá la suma de todos losargumentos pasados a la función.

El resultado será idéntico tanto usando un bucle forcomo usando un bucle foreach. La diferencia está en queel código del segundo es mucho más simple.

¡Un momento! Vamos a parar un momento. ¿Qué es esode que la función func_get_arg() devuelve una matriz?

Page 103: Desarrollo Web Con PHP y MySQL

¿Cómo puedo hacer para que mis funciones devuelvanvalores?

Devolución de valores

Nada más fácil que conseguir que una función escrita porusted devuelva un valor. Sólo ha de utilizar la instrucciónreturn. A continuación de ella indique el valor que lafunción debe devolver. En ese punto la función terminará,devolviendo el valor que ha indicado al código que la llamó.

Por ejemplo, puede cambiar el código de la funciónpar_impar() que construimos anteriormente. Ahora lafunción devolverá TRUE si el número pasado es par yFALSE en caso contrario:

function par_impar($numero){

if($numero % 2 == 0){

return(TRUE);

}else{

return(FALSE);

}

}

De esta forma, cedemos la decisión de escribir un textoen la página Web resultante al código que llama a lafunción, en lugar de hacerlo directamente desde dentro deella. El código completo del programa podría ser elsiguiente:

<?php

function par_impar($numero){

if($numero % 2 == 0){

return(TRUE);

}else{

return(FALSE);

}

}

if(par_impar(7) == TRUE){

print('par');

}else{

print('impar');

}

?>

Trabajando con funciones

Hasta ahora, en este libro hemos tenido dos contactoscon PHP. En el primer capítulo fue un encontronazo, sólonos interesaba tener una visión de conjunto de lasposibilidades que MySQL y PHP ofrecían. El segundo, mássosegado, nos permitió aprender las principales reglas dellenguaje.

Vamos a quedarnos con el primer capítulo. Si recuerda,construimos un pequeño programa para mostrar losgéneros cinematográficos que se encontrasenalmacenados dentro de la tabla genero de la base dedatos videoteca. Fue entonces cuando comprobamos que,al añadir nuevos registros a dicha tabla, el contenido de la

Page 104: Desarrollo Web Con PHP y MySQL

al añadir nuevos registros a dicha tabla, el contenido de lapágina Web cambiaba sin necesidad de modificar el códigoPHP.

Por si acaso se saltó el primer capítulo, resumiremos.Ejecute el siguiente código SQL para crear la base dedatos videoteca y la tabla genero e insertar los valoresiniciales:

DROP DATABASE IF EXISTS videoteca;

CREATE DATABASE videoteca;

USE videoteca;

CREATE TABLE genero (

id INT UNSIGNED NOT NULL AUTO_INCREMENT,

nombre VARCHAR(2) NOT NULL,

descripcion VARCHAR(32) NOT NULL,

PRIMARY KEY(id)

);

INSERT INTO genero(nombre, descripcion)

VALUES('CF', 'Ciencia Ficción');

INSERT INTO genero(nombre, descripcion)

VALUES('A', 'Aventuras');

INSERT INTO genero(nombre, descripcion)

VALUES('D', 'Drama');

INSERT INTO genero(nombre, descripcion)

VALUES('T', 'Terror');

La versión final del código de dicha página es elsiguiente:

<?php

$conexion = mysqli_connect(

'localhost',

'root',

'',

'videoteca'

);

if ($conexion == FALSE){

echo('Error en la conexión.');

exit();

}

$res = mysqli_query(

$conexion,

'SELECT * FROM genero'

);

if ($res == FALSE){

echo('Error en la consulta.');

mysqli_close($conexion);

exit();

}

?>

Page 105: Desarrollo Web Con PHP y MySQL

<table border="1">

<tr>

<th>id</th>

<th>nombre</th>

<th>descripcion</th>

</tr>

<?php

while($fila = mysqli_fetch_row($res)){

printf('<tr>');

printf(

"<td>%u</td><td>%s</td><td>%s</td>",

$fila[0], $fila[1], $fila[2]

);

printf('</tr>');

}

?>

</table>

<?php

mysqli_free_result($res);

mysqli_close($conexion);

?>

La figura 4.2 muestra el resultado de ejecutar el códigoPHP anterior.

Figura 4.2. Lista de géneros

Si se fija en el listado de la página podrá comprobar queel código PHP está muy mezclado con el código HTML. Hasido necesario escapar de PHP en varias ocasiones. ¿Nosería mucho más cómodo disponer de todo el código quese encarga de obtener el listado de géneros agrupado?

Un primer intento podría consistir en situar todo lorelacionado con MySQL al comienzo del programa. Puedecambiar el comportamiento del bucle while, para que creeuna cadena de texto a partir de los resultados obtenidos alrealizar la consulta.

A continuación escaparíamos de PHP. Sólo tenemos quevolver a PHP desde HTML para escribir la cadena quecontiene el listado de géneros. Podría ser algo así:

<?php

$conexion = mysqli_connect(

'localhost',

Page 106: Desarrollo Web Con PHP y MySQL

'root',

'',

'videoteca'

);

if ($conexion == FALSE){

echo('Error en la conexión.');

exit();

}

$res = mysqli_query(

$conexion,

'SELECT * FROM genero'

);

if ($res == FALSE){

echo('Error en la consulta.');

mysqli_close($conexion);

exit();

}

while($fila = mysqli_fetch_row($res)){

$generos .= '<tr>';

$generos .= sprintf(

"<td>%u</td><td>%s</td><td>%s</td>",

$fila[0], $fila[1], $fila[2]

);

$generos .= sprintf('</tr>');

}

mysqli_free_result($res);

mysqli_close($conexion);

?>

<table border="1">

<tr>

<th>id</th>

<th>nombre</th>

<th>descripcion</th>

</tr>

<?php

print($generos);

?>

</table>

El resultado es el mismo que puede verse en la figura4.2, aunque el código está algo más ordenado, con dosbloques: uno con PHP y otro con HTML.

¿Y qué nos impide ubicar todo el código PHP en unaúnica función, que devuelva como resultado una cadena detexto con todos los géneros cinematográficos en filas parainsertar en una tabla? Por ejemplo, así:

<?php

function cargar_generos(){

Page 107: Desarrollo Web Con PHP y MySQL

function cargar_generos(){

$conexion = mysqli_connect(

'localhost',

'root',

'',

'videoteca'

);

if ($conexion == FALSE){

echo('Error en la conexión.');

exit();

}

$res = mysqli_query(

$conexion,

'SELECT * FROM genero'

);

if ($res == FALSE){

echo('Error en la consulta.');

mysqli_close($conexion);

exit();

}

while($fila = mysqli_fetch_row($res)){

$generos .= '<tr>';

$generos .= sprintf(

"<td>%u</td><td>%s</td><td>%s</td>",

$fila[0], $fila[1], $fila[2]

);

$generos .= sprintf('</tr>');

}

mysqli_free_result($res);

mysqli_close($conexion);

return $generos;

}

?>

<table border="1">

<tr>

<th>id</th>

<th>nombre</th>

<th>descripcion</th>

</tr>

<?php

print(cargar_generos());

?>

</table>

Nota: Queda como ejercicio para el lector conseguir que la funcióncargar_generos() devuelva una cadena con toda la tabla en formato HTML, enlugar de devolver sólo las filas.

Hemos conseguido colocar en una función todo el códigonecesario para cargar el listado de géneroscinematográficos. Puede cargar ese listado todas las vecesque quiera llamando a la función varias veces.

Page 108: Desarrollo Web Con PHP y MySQL

Ahora bien, si quiere escribir otra página diferente, quetambién muestre el listado de géneros tendrá que escribirde nuevo el código de la función. Aunque existe una formade ahorrarse ese trabajo.

Inclusión de archivos

Vamos a crear un nuevo archivo PHP cuyo contenidoserá única y exclusivamente la función de carga degéneros que acabamos de crear. Ese archivo podríallamarse generos.php:

<?php

function cargar_generos(){

$conexion = mysqli_connect(

'localhost',

'root',

'',

'videoteca'

);

if ($conexion == FALSE){

echo('Error en la conexión.');

exit();

}

$res = mysqli_query(

$conexion,

'SELECT * FROM genero'

);

if ($res == FALSE){

echo('Error en la consulta.');

mysqli_close($conexion);

exit();

}

while($fila = mysqli_fetch_row($res)){

$generos .= '<tr>';

$generos .= sprintf(

"<td>%u</td><td>%s</td><td>%s</td>",

$fila[0], $fila[1], $fila[2]

);

$generos .= sprintf('</tr>');

}

mysqli_free_result($res);

mysqli_close($conexion);

return $generos;

}

?>

A continuación, crearemos un segundo archivo PHP conel siguiente contenido:

<?php

include('generos.php');

?>

<table border="1">

Page 109: Desarrollo Web Con PHP y MySQL

<table border="1">

<tr>

<th>id</th>

<th>nombre</th>

<th>descripcion</th>

</tr>

<?php

print(cargar_generos());

?>

</table>

Ambos archivos deben estar en la misma carpeta. Podrácomprobar que, al cargar la segunda página, obtendrá elmismo resultado que pudo verse en la figura 4.2. Sinembargo, el código de esta segunda página esconsiderablemente menor que el que se utilizóanteriormente.

Cuando PHP analiza el archivo para saber qué tiene quehacer cuando alguien le pide esa página, encuentra lainstrucción include. Entonces busca el archivo indicado acontinuación y lo incluye en la página actual, como siefectivamente ambos fragmentos de código fuesen partede la misma página.

¿Qué ocurre si el archivo que se intenta incluir noexiste? PHP nos avisará de ello, pero aún así intentaráejecutar el código del resto de la página. Si quiere evitarque el resto de la página se siga ejecutando, puede utilizarla instrucción requiere, que sí provoca un error. Puede verun error de este tipo en la figura 4.3.

Figura 4.3. Archivo no encontrado

Nota: Si desea incluir un determinado archivo sólo una vez dentro del contextode una misma página ut ilice include_once(). También existe require_once(). Lasdiferencias entre estas dos son las mismas que entre include() y require().

Ha aprendido a reutilizar el código mediante funciones,guardando esas funciones en archivos independientes queluego pueden ser incluidos en otros archivos PHP. Un pasomás allá está la programación orientada a objetos, quetambién permite reutilizar código pero que proporcionaotras ventajas que veremos a continuación.

Orientación a objetos

Page 110: Desarrollo Web Con PHP y MySQL

Ríos de tinta han corrido hablando de la programaciónorientada a objetos, tan de moda durante mucho tiempocomo XML lo está siendo ahora.

La versión de PHP 5 incorporó muchas novedades, perola mayoría de ellas en lo referido a la orientación a objetos.Sería muy pretencioso por nuestra parte intentar exponertodas esas novedades con el espacio del que disponemos,de manera que vamos a limitarnos a sentar las basesnecesarias para que esta metodología de programación nole sea desconocida.

La programación orientada a objetos tiene comofinalidad una mejor organización de código y su posiblereutilización. Para lograrlo hemos de intentar localizar lasdiferentes entidades con las que trabajamos en nuestrosprogramas y aislarlas.

Por ejemplo, los programas anteriores mostraban la listade categorías disponibles. Podríamos intentar escribir unprograma cuyo resultado fuese el mismo, pero utilizandoorientación a objetos.

¿Qué es un objeto? Un ejemplar de una clase. Y unaclase, ¿qué es una clase?

Clases

Podemos definir una clase como la plantilla utilizadapara crear un objeto. En una clase se definen laspropiedades y los métodos de los objetos creados a partirde ella.

Las propiedades de una clase describen su aspectomientras que los métodos se corresponden con sucomportamiento. Intentemos crear una clase querepresente a los géneros cinematográficos almacenadosen la base de datos. Las propiedades pueden ser deescritura, de lectura o de ambos tipos, dependiendo de sipuede asignarles valores o no.

¿Qué puede ser "el aspecto" de la lista de géneros? Porejemplo, su ordenación. Una propiedad de la clase para losgéneros podría determinar si el resultado se debe ordenaralfabéticamente o no.

En cuanto al comportamiento, lo tenemos fácil:necesitamos poder pedir a la clase de géneros que carguelos géneros de la base de datos. El resultado de estaoperación será una cadena de texto con las filas enformato HTML, como la devuelta por la funcióncargar_generos().

La figura 4.4 muestra una posible representación gráficade una clase. A la izquierda de la caja, los métodos de laclase, a la derecha sus propiedades. Una flecha de entradaindica si la propiedad es de lectura, una de salida si es deescritura. Si un método devuelve un valor, la flecha será desalida.

Page 111: Desarrollo Web Con PHP y MySQL

Figura 4.4. Diagrama de una clase

Este diagrama describe a la clase perfectamente. Lapropiedad Ordenada es de escritura, mientras que elmétodo Cargar() devuelve un valor. El nombre de la clasees clsGeneros. Sólo nos queda crear la clase. Para ellosvamos a utilizar un archivo que luego incluiremos en laspáginas PHP que vayan a utilizar esta clase. El archivo sellamará generos.cls.php.

El método Cargar() será similar a la funcióncargar_generos(). Este método devuelve una cadena detexto que contiene todos los géneros de la base de datos.

La propiedad Ordenada será de tipo booleano, de formaque podrá asignarle valores TRUE o FALSE. Si le asignaTRUE el resultado de llamar al método Cargar() estaráordenado alfabéticamente. En caso contrario, el resultadose mostrará tal cual esté en la base de datos, sinordenación de ningún tipo.

Nota: Si desea más información sobre consultas SQL consulte el capítulo 6, queestá dedicado a ello.

Por tanto, el contenido del archivo generos.cls.phppodría ser el siguiente:

<?php

class clsGeneros{

var $Ordenada = False;

function Cargar(){

$conexion = mysqli_connect(

'localhost',

'root',

'',

'videoteca'

);

if ($conexion == FALSE){

echo('Error en la conexión.');

exit();

}

if($this->Ordenada == TRUE){

Page 112: Desarrollo Web Con PHP y MySQL

$res = mysqli_query(

$conexion,

'SELECT * FROM genero '.

'ORDER BY nombre'

);

}else{

$res = mysqli_query(

$conexion,

'SELECT * FROM genero'

);

}

if ($res == FALSE){

echo('Error en la consulta.');

mysqli_close($conexion);

exit();

}

while($fila=mysqli_fetch_row($res)){

$generos .= '<tr>';

$generos .= sprintf(

"<td>%u</td><td>%s</td><td>%s</td>",

$fila[0], $fila[1], $fila[2]

);

$generos .= sprintf('</tr>');

}

mysqli_free_result($res);

mysqli_close($conexion);

return $generos;

}

}

?>

Como puede verse en el código anterior, comenzamos ladeclaración de la clase con la palabra reservada class. Acontinuación, definimos el nombre de la clase:clsGeneros. El prefijo sirve para indicar que se trata deuna clase. El código de la clase está entre llaves.

Dentro de una clase puede definir variables, como$Ordenada, cuyo valor predeterminado es FALSE. Estavariable es una de las propiedades de la clase. Esnecesario utilizar la palabra reservada var antes dedeclarar una variable propia de una clase.

El código del método Cargar() es como el de la funcióncargar_generos(), con la que hemos estado trabajandoanteriormente, con una salvedad: la consulta que obtienelos géneros de la base de datos es diferente, dependiendodel valor que tenga $Ordenada, estando el resultadoordenado por nombre si su valor es TRUE.

Nota: PHP proporciona un objeto especial llamado $this, que permite acceder alas propiedades y métodos de una clase desde el código de la propia clase.

Page 113: Desarrollo Web Con PHP y MySQL

Piense en esta clase como en una plantilla. La clase porsí misma no hace nada, pero si crea en su programa unavariable cuyo tipo sea la clase tendrá acceso a toda lafuncionalidad definida en dicha clase. Veamos un ejemplo:

<?php

require('generos.cls.php');

$oGeneros = new clsGeneros;

$oGeneros->Ordenada = TRUE;

$sGeneros = $oGeneros->Cargar();

?>

<table border="1">

<tr>

<th>id</th>

<th>nombre</th>

<th>descripción</th>

</tr>

<?php

print($sGeneros);

?>

</table>

Nuestra página comienza incluyendo aquella en la quese encuentra el código de definición de la clase. Fíjese enque utilizamos require en lugar de include, ya que dichapágina es imprescindible para la ejecución de ésta.

Cuando declaramos una variable cuyo tipo es unadeterminada clase se dice que estamos creando unejemplar de esa clase. La clase es la plantilla, el ejemplarde la clase es el objeto. Para crear dicho ejemplar hemosde utilizar la palabra reserva new:

$oGeneros = new clsGeneros;

Es decir, esta línea crea un nuevo ejemplar de la claseclsGeneros y lo asigna (lo guarda) en la variable$oGeneros. El prefijo o viene de objeto.

Una vez tenga el objeto necesita acceder a suspropiedades para modificar su comportamiento y realizartareas mediante sus métodos. Para ello ha de utilizar loscaracteres -> a continuación del nombre del objeto, y trasestos caracteres, el nombre de la propiedad o el métodoque quiere utilizar. En el programa anterior modificamos elvalor de la propiedad Ordenada así:

$oGeneros->Ordenada = TRUE;

Y llamamos al método de carga de los géneros así:

$sGeneros = $oGeneros->Cargar();

El resultado de este programa es similar al que pudimosver en la figura 4.2, pero la ordenación es diferente. Puedecomprobarlo en la figura 4.5.

Page 114: Desarrollo Web Con PHP y MySQL

Figura 4.5. Géneros ordenados por nombre

Puede crear tantos ejemplares de la clase clsGeneroscomo necesite, y cada uno de ellos tendrá sus propiaspropiedades. El siguiente código es perfectamente válido:

<?php

require('generos.cls.php');

$oGeneros1 = new clsGeneros;

$oGeneros2 = new clsGeneros;

$oGeneros1->Ordenada = TRUE;

$oGeneros2->Ordenada = FALSE;

$sGeneros1 = $oGeneros1->Cargar();

$sGeneros2 = $oGeneros2->Cargar();

?>

<table><tr><td>

<table border="1">

<tr>

<th>id</th>

<th>nombre</th>

<th>descripción</th>

</tr>

<?php

print($sGeneros1);

?>

</table>

</td><td>

<table border="1">

<tr>

<th>id</th>

<th>nombre</th>

<th>descripción</th>

</tr>

<?php

print($sGeneros2);

?>

</table>

Page 115: Desarrollo Web Con PHP y MySQL

</table>

</td></tr></table>

Como resultado de cargar esta página obtendrá dostablas, la primera mostrará la lista de géneros ordenadospor nombre, mientras que la segunda no. Puede verlo en lafigura 4.6.

Figura 4.6. Con y sin orden

En la definición de la clase asigne un valor inicial a lapropiedad $Ordenada. Esa operación puede realizarse deotra manera: utilizando un constructor.

Constructores

Dentro de una clase, el constructor es un métodoespecial que se ejecuta siempre que se crea un ejemplarde dicha clase. El nombre de ese método especial debe serel mismo que el de la clase.

Si añade el siguiente método al código de la claseclsGeneros tendrá su constructor. Hágalo justo debajo dela definición del método de carga:

var $Ordenada;

...

function clsGeneros(){

$this->Ordenada = TRUE;

}

Hemos trasladado la asignación de un valor inicial a$Ordenada al constructor de la clase. Ahora, elcomportamiento predeterminado del método de carga serádevolver la lista de géneros ordenada.

Como si de un método normal y corriente se tratase, esposible definir una lista de argumentos que el constructorpuede recibir. Sería interesante que recibiese si quiere ono la lista de géneros ordenada:

function clsGeneros($fOrdenada){

$this->Ordenada = $fOrdenada;

}

Al crear el ejemplar de la clase indicaremos si queremosordenación o no:

$oGeneros = new clsGeneros(TRUE);

Más allá de las clases

Page 116: Desarrollo Web Con PHP y MySQL

Con lo visto en este capítulo sobre las clases en PHP nohemos hecho más que descubrir la punta del iceberg. En eltintero hemos dejado algunas de las características másaplaudidas de la programación orientada a objetos:encapsulación, herencia y polimorfismo. De hecho, sonestas tres características las que diferencian este sistemade programación de otros.

La encapsulación, en la jerga de los programadores, esla capacidad de ocultar las interioridades de las clases aaquellos que las usan. Sin ir más lejos, el método de cargade la clase clsGeneros utiliza la interfaz mejorada deacceso a MySQL pero, si alguien utiliza esa clase paraacceder al listado de géneros, ¿debería saber que esosgéneros están en una base de datos? No necesariamente.Al usuario le basta con saber que cuando crea un ejemplarde la clase y llama a su método de carga obtiene la lista degéneros.

Si más adelante, el programador de clsGeneros decideque el listado de géneros se debe obtener utilizando otrainterfaz de acceso a datos, mientras mantenga el mismosistema para obtenerlos, aquellos programas que utilicenesa clase no deberán ser modificados.

La programación orientada a objetos busca símiles entreel mundo real y el de la programación para simplificar lacreación y el mantenimiento de programas. La herencia esotro símil, muy próximo al significado de esta palabra en elmundo real. Puede crear una clase con unas determinadascaracterísticas y, posteriormente, otra que herede de laprimera. La clase heredera tendrá todas las característicasde la primera pero podrá incorporar novedades, lo que leahorrará mucho trabajo.

Por último, el polimorfismo permite tratar clases dediferente tipo como si fuesen del mismo, algo que puedeser de gran utilidad en determinadas circunstancias.

No nos extenderemos más para hablar de estascaracterísticas de la programación orientada a objetos,algo que queda fuera de los objetivos de este libro. Sinembargo, queremos que conozca de su existencia y lerecomendamos que busque más información al respecto,ya que sus programas pueden beneficiarse enormementede ellas.

Page 117: Desarrollo Web Con PHP y MySQL

5

Diseño de bases de datos

Por lo general, creamos bases de datos para poderextraer de ellas posteriormente todo tipo de informaciónútil. Pero los datos no deben guardarse de cualquiermanera, hemos de buscar el mayor aprovechamiento delos recursos disponibles, tanto de espacio como derendimiento.

La consistencia de los datos ha de mantenerse durantetodo el ciclo de vida de la base de datos, sobre todo si éstavaya a utilizarse en aplicaciones críticas, como lasdestinadas a emitir las nóminas de los empleados de unaempresa. Si los datos almacenados no mantuviesen laconsistencia alguien podría acabar no cobrando este mes.

El primer paso en la creación de una base de datos es elanálisis del sistema que servirá de modelo, la observaciónde todos los elementos que lo componen y sudescomposición en partes más pequeñas.

Tras el análisis, procederemos con el diseño de la basede datos. Un diseño correcto puede ser crucial, de maneraque debe dedicarle todo el tiempo necesario hasta estarcompletamente seguro de que no existan incongruencias ytodos los aspectos del sistema están reflejados en la basedatos.

Durante este capítulo recorreremos todos los pasos quedeben darse para dar vida a una base de datos, desde laidea inicial hasta su creación, pasando por los pasosintermedios necesarios. Veremos qué herramientas estána nuestra disposición, tanto las conceptuales como losprogramas.

Al terminar dispondremos de un diseño completo de labase de datos que utilizará como ejemplo durante el restode capítulos.

El ejemplo

En el capítulo 3 se utilizó como ejemplo una pequeñabase de datos que contenía una única tabla en la que sealmacenaban sólo tres datos de cada película de unavideoteca: el título, el nombre del director y el de uno desus intérpretes. La figura 5.1 muestra el diseño que se hizode dicha tabla.

Figura 5.1. Primer diseño del ejemplo

En esta tabla se pueden guardar perfectamente losdatos de todas las películas que desee, aunque no sin

Page 118: Desarrollo Web Con PHP y MySQL

limitaciones. De hecho, se trata de una base de datos algolimitada... bueno, muy limitada. ¡Bah, para quéengañarnos! La primera versión de la base de datos deejemplo no sirve para nada. Se podría conseguir lo mismousando una hoja de cálculo creada con Excel, Gnumeric oNumbers. Al menos sirvió para su propósito: una primeratoma de contacto con el servidor de bases de datosMySQL.

Limitaciones

La primera versión de la base de datos de ejemplo esdemasiado simple. Sólo se puede guardar el nombre deuno de los intérpretes de la película, aunque sería muchomás interesante tener los nombres de tantos actoresrelacionados con un título en concreto como se quisiese. Yaunque no es muy frecuente, existen algunas películas conmás de un director.

Tampoco se guarda detalle alguno sobre la duración dela película, su fecha de estreno, sus productores,guionistas, es decir, su ficha técnica. Ni se pueden conocerdetalles relativos a una copia de la película en particular,como si el formato es VHS o DVD, o si se ha prestado, laopinión que le merece o les mereció a otros, etcétera.

Por otra parte, en esta primera versión, cada vez que seguarda una película se han de guardar los datos deldirector y del actor, incluso si con anterioridad existíaalgún registro con el mismo actor o director. Quizá losdatos podrían estar mejor organizados.

Objetivos

Antes de diseñar de nuevo el ejemplo es necesario darotros pasos. En primer lugar, debemos conocer lasherramientas que tenemos a nuestra disposición para lacreación de bases de datos. Por herramientas no sólo nosreferimos a los programas, también a otras de tipoconceptual de las que daremos buena cuenta durante estecapítulo.

En la parte de los programas veremos cómo utilizarMySQL Workbench. Esta aplicación le ayudará en la fasede diseño de bases de datos y en su posterior puesta enmarcha, ya que genera de forma automática el código SQLnecesario para la creación de bases de datos y tablas. Setrata de un programa de código abierto que se distribuyebajo licencia GPL, creado por la empresa detrás de MySQLsobre las cenizas de DBDesigner.

Nota: Aunque en el momento de escribir estas líneas las versiones para Mac OSX y Linux están en fase alfa, el equipo de desarrollo de MySQL Workbench se hacomprometido a lanzarla en las t res plataformas.

En cuanto a las herramientas conceptuales, primeroveremos algunos conceptos que no se han tratado aún. Esel caso del modelo relacional, imprescindible como ayudapara mantener la integridad de los datos. El capítulo

Page 119: Desarrollo Web Con PHP y MySQL

terminará con algunas indicaciones sobre los pasos aseguir para que las bases de datos puedan almacenar losdatos de forma inequívoca.

MySQL Workbench

Según las propias palabras del equipo encargado deldesarrollo de esta aplicación, "MySQL Workbench es unaherramienta para el diseño visual de bases de datosdesarrollada por MySQL. Se trata del esperado sucesor delproyecto DBDesigner4". DBDesigner era (y sigue siendo,visite http://fabforce.net/dbdesigner4/) un sistema para eldiseño visual de bases de datos que integraba en unentorno unificado las fases de diseño, modelado, creacióny mantenimiento.

Con MySQL Workbench es posible diseñar tablas,cambiar los tipos de las columnas, sus nombres, una y otravez, sin tener que escribir ni una sola línea de código. Ycuando estemos satisfechos con nuestro trabajo, elprograma puede generar por nosotros todo el códigonecesario para crear la base de datos en MySQL. En lafigura 5.2 puede ver el entorno que este programaproporciona.

Figura 5.2. Entorno de trabajo de MySQL Workbench

No se trata del único programa de este tipo que existe.Otras alternativas son:

Navicat, de PremiumSoft.PowerDesigner, de Sybase.

Page 120: Desarrollo Web Con PHP y MySQL

DataArchitect, de theKompany.Rational Rose, de IBM.

Lo que diferencia a MySQL Workbench del resto es sulicencia GPL, la disponibilidad para múltiples sistemasoperativos y, sobre todo, que está mejor integrado conMySQL que los demás. Es normal, ambos productos estándesarrollados por la misma empresa.

Instalación

MySQL Workbench está siendo desarrollado para tresplataformas muy diversas. Por lo que sabemos,aprovechará las características particulares de cada una deellas, de manera que el proceso de instalación serádiferente en cada sistema operativo:

En Windows se utiliza el típico programa de instalaciónguiado por asistente. No existen demasiadas opcionesque configurar, basta con seguir los pasos y podremosutilizar el programa en un periquete.En Linux, por el momento, las primeras versionesdisponibles se están ofreciendo a través de sistemastan utilizados como APT, disponible Debian y Ubuntu,por ejemplo. A medida de que esta versión madureestará disponible en los gestores para la instalación depaquetes del resto de distribuciones.Las imágenes de disco (archivos DMG) se utilizan parala instalación en Mac OS X. Basta con hacer doble clicsobre el archivo ofrecido para esta plataforma yarrastrar el contenido del mismo a la carpeta deaplicaciones.

Nota: De momento, MySQL Workbench se distribuirá en dos versiones, siguiendolo que parece será una norma. Por una parte está la versión para la comunidad,disponible de manera gratuita y bajo licencia GPL. Por otra, la versión estándar,distribuida bajo una licencia comercial. Adivine cuál de las dos versiones ofrecemás característ icas. Es posible que, en el futuro, aparezcan más ediciones paracomplementar a estas dos.

Conceptos varios

Antes de comenzar con el diseño del ejemplo queutilizaremos durante este libro es necesario que conozcaalgunos conceptos que se utilizan en la mayoría de lossistemas gestores de bases de datos y, como no podía serde otra manera, también en MySQL.

El valor NULL

O el infierno por el que han de pasar muchos. Pidodisculpas si no puedo ser parcial en esta sección: hesufrido mucho con NULL.

El valor NULL es una de esas herramientas que no dejanindiferentes: muchos la encuentran indispensable, otrosprefieren atravesarse el ojo con un hierro al rojo vivo hastallegar al cerebro antes que utilizarlo.

Page 121: Desarrollo Web Con PHP y MySQL

Parece que he dejado clara mi opinión, mas no se dejeinfluir, permítame que le explique con total imparcialidadcómo funciona NULL. Si no existe un valor para unadeterminada columna, se suele guardar unorepresentativo, como una cadena vacía o un cero,dependiendo del tipo de datos de la columna. Pero, ¿quéhacer cuando no se conoce el valor de esa columna?

Precisamente ésa es la función de NULL: es el valorcontenido en las columnas para las que no se haintroducido dato alguno.

Cualquier columna que cree dentro de una tabla,independientemente de su tipo, puede almacenar estevalor, a no ser que explícitamente se diga lo contrario.Recuerde que, cuando creó la tabla pelicula en el tercercapítulo, lo hizo así:

USE videoteca;

CREATE TABLE pelicula(

titulo VARCHAR(64),

director VARCHAR(128),

actor VARCHAR(128)

);

Como ya insertó algunos registros en esta tabla puederealizar consultas de selección sobre ella. La siguienteconsulta muestra el título de las películas en una columnay, concatenados, el nombre de director y el del actor,separados por comas:

USE videoteca;

SELECT

titulo,

CONCAT(director, ', ', actor)

FROM

pelicula;

La función CONCAT recibe como parámetros lascadenas que desee concatenar. En este caso seconcatenan tres: el nombre del director, una coma seguidade un espacio y el nombre del actor. El resultado de estaconsulta puede verse en la figura 5.3.

Figura 5.3. Concatenación de dos cadenas

Page 122: Desarrollo Web Con PHP y MySQL

Ahora vamos a insertar una nueva película. De ellaconocemos el título y el nombre del director, pero ningúnintérprete:

USE videoteca;

INSERT INTO pelicula(

titulo,

director

)

VALUES(

'Naves misteriosas',

'Douglas Trumbull'

);

La inserción se realizará sin problemas. La columnaactor contendrá el valor NULL, ya que no se proporcionóvalor alguno durante la inserción. La siguiente consulta deselección devolverá los valores que pueden verse en lafigura 5.4:

USE videoteca;

SELECT

*

FROM

pelicula;

Figura 5.4. Se ha insertado NULL

¿Qué ocurrirá ahora si vuelve a utilizar la consulta queconcatena el nombre del director y el del actor? Podríamosesperar que sólo devolviese el título de la película y elnombre del director, sin el actor. Pero la realidad puedeverse en la figura 5.5.

Figura 5.5. Concatenación con NULL

Y no se trata de un comportamiento erróneo, así escomo debe ser. El resultado de comparar cualquier valor

Page 123: Desarrollo Web Con PHP y MySQL

con NULL es NULL. Cualquier operación aritmética en laque participe un valor NULL da como resultado NULL.Cualquier concatenación con NULL acaba siendo NULL.

Existen variadas alternativas para evitar estecomportamiento, como el uso de cadenas vacías. Porsimplicidad, la recomendación desde aquí es evitar en loposible el uso de valores nulos. Quede claro que estarecomendación se debe nada más que a experienciaspersonales.

Para evitar la inserción de valores nulos en los camposde la tabla de películas puede cambiar la forma en la quese crea:

USE videoteca;

DROP TABLE IF EXISTS pelicula;

CREATE TABLE pelicula(

titulo VARCHAR(64) NOT NULL,

director VARCHAR(128) NOT NULL,

actor VARCHAR(128) NOT NULL

);

De esta forma, si en una inserción no indica el valor dealguna columna, como en la última que se ha utilizadopara la película "Naves misteriosas", se producirá un error.

Puede evitar la aparición de dicho error si asigna unvalor predeterminado para las columnas no obligatorias.En el caso de la tabla de películas podríamos hacerobligatorio el título, pero no el director ni el actor. Elsiguiente código hará que se guarde una cadena vacía enesas columnas si no se indica un valor para ellas durantelas inserciones:

USE videoteca;

DROP TABLE IF EXISTS pelicula;

CREATE TABLE pelicula(

titulo VARCHAR(64) NOT NULL,

director VARCHAR(128) NOT NULL DEFAULT '',

actor VARCHAR(128) NOT NULL DEFAULT ''

);

También es posible cambiar las propiedades de la tablade películas de acuerdo a lo que acaba de ver, pero sineliminar los registros que ya ha insertado en ella.Empecemos por eliminar la película que acabamos deañadir ya que el valor nulo en la columna actor de la tablade películas impide la modificación de dicha característicade la tabla:

USE videoteca;

DELETE FROM

pelicula

WHERE

titulo = 'Naves misteriosas';

Utilice la instrucción ALTER TABLE que vimos en el tercer capítulo:

Page 124: Desarrollo Web Con PHP y MySQL

Utilice la instrucción ALTER TABLE que vimos en el tercer capítulo:

USE videoteca;

ALTER TABLE pelicula

MODIFY titulo VARCHAR(64) NOT NULL,

MODIFY director VARCHAR(128) NOT NULL

DEFAULT '',

MODIFY actor VARCHAR(128) NOT NULL

DEFAULT '';

Si, tras modificar la tabla, vuelve a insertar la película"Naves misteriosas" y, a continuación, ejecuta la consultade selección que concatena el nombre del director y el delactor, podrá comprobar que el resultado ya no incluyeningún NULL, con lo que es posible utilizar la mismaconsulta para aquellas películas de las que no conozca sudirector o su actor. La figura 5.6 muestra el resultado dedicha consulta.

Figura 5.6. Concatenación sin NULL

Claves primarias

Para explicar qué es una clave primaria vamos a volver autilizar la tabla pelicula, que está dando mucho juego.Insertemos una más, esta vez la segunda parte de "Alien",llamada "Aliens", dirigida por James Cameron yprotagonizada, de nuevo, por Sigourney Weaver:

USE videoteca;

INSERT INTO

pelicula

VALUES(

'Alien',

'James Cameron',

'Sigourney Weaver'

);

La inserción se realiza sin problemas. Ahora, consulte elcontenido de la tabla pelicula y ordene el resultado portítulo:

USE videoteca;

SELECT

*

FROM

pelicula

Page 125: Desarrollo Web Con PHP y MySQL

pelicula

ORDER BY

titulo;

Vea el resultado de realizar esta consulta en la figura5.7.

Figura 5.7. Con la segunda parte de "Alien"

¡Uy, qué torpe! El título no se ha introducidocorrectamente, no era Alien sino Aliens. ¡Pero aun así,MySQL ha permitido introducir dos películas con el mismotítulo! Esto no está bien, el título de la película debería seralgo único, algo que permita diferenciar una película deotras.

Y precisamente eso es una clave primaria, un valormediante el cual se puede distinguir de forma única cadaelemento de una determinada tabla. Todos los registrosdeben tener algún valor almacenado en esa columna (nose permiten valores NULL), y todos los valores de dichacolumna deben ser diferentes.

Nota: Se puede ut ilizar más de una columna como clave primaria en aquelloscasos en los que sólo se consiguen valores únicos al combinar dos columnas.Veremos un ejemplo de esto al final del capítulo, con las relaciones muchos amuchos.

Cambie la sentencia para crear la tabla pelicula demanera que el título sea la clave primaria:

USE videoteca;

CREATE TABLE pelicula(

titulo VARCHAR(64) NOT NULL,

director VARCHAR(128) NOT NULL DEFAULT '',

actor VARCHAR(128) NOT NULL DEFAULT '',

PRIMARY KEY(titulo)

);

Sólo se ha añadido una línea al final de las definicionesde las columnas para indicar qué campos componen laclave primaria. También puede modificar la tabla yaexistente, así no perderá los datos almacenados en ella:

USE videoteca;

ALTER TABLE

Page 126: Desarrollo Web Con PHP y MySQL

ALTER TABLE

pelicula

ADD PRIMARY KEY(titulo);

Y, como verá, se produce un error: existe un valorduplicado para la clave que está intentado crear.¿Recuerda? "Alien" aparece dos veces. Solucionarlo esbien sencillo:

USE videoteca;

UPDATE

pelicula

SET

titulo = 'Aliens'

WHERE

director = 'James Cameron';

Ahora que no existen dos películas con el mismo títulopuede ejecutar la consulta que añade la clave primaria a latabla sin que se produzca ningún error.

Es muy importante seleccionar las claves correctas, demanera que sean únicas. Podría llevarse una sorpresa si,con el paso del tiempo, se encuentra con que sí existendos películas con el mismo título.

Índices

Con un índice es posible encontrar más rápido los datosque se necesitan. Como en el que aparece al final de estaguía: busque el término que le interese, que encontrarárápidamente gracias a que está organizado por ordenalfabético, y allí aparecerá el número de página al quetiene que acudir. Bastante más rápido que leer desde laprimera página hasta localizarlo.

Para las tablas se puede utilizar una técnica similar. Sisabe que las búsquedas de valores de una determinadacolumna serán frecuentes, cree un índice para ella.

Hablaremos con más detalle los índices en el capítulodedicado a la optimización.

Columnas de incremento automático

Todas las operaciones de inserción realizadas en loscapítulos anteriores tenían algo en común: se conocían deantemano los valores a insertar en cada columna.

Si insertábamos de forma explícita un valor, sabíamosque éste sería el almacenado en la columna. Tambiénhemos realizado un par de inserciones implícitas, las dosen el capítulo dedicado a tipos de datos. Una de ellas, alexplicar el uso del modificador DEFAULT , que le permitíaprecisamente indicar qué valor se insertaría en unacolumna si no se indicaba ninguno. La segunda inserciónimplícita tenía lugar al utilizar el tipo TIMESTAMP. No eranecesario indicar un valor porque MySQL insertaba lafecha y la hora en la que se estaba realizando la insercióndel registro o su modificación.

Page 127: Desarrollo Web Con PHP y MySQL

Existe otra forma de insertar valores de forma implícitaen una columna: utilizando el incremento automático.

Anteriormente tomamos la decisión de utilizar comoclave primaria de la tabla de películas el título de lasmismas, porque es algo que no se repite. Sin embargo, lahistoria del cine está plagada de películas con títulosidénticos. Por ejemplo, "La cosa", dirigida por JohnCarpenter, es una nueva versión de la película del mismotítulo de 1951. ¿No debería ser posible insertar en la tablalas dos películas, con el mismo título?

Una solución podría consistir en añadir una columnamás y utilizarla como clave primaria de la tabla. La únicacondición que debe cumplir es que sea diferente para cadaregistro. Podría tratarse de un número, un identificador quepermita diferenciar entre una y otra película. Y para ahorraresfuerzos, lo ideal sería que la columna fuese deincremento automático, para que MySQL se encargase dehacer que todos sus valores fuesen diferentes.

Utilice las siguientes instrucciones para crear una tablacon esas características:

USE videoteca;

CREATE TABLE pelicula(

id INT NOT NULL AUTO_INCREMENT,

titulo VARCHAR(64) NOT NULL,

director VARCHAR(128) NOT NULL

DEFAULT '',

actor VARCHAR(128) NOT NULL

DEFAULT '',

PRIMARY KEY(id)

);

También existe la posibilidad de modificar la tabla paralograr el mismo resultado, manteniendo los registros yaexistentes:

USE videoteca;

ALTER TABLE pelicula

DROP PRIMARY KEY,

ADD id INT NOT NULL AUTO_INCREMENT FIRST,

ADD PRIMARY KEY(id);

Con cada nueva inserción en la tabla, un nuevo valor seinsertará de forma automática en la columna id,diferenciando de forma única cada registro de la misma. Siselecciona todos los registros de la tabla verá que a losexistentes ya se les ha asignado un identificador único.Puede comprobarlo en la figura 5.8. Es posible que elidentificador asignado a cada película que aparece endicha figura no sea el mismo en su caso.

Page 128: Desarrollo Web Con PHP y MySQL

Figura 5.8. Nueva clave primaria

Puede que ahora mismo no encuentre demasiadautilidad a este tipo de columnas. Sin embargo, con eltiempo comprenderá que se trata de una herramientaimprescindible. Y con el tiempo es al terminar estecapítulo.

El modelo relacional

Es posible que haya escuchado en más de una ocasiónque MySQL es un sistema gestor de bases de datosrelacionales. ¿Qué significa esto? Entre otras cosas, quees posible relacionar entre sí las diferentes tablas quecomponen una base de datos, de ahí la palabra relacional.

Tras este modelo para la organización de los datosexiste amplia documentación, tanto histórica como teórica.A los más puristas no les gustará nada que nos saltemostoda esa parte pero, a fin de cuentas, esto es una guíapráctica. Por supuesto, si está interesado podrá encontrartodas las fuentes de documentación al respecto quenecesite, tanto impresas como en Internet. Es más, lerecomendamos que lo haga.

Sin embargo, en esta guía prima lo práctico. En elmodelo relacional es necesario que las tablas compartandatos para poder relacionarlas. ¿Cómo se consigue algoasí? Vea en la figura 5.9 cómo ha quedado el diseño de latabla de películas tras aplicar lo aprendido en losapartados anteriores.

Figura 5.9. La tabla de películas, t ras algunos cambios

Si necesitase relacionar una película con otra tabla sólotendría que incluir en esa tabla el identificador de lapelícula a la que hace referencia. Lo mejor paracomprenderlo es un sencillo ejemplo.

Suponga que tiene tantas buenas películas que susamigos no hacen más que pedírselas prestadas. Perocomo de memoria no anda tan bien como de amigos ypelículas, y siempre se le olvida a quién deja qué película,ha decidido guardar en otra tabla de la base de datos unalista de préstamos. En esa lista sólo necesita almacenar el

Page 129: Desarrollo Web Con PHP y MySQL

nombre de la persona, la película que se lleva prestada yen qué fecha se la llevó, algo parecido a lo que se puedever en la figura 5.10.

Figura 5.10. Tabla de préstamos

La primera columna, id, tiene las mismas característicasque la homónima de la tabla pelicula: un identificador deincremento automático, que es la clave primaria de latabla. La segunda columna, persona, contiene el nombrede quien se lleva la película. En tercer lugar, elidentificador de la película, idpelicula. Como la tabla depelículas contiene un campo llamado id que identifica acada registro de forma inequívoca, puede guardar aquí esecampo para saber qué película se llevó su amigo.

Pero claro, existe la posibilidad de que se inserte comoidentificador de la película un valor sin contrapartida en latabla pelicula. Lo ideal sería que MySQL controlase que enese campo sólo se pudiesen insertar valores existentes endicha tabla. Cuando esa condición se cumple, se dice quese está manteniendo la integridad referencial entre lastablas, y que idpelicula es una clave externa.

Utilice las siguientes instrucciones para crear la tabla depréstamos:

USE videoteca;

DROP TABLE IF EXISTS prestamo;

CREATE TABLE prestamo (

id INT NOT NULL AUTO_INCREMENT,

idpelicula INT NOT NULL,

persona VARCHAR(128) NOT NULL,

fecha DATE NOT NULL,

PRIMARY KEY(id),

FOREIGN KEY(idpelicula)

REFERENCES pelicula(id)

);

Nota: La tabla prestamo, que cont iene la clave externa, se conoce como tablahija o secundaria, mientras que la tabla a la que hace referencia se conoce comotabla madre o principal.

Ahora que disponemos de dos tablas relacionadasvamos a comprobar que se cumple lo descrito acerca de lasrelaciones. Para ello sólo tenemos que realizar insercionesen la tabla de préstamos. En primer lugar, vamos a prestar"Contact" a Kake. Como pudo verse en la figura 5.8, elidentificador que MySQL asignó automáticamente a esapelícula es el 4, así que:

USE videoteca;

Page 130: Desarrollo Web Con PHP y MySQL

INSERT INTO

prestamo(

idpelicula,

persona,

fecha

)

VALUES(

4,

'Kake',

CURRENT_DATE()

);

Advertencia: Es posible que el ident ificador de "Contact" en su tabla depelículas sea otro, no se preocupe en absoluto. Ut ilice el ident ificador asignado ensu sistema para este ejemplo.

Como ve, hemos utilizado la función CURRENT_DATE()para guardar la fecha actual en la columna fecha. Si ahoraselecciona todos los registros de la tabla prestamo podráver algo parecido a lo que aparece en la figura 5.11.

Figura 5.11. El primer préstamo

Ahora comprobaremos cómo funciona la integridadrelacional, intentando prestar una película no presente enla base de datos. Utilice un identificador de película que noexista:

USE videoteca;

INSERT INTO

prestamo(

idpelicula,

persona,

fecha

)

VALUES(

123,

'Germán',

CURRENT_DATE()

);

MySQL le informará de que ha surgido un error...¿Cómo? ¿Que no informa de ningún error? ¿Que se hapodido realizar la inserción? Claro que se ha podido, sólointentaba comprobar si prestaba atención.

El propósito de esta jugarreta ha sido demostrarle losencillo que es perder la consistencia de los datos de una

Page 131: Desarrollo Web Con PHP y MySQL

base de datos si no se presta atención durante la fase dediseño. Esta última inserción ha conseguido que se inserteun préstamo de la película con identificador 123, películaque no existe en la base de datos. Localizar este tipo deproblemas en una tabla con dos registros es sencillo pero,¿y si esta tabla tuviese miles?

¿Por qué no se ha cumplido ni una palabra de cuanto haaprendido sobre relaciones entre tablas? Muy sencillo: eltipo de tabla predeterminado de MySQL, MyISAM, noincorpora los mecanismos de integridad relacional. CuandoMySQL encuentra las instrucciones de integridad referidasa una tabla MyISAM, simplemente las ignora. Para lograrnuestro objetivo hemos de utilizar tablas InnoDB, de lasque ya hablamos en el capítulo tercero.

Nota: Aquellos usuarios de Windows que hayan instalado MySQL usando elasistente se preguntarán qué ha ocurrido y por qué no les ha dejado realizar lainserción anterior, que rompía la integridad referencial. Esto se debe a que, paraellos, el t ipo de tabla predeterminado es InnoDB, no MyISAM. Si quiere comprobarde qué t ipo es una tabla sólo t iene que ut ilizar la instrucción SHOW CREATETABLE seguida del nombre de la tabla en cuest ión y localizar la palabra claveENGINE.

El primer paso para lograr que la integridad referencialfuncione es convertir la tabla de películas en una tablaInnoDB:

USE videoteca;

ALTER TABLE pelicula ENGINE = InnoDB;

Hecho, así de fácil. Ahora, elimine y vuelva a crear latabla de préstamos:

USE videoteca;

DROP TABLE IF EXISTS prestamo;

CREATE TABLE prestamo (

id INT NOT NULL AUTO_INCREMENT,

idpelicula INT NOT NULL,

persona VARCHAR(128) NOT NULL,

fecha DATE NOT NULL,

PRIMARY KEY(id),

FOREIGN KEY(idpelicula)

REFERENCES pelicula(id)

) ENGINE = InnoDB;

En este caso no bastaría con cambiar el tipo de tabla yaque esa operación no crearía las estructuras necesariaspara el mantenimiento de la integridad referencial. Intenteahora la inserción del préstamo de una películainexistente:

USE videoteca;

INSERT INTO

prestamo(

idpelicula,

persona,

Page 132: Desarrollo Web Con PHP y MySQL

persona,

fecha)

VALUES(

123,

'Germán',

CURRENT_DATE()

);

Como podrá comprobar, MySQL ya no le permite insertaren la columna idpelicula identificadores de películas queno estén en la tabla pelicula. Hemos logrado (no sinesfuerzo) nuestro objetivo. La figura 5.12 muestra undiagrama de su primera base de datos con tablasrelacionadas.

Figura 5.12. Relación entre películas y préstamos

Para terminar este apartado vamos a ver qué clases derelaciones entre tablas existen atendiendo al número deelementos que se ven involucrados:

Uno a uno: Un registro de una de las tablas sólo puedeestar relacionado con un registro de la otra tabla. Seríael caso de la relación entre películas y préstamos si elidentificador de la película de esta última fuese la claveprimaria, ya que así sólo podría guardar un registro porpelícula. Resulta interesante si no se quiere almacenarun histórico de préstamos (algo que ahora sí se puedehacer).Uno a muchos: Se da en el caso de que un registro dela tabla hija sólo pueda estar relacionado con unregistro de la tabla madre. A su vez, un registro de latabla principal puede estar relacionado con más de unode la tabla hija. Es el caso de la relación entre tablasque acaba de crear. Un préstamo sólo se aplica a unadeterminada película, aunque a lo largo del tiempo esapelícula la ha podido tener mucha gente.Muchos a muchos: En esta relación, un registro de latabla hija puede estar relacionado con cualquierregistro de la tabla madre y viceversa. Adelantandocontenidos, en el siguiente apartado dividiremos latabla de películas en otras tablas. Una de ellascontendrá información sobre los actores, relacionadacon la tabla de películas. Un actor puede haberparticipado en muchas películas y, a su vez, en unapelícula pueden participar muchos actores.

Tras lo visto hasta ahora dispone de los conocimientosnecesarios para afrontar el objetivo de este capítulo,mejorar el diseño de esta base de datos. Una de lastécnicas más empleadas en el mundo de las bases dedatos, y en el de la informática en general, es el "divide yvencerás".

Page 133: Desarrollo Web Con PHP y MySQL

Divide y vencerás

El punto de partida es la tabla pelicula de la base dedatos videoteca que ha construido a lo largo de estecapítulo. Pudo ver su diseño en la anterior figura 5.9.Utilizó estas instrucciones para crearla:

USE videoteca;

CREATE TABLE pelicula(

id INT NOT NULL AUTO_INCREMENT,

titulo VARCHAR(64) NOT NULL,

director VARCHAR(128) NOT NULL

DEFAULT '',

actor VARCHAR(128) NOT NULL

DEFAULT '',

PRIMARY KEY(id)

) ENGINE = InnoDB;

Creación de tablas con MySQL Workbench

Vamos a mejorar el diseño de la tabla de películas,añadiéndole algunos campos más en los que poderguardar otros datos que pueden resultar interesantes:

soporte: Una cadena de tres caracteres que guardaráel formato en el que está la grabación (VHS, DVD,etcétera).imdb_director: El identificador que la famosa WebIMDb (http://imdb.com/) dedicada al cine asigna a esedirector. Una aplicación podría utilizar este dato paramostrar una página con detalles de un director enconcreto. Se guardará en una cadena de 32 caracteres.La figura 5.13 muestra la página del director RidleyScott. Su identificador, nm0000631, aparece en labarra de direcciones.

Page 134: Desarrollo Web Con PHP y MySQL

Figura 5.13. Ridley Scott en IMDb

imdb_actor: Igual que el campo imdb_director, peroaplicado al actor.genero: Siglas del género cinematográfico al quepertenece la película.genero_desc: Descripción de las siglas del campoanterior.

Siga estos pasos para crear esta tabla utilizando MySQLWorkbench:

1. Ponga en marcha MySQL Workbench. Inicialmente, elaspecto de este programa es que el puede verse en lafigura 5.14.

Page 135: Desarrollo Web Con PHP y MySQL

Figura 5.14. MySQL Workbench

2. Para comenzar a trabajar con un documento en blancoseleccione la opción New del menú File.

3. Vamos a añadir un nuevo diagrama: seleccione laopción Add Diagram del menú Model. También puedeutilizar la combinación de teclas Control-T . El aspectode MySQL Workbench cambiará, mostrándole unarejilla en la que podrá situar los diferentes elementosque compongan su base de datos, tal y como muestrala figura 5.15.

Page 136: Desarrollo Web Con PHP y MySQL

Figura 5.15. Diagrama en blanco

Nota: Fí jese en que, bajo la barra de menús, aparecen ya dos fichas. La primera,MySQL Model, es la que pudo ver en la figura 5.14. La segunda, EER Diagram,significa diagrama ent idad-relación mejorado (Enhanced Entity Relationship).

4. Antes de nada, cambie el nombre de la base de datos.Fíjese en el panel de la derecha llamado Catalog. Elnombre de la base de datos actual es mydb. Haga clicsobre él, espere y vuelva a hacer clic para poder editarsu nombre. También puede hacer clic con el botónderecho sobre él y seleccionar la opción Rename delmenú contextual. Escriba videoteca y pulse la teclaIntro.

5. Cree una nueva tabla. Para ello, haga clic en el iconoPlace a New Table de la barra de herramientas quese encuentra en la parte izquierda de la ventana delprograma. El puntero del ratón cambiará de forma para indicarle que, cuando haga clic sobre la zona deedición del documento, en la parte central de laventana donde se encuentra la rejilla, se insertará unanueva tabla.

6. Haga clic en la zona de edición del documento.Aparecerá una nueva tabla con un nombrepredeterminado table1, como puede ver en la figura5.16.

Page 137: Desarrollo Web Con PHP y MySQL

Figura 5.16. Nueva tabla

7. Haga doble clic sobre el nombre de tabla que acaba deaparecer. MySQL Workbench le presentará el editor detablas, en la parte inferior de la ventana del programa,desde el que puede añadir nuevos campos, cambiarsus propiedades, el tipo de tabla, etcétera. La figura5.17 le muestra este panel tal y como quedaría trasintroducir los detalles de las columnas de la tablapelicula.

Page 138: Desarrollo Web Con PHP y MySQL

Figura 5.17. Diseñando la nueva tabla

8. Para terminar, seleccione la opción Save del menú Fileo haga clic en el botón Save Model to File de labarra de herramientas para guardar el modelo queacaba de crear en la ubicación que desee.

Además de tener una representación visual de sustablas, también puede obtener las instruccionesnecesarias para crear la que acaba de diseñar. Haga cliccon el botón derecho del ratón sobre la tabla y seleccionela opción Copy SQL to Clipboard. Si luego pega elresultado usando Control-V en su editor de texto favoritoverá un resultado similar al siguiente:

CREATE TABLE pelicula (

id INT NOT NULL AUTO_INCREMENT,

titulo VARCHAR(64) NOT NULL,

director VARCHAR(128) NOT NULL DEFAULT '',

actor VARCHAR(128) NOT NULL DEFAULT '',

soporte VARCHAR(3) NOT NULL DEFAULT '',

imdb_director VARCHAR(32) NOT NULL DEFAULT '',

imdb_actor VARCHAR(32) NOT NULL DEFAULT '',

genero VARCHAR(2) NOT NULL DEFAULT '',

genero_desc VARCHAR(32) NOT NULL DEFAULT '',

PRIMARY KEY (id)

) ENGINE = InnoDB;

La base de datos de películas que está diseñando seencuentra ahora mismo en lo que algunos llaman la formanormal cero: contiene todos los datos que se deseanmostrar y una clave primaria.

Para crear esta tabla cree primero la base de datos

Page 139: Desarrollo Web Con PHP y MySQL

videoteca. Es posible que ya exista si la creó en elsegundo capítulo. Las siguientes instrucciones eliminaránesta base de datos si ya existiese y la volverán a crear:

DROP DATABASE IF EXISTS videoteca;

CREATE DATABASE videoteca;

Cree ahora la tabla de películas (no se olvide deseleccionar antes en qué base de datos con USEvideoteca;) y, a continuación, inserte algunos datos en latabla:

USE videoteca;

INSERT INTO pelicula(

titulo,

director,

actor,

soporte,

imdb_director,

imdb_actor,

genero,

genero_desc

)

VALUES(

'Blade Runner',

'Ridley Scott',

'Harrison Ford',

'DVD',

'nm0000631',

'nm0000148',

'CF',

'Ciencia-ficción'

);

INSERT INTO pelicula(

titulo,

director,

actor,

soporte,

imdb_director,

imdb_actor,

genero,

genero_desc

)

VALUES(

'Gladiator',

'Ridley Scott',

'Russell Crowe',

'DVD',

'nm0000631',

'nm0000128',

'A',

'Aventuras'

);

Page 140: Desarrollo Web Con PHP y MySQL

INSERT INTO pelicula(

titulo,

director,

actor,

soporte,

imdb_director,

imdb_actor,

genero,

genero_desc

)

VALUES(

'A propósito de Henry',

'Mike Nichols',

'Harrison Ford',

'VHS',

'nm0001566',

'nm0000148',

'D',

'Drama'

);

El resultado de hacer una consulta de selección trasestas inserciones puede verse en la figura 5.18. Fíjese enel uso de \G al final de la operación de consulta.

Figura 5.18. Los datos de part ida

Con este diseño y estos datos de partida, ¿cómo seencuentra la base de datos? Busquemos todas lasdeficiencias de diseño que podamos:

Cada vez que introduzca el nombre de un actor, si eseactor ya participó en alguna de las películas que tieneen la base de datos, estará duplicando los datos,ocupando más espacio.Con relación al punto anterior, es posible que cometaalgún error al introducir el nombre de algún actor.Podría escribir Harrisond Ford como protagonista de

Page 141: Desarrollo Web Con PHP y MySQL

una de las películas de Indiana Jones. Siposteriormente hiciese una consulta de las películasprotagonizadas por este actor, la de Indiana Jones noaparecería, por el error en el nombre.Esta misma fuente de errores se repite con el génerode la película y su descripción, y con los códigos deIMDb.Sólo puede indicarse un director por película. Algunas,como "Delicatessen", fueron dirigidas por dospersonas.Lo mismo se puede decir, con más razón, de losactores.

Está claro que la base de datos es manifiestamentemejorable y muchas de estas mejoras se lograríandividiendo la tabla en fragmentos más pequeños y másmanejables, haciendo bueno el dicho "divide y vencerás".

División de tablas

Vamos a comenzar con los directores. Por sí misma, lacreación de una tabla para la gestión de los directores depelículas podría tener sentido. Cree una nueva tabla en laque almacenar los detalles de cada uno de ellos. La figura5.19 muestra el aspecto de dicha tabla, creada con MySQLWorkbench.

Figura 5.19. Los datos de los directores

¡Fantástico! Ya tiene una tabla para los directores que,utilizando claves externas como las que vio en el apartadodedicado a las bases de datos relacionales, puede llevar acabo correspondencias con cada película. Pero aún hayalgo que falla en esta tabla.

Aunque hemos comenzado con la división de la tablaprincipal, no hemos continuado con esa división en lastablas obtenidas. Los datos han de dividirse todo loposible, siempre que esta división sea útil.

¿Qué más se puede dividir en esta tabla? El nombre deldirector, por ejemplo, podría dividirlo en dos partes:nombre y apellidos. De esta forma, lo que antes era unúnico campo (Ridley Scott, por ejemplo), que sólo permitíaordenación por el nombre, ahora se convierte en dos. Estole da la oportunidad de ordenar también por los apellidos, ala vez que se evitan errores en la introducción del nombre.La figura 5.20 muestra este otro diseño de la tabla dedirectores.

Figura 5.20. Otro diseño de la tabla de directores

Page 142: Desarrollo Web Con PHP y MySQL

El código necesario para crear esta tabla es el siguiente:

USE videoteca;

CREATE TABLE director (

id INT NOT NULL AUTO_INCREMENT,

nombre VARCHAR(64) NOT NULL,

apellidos VARCHAR(64) NOT NULL,

imdb VARCHAR(32) NOT NULL DEFAULT '',

PRIMARY KEY(id)

) ENGINE = InnoDB;

Fíjese en que la única columna con un valorpredeterminado es la que almacena el código de IMDb:puede que no lo conozca para todos los directores. Por elcontrario, es necesario introducir el resto de valores encada inserción.

El mismo razonamiento que se ha seguido para crearesta tabla de directores puede aplicarse para aquella en laque se guardan los datos de los actores. La figura 5.21muestra el diseño de dicha tabla.

Figura 5.21. Los datos de los actores, por separado

El código para crear esta tabla es el siguiente:

USE videoteca;

CREATE TABLE actor (

id INT NOT NULL AUTO_INCREMENT,

nombre VARCHAR(64) NOT NULL,

apellidos VARCHAR(64) NOT NULL,

imdb VARCHAR(32) NOT NULL DEFAULT '',

PRIMARY KEY(id)

) ENGINE = InnoDB;

Relacionar tablas

El diseño de la tabla de películas ha de cambiarse parareflejar los cambios realizados en la sección anterior. Hade incluir una referencia al director de la película, y otra alactor, para seguir guardando los mismos datos que antes.Este cambio se muestra en la figura 5.22.

Figura 5.22. Modificación de la tabla de películas

Sólo ha sido necesario sustituir los campos director y

Page 143: Desarrollo Web Con PHP y MySQL

actor, que guardaban sus nombres, por los identificadorescorrespondientes de las tablas que acaba de crear, yeliminar los datos de IMDb que se guardaban, ya que ahoraestarán en las tablas correspondientes.

Para terminar tenemos que relacionar las tres tablasexistentes entre sí: actor, director y pelicula. La columnaiddirector debe estar relacionada con la columna id de latabla director. Por otra parte, la columna idactor debeestar relacionada con la columna id de la tabla actor.

La relación entre directores y películas es lo que sedefinió anteriormente como una relación uno a muchos.Traduciendo: por ahora, en este modelo, una película sólola dirige un director, pero un director puede haber dirigidomuchas películas.

Siga estos pasos para crear relaciones utilizando MySQLWorkbench:

1. Haga clic sobre la tabla pelicula para seleccionarla.2. Active la ficha Foreign Keys, se encuentra en la parte

inferior de la ventana de MySQL Workbench.3. Introduzca el nombre que quiera dar a la relación en la

primera fila de la columna Foreign Key Name. Comose trata de saber quién ha dirigido cada película,llamémosla dirigida_por.

4. Introduzca el nombre de la tabla con la que quiererelacionar la actual en la primera fila de la columnaReferenced Table . Una lista desplegable le permitiráseleccionar entre las tablas existentes. En este casohemos de seleccionar la tabla director.

5. Justo a la derecha del panel con el que hemos estadotrabajando podrá ver la lista de los campos de la tablapelicula. Marque la casilla de verificación del campoiddirector. Cuando lo haga se desplegará una lista conlos campos de la tabla de directores. Seleccione elcampo id.

6. Repita la operación con la tabla de actores.7. El aspecto del modelo en ese momento será similar al

que puede verse en la figura 5.23.

Figura 5.23. Primer paso de la creación de relaciones

El modelo de datos que tiene ahora permite manteneruna lista de directores, otra de actores y una última depelículas, que toma datos de las dos primeras. Este

Page 144: Desarrollo Web Con PHP y MySQL

proceso de simplificación, dividiendo el modelo, puedeseguir aplicándose a la tabla de películas.

El soporte en el que está grabada la película puede serotra tabla que, por ahora, sólo contendrá los valores DVD yVHS, pero que en el futuro puede contener los valores delos formatos que vaya añadiendo a su videoteca. Losgéneros también podrían llevarse a otra tabla.

Debería añadir, de nuevo, los identificadores necesariosa la tabla de películas para mantener las relaciones entrepelículas, formatos y géneros. En la figura 5.24 puede verel aspecto del modelo resultante tras la nueva división delos datos, que ocasiona la aparición de dos nuevas tablas,soporte y genero, y la incorporación de los camposidsoporte e idgenero a la tabla pelicula, tras eliminar loscampos correspondientes de las nuevas tablas.

Figura 5.24. Películas, directores y actores

Aún se puede añadir una mejora más al modelo,permitiendo que una película pueda estar protagonizadapor más de un actor, algo que este no permite en estemomento.

La opción más sencilla sería incluir otro identificador deactor más, idactor2. Pero entonces ¿qué ocurre si sequiere guardar información sobre tres actores? ¿Creamosun tercer campo, idactor3? ¿Y si luego quisiésemos añadirun cuarto actor?

Relaciones muchos a muchos

La forma más eficaz de lograr este objetivo es cambiar eltipo de relación que existe entre la tabla de actores y la depelículas. Ahora mismo es una relación uno a muchos,como ha visto. Hay que lograr convertirla en una relaciónmuchos a muchos.

Para ello, es necesario utilizar una tabla intermedia, quealmacenará las relaciones entre películas y actores. Elidentificador del actor dejará de estar en la tabla depelículas y pasará a esta nueva tabla.

La tabla de películas tendrá una relación de uno amuchos con la tabla de actores por película, al igual que latabla de actores. De esta manera, el resultado final es quela tabla de películas tendrá una relación de muchos amuchos con la de actores. Puede ver cómo quedará esta

Page 145: Desarrollo Web Con PHP y MySQL

parte del modelo de la base de datos en la figura 5.25. Seha simplificado la tabla de películas para que sólo incluyalos campos interesantes para este apartado.

Figura 5.25. Una relación muchos a muchos

Por ejemplo, para crear las tablas que se pueden ver enla figura 5.25 sería necesario ejecutar las siguientesinstrucciones:

USE videoteca;

DROP TABLE IF EXISTS actor;

CREATE TABLE actor (

id INT NOT NULL AUTO_INCREMENT,

nombre VARCHAR(64) NOT NULL,

apellidos VARCHAR(64) NOT NULL,

imdb VARCHAR(32) NOT NULL DEFAULT '',

PRIMARY KEY(id)

) ENGINE = InnoDB;

DROP TABLE IF EXISTS pelicula;

CREATE TABLE pelicula (

id INT NOT NULL AUTO_INCREMENT,

titulo VARCHAR(64) NOT NULL,

PRIMARY KEY(id)

) ENGINE = InnoDB;

DROP TABLE IF EXISTS actores_por_pelicula;

CREATE TABLE actores_por_pelicula (

idpelicula INT NOT NULL,

idactor INT NOT NULL,

PRIMARY KEY(idpelicula, idactor),

INDEX actores_por_pelicula_fk1(

idpelicula

),

INDEX actores_por_pelicula_fk2(

idactor

),

FOREIGN KEY(idpelicula)

REFERENCES pelicula(id),

FOREIGN KEY(idactor)

REFERENCES actor(id)

) ENGINE = InnoDB;

Tenga en cuenta que ahora, para guardar en la base dedatos los detalles de una película, es necesario realizarmás inserciones. Por ejemplo, "Blade Runner" requeriríauna inserción en la tabla de actores para disponer deHarrison Ford. Sería necesaria otra inserción en la tabla depelículas para crear la película, y por último, una inserción

Page 146: Desarrollo Web Con PHP y MySQL

en la tabla de actores por película para crear la asociaciónentre ambos. Esta última inserción requiere que conozcalos identificadores tanto del actor como de la película, quepueden obtenerse mediante una consulta:

USE videoteca;

INSERT INTO actor(nombre, apellidos, imdb)

VALUES('Harrison', 'Ford', 'nm0000148');

INSERT INTO pelicula(titulo)

VALUES('Blade Runner');

SELECT

id

FROM

actor

WHERE

imdb = 'nm0000148';

SELECT

id

FROM

pelicula

WHERE

titulo = 'Blade Runner';

INSERT INTO actores_por_pelicula(

idpelicula, idactor

)

VALUES(

15, 10

);

Nota: Es posible combinar los procedimientos almacenados y losdesencadenadores para hacer más sencillo el t rabajo de inserción de películas enla base de datos. Encontrará más información al respecto en los capítuloscorrespondientes.

En las operaciones de inserción anteriores se hasupuesto que el identificador del actor es 10 y el de lapelícula es 15. Este modelo le permitiría incluir un segundoactor relacionado con la película de la siguiente forma:

USE videoteca;

INSERT INTO actor(nombre, apellidos, imdb)

VALUES('Rutger', 'Hauer', 'nm0000442');

SELECT

id

FROM

actor

WHERE

imdb = 'nm0000442';

Page 147: Desarrollo Web Con PHP y MySQL

INSERT INTO actores_por_pelicula(

idpelicula, idactor

)

VALUES(

15, 11

);

Nota: En el siguiente capítulo, dedicado a las consultas de datos, podrá vercómo recuperar la información de los actores que han trabajado en unadeterminada película, así como otras consultas más complejas.

El ejemplo finalizado

Si extiende la modificación en el diseño a la tabla dedirectores podrá tener varios directores para una película.La figura 5.26 muestra el diseño final de la base de datostras incorporar este cambio.

Figura 5.26. ¡El diseño, por fin!

Existe un truquito de MySQL Workbench que permitetrabajar con diseños grandes en poco espacio. ¿Se hafijado en el triángulo que aparece a la derecha del nombrede cada tabla? Si hace clic en él, MySQL Workbenchocultará los campos de las tablas, mostrando sólo susnombres. La figura 5.27 muestra el mismo diagrama que la5.26, pero tras utilizar dicho triángulo para simplificar elaspecto del diagrama.

Figura 5.27. Simplificación del diagrama

Page 148: Desarrollo Web Con PHP y MySQL

Durante este capítulo se ha terminado de diseñar labase de datos con la que trabajaremos en los capítulossucesivos. Una nota final: queda como ejercicio mejorar eldiseño de la tabla dedicada a almacenar los préstamos delas películas, así como la posibilidad de que una películapertenezca a más de un género y esté en más de unsoporte. O, por ejemplo, añadir más campos a la tablaprincipal para guardar la fecha de la película, unacalificación sobre la misma o los comentarios que desee.

Page 149: Desarrollo Web Con PHP y MySQL

6

SQL

Las primeras veces que se encargue de él, el diseño dela base de datos le acarreará dolores de cabeza. Lapráctica logrará que se convierta en una tarea más, quedebe tener lugar al principio del proceso de desarrollo.

Existe una tarea que le ocupará bastante más tiempoque el diseño: las consultas a la base de datos, ya seaninserciones, actualizaciones, borrados o simplessolicitudes de información. Mientras la base de datos seencuentre en funcionamiento estas cuatro operacionesserán fundamentales.

El lenguaje estructurado de consultas, o SQL, le permitecomunicarse con el sistema gestor de bases de datos pararealizar todas esas operaciones. Existen herramientasvisuales para llevar a cabo las tareas de mantenimiento delas bases de datos, que facilitan mucho las insercionespuntuales. Sin embargo, la utilización de SQL proporcionamuchas ventajas de las que hablaremos a lo largo de estecapítulo.

Comenzaremos creando desde cero la base de datos quediseñamos en el capítulo anterior, precisamente utilizandoinstrucciones SQL, lo que permitirá ilustrar algunas de lasventajas de este método de trabajo. Continuaremosinsertando valores en las tablas de la base de datos. Estosvalores se utilizarán durante el resto del capítulo.

Tras repasar las consultas para la creación y elmantenimiento de bases de datos, exploraremos lasdiferentes variantes de consultas de selección que puedenser útiles para el trabajo diario y continuaremos con lasactualizaciones y las inserciones. Por último, veremos losborrados.

La base de datos de ejemplo

Quizá sería interesante ofrecerle una lista de ventajas ydesventajas comparando, por un lado, el uso de lasherramientas visuales como MySQL Administrator yMySQL Query Browser para crear bases de datos y tablasy, por otro, el uso de archivos de instrucciones (tambiénconocidos como scripts), pero no va a ser el caso. Lerecomendamos que, siempre que sea posible, utilicearchivos de instrucciones para este tipo de tareas, porvarios motivos.

El primero de ellos es que en la mayoría de trabajos a losque se enfrentará con MySQL contará con un servidor dedesarrollo, en el que podrá hacer todas las pruebasnecesarias, y un servidor de explotación, en el que laaplicación funcionará una vez se haya probadoconvenientemente.

Page 150: Desarrollo Web Con PHP y MySQL

En este tipo de entornos es mucho más eficaz lautilización de los archivos de instrucciones obtenidos apartir de herramientas de diseño de bases de datos comoMySQL Workbench. Una vez disponga de las instruccionesde creación de la base de datos y de sus tablas, puederepetir la operación de forma exacta e idéntica todas lasveces que lo necesite.

Sin embargo, si tuviese que utilizar las herramientasvisuales que ha visto hasta ahora cada vez que fuesenecesario crear la base de datos y sus tablas, introduciríaun punto de fallo. Podría cometer algún error al repetir lasoperaciones una y otra vez.

Más aún, una vez creados los archivos de instruccionesnecesarios, cualquiera puede crear la bases de datos,dadas unas instrucciones muy sencillas, sin necesidad detener el más mínimo conocimiento acerca del diseño de lamisma.

Consejo: Le recomendamos encarecidamente que, en cualquier operación quetenga que realizar con MySQL, si existe la posibilidad de automat izarla medianteel empleo de archivos de órdenes, lo haga. Aunque le cueste más esfuerzo alprincipio, ahorrará un valioso t iempo en el futuro.

Creación de la base de datos

En los archivos de ejemplo de este libro, dentro delapartado dedicado a este capítulo, podrá encontrar unarchivo llamado 01 - Crear la base de datos.sql. Estearchivo contiene todas las instrucciones SQL necesariaspara crear tanto la base de datos como las tablas de lavideoteca que con tanto esfuerzo ha desarrollado durantelos capítulos previos. El contenido de ese archivo es elsiguiente:

DROP DATABASE IF EXISTS videoteca;

CREATE DATABASE videoteca;

USE videoteca;

DROP TABLE IF EXISTS director;

CREATE TABLE director (

id INT NOT NULL AUTO_INCREMENT,

nombre VARCHAR(64) NOT NULL,

apellidos VARCHAR(64) NOT NULL,

imdb VARCHAR(32) NOT NULL DEFAULT '',

PRIMARY KEY(id)

) ENGINE = InnoDB;

DROP TABLE IF EXISTS genero;

CREATE TABLE genero (

id INT NOT NULL AUTO_INCREMENT,

nombre VARCHAR(2) NOT NULL,

descripcion VARCHAR(32) NOT NULL,

PRIMARY KEY(id)

) ENGINE = InnoDB;

Page 151: Desarrollo Web Con PHP y MySQL

DROP TABLE IF EXISTS actor;

CREATE TABLE actor (

id INT NOT NULL AUTO_INCREMENT,

nombre VARCHAR(64) NOT NULL,

apellidos VARCHAR(64) NOT NULL,

imdb VARCHAR(32) NOT NULL DEFAULT '',

PRIMARY KEY(id)

) ENGINE = InnoDB;

DROP TABLE IF EXISTS soporte;

CREATE TABLE soporte (

id INT NOT NULL AUTO_INCREMENT,

nombre VARCHAR(3) NOT NULL,

descripcion VARCHAR(32) NOT NULL,

PRIMARY KEY(id)

) ENGINE = InnoDB;

DROP TABLE IF EXISTS pelicula;

CREATE TABLE pelicula (

id INT NOT NULL AUTO_INCREMENT,

titulo VARCHAR(64) NOT NULL,

idsoporte INT NOT NULL,

idgenero INT NOT NULL,

PRIMARY KEY(id),

INDEX p_FK1(idsoporte),

INDEX p_FK2(idgenero),

FOREIGN KEY(idsoporte)

REFERENCES soporte(id),

FOREIGN KEY(idgenero)

REFERENCES genero(id)

) ENGINE = InnoDB;

DROP TABLE IF EXISTS actores_por_pelicula;

CREATE TABLE actores_por_pelicula (

idpelicula INT NOT NULL,

idactor INT NOT NULL,

PRIMARY KEY(idpelicula, idactor),

INDEX app_FK1(idpelicula),

INDEX app_FK2(idactor),

FOREIGN KEY(idpelicula)

REFERENCES pelicula(id),

FOREIGN KEY(idactor)

REFERENCES actor(id)

) ENGINE = InnoDB;

DROP TABLE IF EXISTS directores_por_pelicula;

CREATE TABLE directores_por_pelicula (

idpelicula INT NOT NULL,

iddirector INT NOT NULL,

PRIMARY KEY(idpelicula, iddirector),

INDEX dpp_FK1(idpelicula),

INDEX dpp_FK2(iddirector),

FOREIGN KEY(idpelicula)

Page 152: Desarrollo Web Con PHP y MySQL

FOREIGN KEY(idpelicula)

REFERENCES pelicula(id),

FOREIGN KEY(iddirector)

REFERENCES director(id)

) ENGINE = InnoDB;

Si ha seguido los pasos dados en los capítulosanteriores ya estará familiarizado con el proceso deejecución de instrucciones utilizando la consola. Ahoraaprenderá una forma nueva de hacerlo.

En primer lugar, necesita un archivo en el que guardarlas instrucciones SQL que acaba de ver. Si tiene acceso aInternet no es necesario que las escriba usted mismo, yasabe del archivo 01 - Crear la base de datos.sql,hablamos de él anteriormente. Si no tiene acceso aInternet tendrá que teclear.

En segundo lugar, guarde el archivo en el disco con elnombre crear.sql, abra una consola (o un terminal en elcaso de Linux o Mac OS X) y cambie a la ubicación en laque se encuentra el archivo. Lo más sencillo: guárdelo enla raíz del disco C: si utiliza Windows o su carpeta home siutiliza Linux o Mac OS X. Entonces, ejecute la siguienteorden:

mysql -u root -p < crear.sql

El cliente de MySQL le pedirá que introduzca lacontraseña y, tras pensárselo un momento, le devolverá elcontrol. Recuerde que si instaló MySQL a través de XAMPPy no cambió su configuración predeterminada, el usuarioroot no tendrá contraseña. El aspecto de la consola serásimilar al que puede verse en la figura 6.1.

Figura 6.1. Creación de la base de datos

Eso es todo. De un plumazo, la base de datos y suscorrespondientes tablas, creadas. Y puede repetir laoperación las veces que sea necesario con la mismafacilidad.

Inserción de datos

Tras la ejecución de las instrucciones de creación de labase de datos estaremos trabajando, usted y yo, con losmismos elementos. Ahora vamos a llenar las tablas de labase de datos con los registros que utilizaremos durantelos siguientes apartados. De nuevo vamos a utilizararchivos de instrucciones.

Puede utilizar un archivo que se encuentra en la mismaubicación que el que utilizó anteriormente para crear labase de datos. Su nombre es 02 - Insertar valoresiniciales.sql. Ejecútelo siguiendo los mismos pasos quecon el de creación de base de datos y tablas. Lasinstrucciones de inserción incluidas en dicho archivo sonlas siguientes:

Page 153: Desarrollo Web Con PHP y MySQL

USE videoteca;

DELETE FROM actores_por_pelicula;

DELETE FROM directores_por_pelicula;

DELETE FROM actor;

DELETE FROM director;

DELETE FROM pelicula;

DELETE FROM soporte;

DELETE FROM genero;

INSERT INTO soporte(nombre, descripcion)

VALUES('DVD', 'Digital Versatile Disc');

INSERT INTO soporte(nombre, descripcion)

VALUES('VHS', 'Video Home System');

INSERT INTO genero(nombre, descripcion)

VALUES('CF', 'Ciencia Ficción');

INSERT INTO genero(nombre, descripcion)

VALUES('A', 'Aventuras');

INSERT INTO genero(nombre, descripcion)

VALUES('D', 'Drama');

INSERT INTO actor(nombre, apellidos, imdb)

VALUES('Harrison', 'Ford', 'nm0000148');

INSERT INTO actor(nombre, apellidos, imdb)

VALUES('Russell', 'Crowe', 'nm0000128');

INSERT INTO director(nombre, apellidos, imdb)

VALUES('Ridley', 'Scott', 'nm0000631');

INSERT INTO director(nombre, apellidos, imdb)

VALUES('Mike', 'Nichols', 'nm0001566');

INSERT INTO pelicula(titulo, idsoporte, idgenero)

VALUES('Blade Runner', 1, 1);

INSERT INTO pelicula(titulo, idsoporte, idgenero)

VALUES('Gladiator', 1, 2);

INSERT INTO pelicula(titulo, idsoporte, idgenero)

VALUES('A propósito de Henry', 2, 3);

INSERT INTO actores_por_pelicula(

idpelicula, idactor

)

VALUES(1, 1);

INSERT INTO actores_por_pelicula(

idpelicula, idactor

Page 154: Desarrollo Web Con PHP y MySQL

)

VALUES(2, 2);

INSERT INTO actores_por_pelicula(

idpelicula, idactor

)

VALUES(3, 1);

INSERT INTO directores_por_pelicula(

idpelicula, iddirector

)

VALUES(1, 1);

INSERT INTO directores_por_pelicula(

idpelicula, iddirector

)

VALUES(2, 1);

INSERT INTO directores_por_pelicula(

idpelicula, iddirector

)

VALUES(3, 2);

La principal diferencia consiste en que hasta que notenga valores en las tablas de las que depende la tablapelicula no podrá realizar inserciones en ella, porque hande cumplirse las reglas de integridad referencial. Por unaparte, ha de tener soportes válidos en la tabla de soportesde grabación, y también géneros en la tabla de géneroscinematográficos.

Con valores en esas dos tablas sí es posible realizarinserciones en la de películas. Pero hasta que tengaregistros en las tablas de directores y actores no podráasociar valor alguno a la tabla de películas a través de lastablas intermedias. Los pasos necesarios para insertar lapelícula "Blade Runner" en la base de datos, como si fuesela primera que se inserta, son los siguientes:

1. Inserte el soporte en que se encuentra la película. Si,posteriormente, inserta otras películas que esténgrabadas en el mismo formato, no tendrá que insertarun nuevo registro en esta tabla, puesto que ya tendráalmacenado el valor necesario.

USE videoteca;

INSERT INTO soporte(nombre, descripcion)

VALUES('DVD', 'Digital Versatile Disc');

2. Ahora necesita un registro en la tabla de géneroscinematográficos que se ajuste al de esta película."Blade-Runner" es de ciencia ficción.

INSERT INTO genero(nombre, descripcion)

VALUES('CF', 'Ciencia Ficción');

Page 155: Desarrollo Web Con PHP y MySQL

3. Adelántese e inserte ya el actor de la película, aunquetambién podría insertar en este momento la película.

INSERT INTO actor(nombre, apellidos, imdb)

VALUES('Harrison', 'Ford', 'nm0000148');

4. El último paso previo a la inserción de la película serála inserción de su director en la tabla de directores.

INSERT INTO director(nombre, apellidos, imdb)

VALUES('Ridley', 'Scott', 'nm0000631');

5. Llegado a este punto tiene toda la informaciónnecesaria para insertar la película en la base de datos.Recuerde que los identificadores de cada uno de losregistros insertados hasta ahora son de incrementoautomático. La primera inserción de un valor en unacolumna de ese tipo toma el valor 1, la segunda el valor2 y así sucesivamente. Como la base de datos estárecién creada, cada uno de los elementos queinsertados tiene el identificador 1 en su tablacorrespondiente. Por lo tanto, puede insertar la películautilizando 1 como referencia al formato de grabación y1 como referencia al género cinematográfico.

INSERT INTO pelicula(

titulo, idsoporte, idgenero

)

VALUES('Blade Runner', 1, 1);

7. Siguiendo el mismo razonamiento, asocie a la películasu actor.

INSERT INTO actores_por_pelicula(

idpelicula, idactor

)

VALUES(1, 1);

8. Igualmente, asocie el director a la película.

INSERT INTO directores_por_pelicula(

idpelicula, iddirector

)

VALUES(1, 1);

Las inserciones del resto de películas se han realizadosiguiendo estos mismos pasos. Si examina el código delarchivo 02 - Insertar valores iniciales.sql podrácomprobar que en primer lugar se borran todos losregistros de todas las tablas de la base de datos. Tras ellose insertan todos los soportes en los que están laspelículas que tenemos, luego todos los géneros, acontinuación los actores y por último los directores. Y esen ese momento en el que se insertan las películas y seasocian con actores y directores.

Nota: Este proceso, mucho más complejo que el ut ilizado en el diseño original deuna sola tabla, t iene múlt iples ventajas, aunque también una desventaja: lainserción de una película requiere de comprobaciones e inserciones adicionalespor su parte. Como verá en capítulos sucesivos, esto no supone ningún problema:

Page 156: Desarrollo Web Con PHP y MySQL

existen formas de simplificar las inserciones para que no tenga que escribir unasola línea de SQL una vez haya comprobado que la base de datos funcionacorrectamente.

Ahora que dispone de la misma base de datos, con losmismos registros ordenados de la misma forma, con losmismos identificadores, que la utilizada en este libro,comienza el trabajo.

Existe un tercer archivo en el apartado de ejemplos deeste capítulo que le será de utilidad. Se llama 03 - Restode inserciones.sql. Ejecute las instrucciones de esearchivo para introducir muchos más valores en la bases dedatos de películas. Lo usará en el resto del capítulo. Sucontenido es el siguiente:

USE videoteca;

INSERT INTO soporte(nombre, descripcion)

VALUES('LD', 'Laser Disc');

INSERT INTO genero(nombre, descripcion)

VALUES('C', 'Comedia');

INSERT INTO actor(nombre, apellidos, imdb)

VALUES('Lee', 'Marvin', 'nm0001511');

INSERT INTO actor(nombre, apellidos, imdb)

VALUES('Clint', 'Eastwood', 'nm0000142');

INSERT INTO actor(nombre, apellidos, imdb)

VALUES('Jean', 'Seberg', 'nm0781029');

INSERT INTO actor(nombre, apellidos, imdb)

VALUES('Bruce', 'Dern', 'nm0001136');

INSERT INTO actor(nombre, apellidos, imdb)

VALUES('Bruce', 'Boxleitner', 'nm0000310');

INSERT INTO actor(nombre, apellidos, imdb)

VALUES('Rutger', ' Hauer', 'nm0000442');

INSERT INTO actor(nombre, apellidos, imdb)

VALUES('Sean', 'Young', 'nm0000707');

INSERT INTO actor(nombre, apellidos, imdb)

VALUES('Matthew', 'McConaughey', 'nm0000190');

INSERT INTO director(nombre, apellidos, imdb)

VALUES('Robert', 'Zemekis', 'nm0000709');

INSERT INTO director(nombre, apellidos, imdb)

VALUES('Douglas', 'Trumbull', 'nm0874320');

INSERT INTO pelicula(titulo, idsoporte, idgenero)

Page 157: Desarrollo Web Con PHP y MySQL

VALUES('Naves misteriosas', 1, 1);

Operadores

Desde que aprendió a sumar utiliza operadores: elsímbolo de la suma (+) es un operador, como lo son el de laresta y el de la multiplicación.

Ya ha utilizado operadores en SQL con anterioridad, enel ejemplo dedicado a las transacciones. Si recuerda,sumaba y restaba cantidades a los saldos de dos personaspara realizar una transferencia de capital.

MySQL permite utilizar esos operadores dentro de lasconsultas, algo que puede ser de mucha utilidad. Durantelos siguientes apartados aprenderá a manejar algunos delos operadores que MySQL proporciona.

Operadores aritméticos

En las cuentas sobre papel, las operaciones de suma,resta, multiplicación y división se representan utilizandolos operadores aritméticos +, -, * y /, respectivamente. ConSQL no es diferente.

Puede utilizar una consulta de selección de SQL paracomprobar el funcionamiento de estos operadores, no haráfalta base de datos alguna. Escriba la siguiente:

SELECT 2 + 2;

Y mirando a la figura 6.2, dígame, ¿cuántas son dos másdos?

Figura 6.2. Dos más dos son cuatro, señor maestro

Ésta no era difícil, ¿verdad? En líneas generales, asífuncionan todos los operadores aritméticos: un valor, unoperador y otro valor dan como resultado un tercer valor.Obviamente, el resultado varía dependiendo del operadorque tenga entre los valores. Y de los valores, claro.

Igual que se pueden realizar estas operaciones entre dosvalores numéricos en una consulta de selección, sepueden realizar entre un valor numérico y el valor de unacolumna de un determinado registro. Si la tabla depelículas almacenase el año en el que se estrenaron,podría saber cuántos años hace que se estrenó unadeterminada película con sólo restar al año actual el añode estreno.

La consulta podría ser ésta:

USE videoteca;

Page 158: Desarrollo Web Con PHP y MySQL

SELECT

YEAR(CURDATE()) - estreno

FROM

pelicula

WHERE

id = 12;

Donde 12 es el identificador de la película en cuestión yYEAR(CURDATE()) devuelve el año actual.

La consulta anterior se realiza sobre un determinadovalor de un registro pero, como ya sabrá a estas alturas,las consultas de selección pueden devolver más de unvalor. ¿Qué ocurre en estos casos, cómo se comportaMySQL cuando se le pide que realice una operaciónaritmética sobre una determinada columna de una tabla?

La respuesta es muy sencilla: la operación se realizasobre todos los valores devueltos por la consulta. Si tienealgunas nociones de programación, sabrá que para sumarun determinado valor a todos los elementos de una lista esnecesario utilizar un bucle que recorra todos los elementosde dicha lista, realizando la operación sobre todos y cadauno de ellos.

Sin embargo, con una sola instrucción en SQL obtendrálos mismos resultados. Siguiendo con el ejemplo anterior,la siguiente instrucción calcula el tiempo pasado desde elestreno de todas las películas de la base de datos:

USE videoteca;

SELECT

YEAR(CURDATE()) - estreno

FROM

pelicula;

La sencillez del lenguaje SQL es aparente: lo que pareceuna sola operación aritmética puede tener implícitas milesde ellas si la consulta devuelve miles de registros.

Y esta sencillez también es aparente en otro aspecto,aunque esto lo va a ver con otro ejemplo. Vuelva a utilizarla base de datos de pruebas. Ya vio cómo crearla:

DROP DATABASE IF EXISTS pruebas;

CREATE DATABASE pruebas;

Cree una tabla con dos columnas con las siguientesinstrucciones:

USE pruebas;

DROP TABLE IF EXISTS operadores;

CREATE TABLE operadores(

uno TINYINT UNSIGNED,

otro TINYINT UNSIGNED

);

Ahora, inserte un registro:

Page 159: Desarrollo Web Con PHP y MySQL

USE pruebas;

INSERT INTO operadores VALUES(3, 7);

El resultado de sumar los valores almacenados en lasdos columnas de esta tabla se consigue así:

USE pruebas;

SELECT uno + otro FROM operadores;

Obviamente, el resultado es 10. Pero, ¿cuál será elresultado de esta misma consulta cuando inserte estanueva pareja de valores?

USE pruebas;

INSERT INTO operadores VALUES(300, 500);

Uno diría que se obtendrán dos registros, el primero conel valor 10, resultado de la suma de las columnas de losprimeros valores insertados, y el segundo con el valor 800.Pues hay una sorpresa, mire en la figura 6.3 cuál ha sido elresultado real.

Figura 6.3. Fuera de rango

Y es que se ha salido de rango: ha insertado en unacolumna, que es de tipo TINYINT sin signo, valoressuperiores al máximo que puede almacenar una columnade este tipo (recuerde, el valor máximo es 255).

Se trata de algo similar a lo que pasaría si intentasemultiplicar dos valores enteros muy grandes, cuyoresultado estuviese por encima del máximo permitido poresa operación. Por ejemplo, tome el mayor número enteroque se puede almacenar en MySQL y multiplíquelo por 2:

SELECT 18446744073709551615 * 2;

El resultado: ese mismo número menos uno. La razón,de nuevo, que ha intentado almacenar en una columna unvalor mayor que el que cabe en ella. Fíjese en que elresultado cambia si en lugar de multiplicar por 2 (entero) lohace por 2,0 (coma flotante):

SELECT 18446744073709551615 * 2.0;

Operadores de comparación

Estos operadores permiten comparar dos valores. Elresultado de dicha comparación puede ser TRUE(verdadero), FALSE (falso) o NULL. El resultado de lacomparación será NULL si uno de los valores comparadoses NULL.

Page 160: Desarrollo Web Con PHP y MySQL

Nota: MySQL ut iliza un cero como FALSE y un uno como TRUE. Téngalopresente al obtener los resultados de las consultas. Las constantes TRUE, t rue,FALSE y false están a su disposición.

MySQL proporciona operadores para comprobar si dosvalores son iguales (=) o diferentes (<>), si uno es mayor(>) o menor (<) que otro, y las variantes mayor o igual (>=) ymenor o igual (<=).

Éstos son los operadores más utilizados cuando secomienza a trabajar con MySQL, ya que los otros son untanto esotéricos y no es hasta después de mucho trabajarcon bases de datos cuando se encuentra su utilidad. Porejemplo, existen operadores para comprobar si undeterminado valor pertenece a un conjunto de valores, o siestá dentro de un rango.

Fíjese en los quebraderos de cabeza que puede darNULL. Tanto es así, que hasta existe un operador deigualdad "a prueba de NULL": es el <=>. Pruebe el operadorde igualdad comparando dos parejas de valores:

SELECT 7 = 7, NULL = NULL;

Cualquiera diría que el resultado de esta consultadebería ser TRUE (cierto) en ambos casos. La realidad quemuestra la figura 6.4 es otra: mientras que 7 sí es igual a 7,cualquier comparación de un valor con NULL tendrá comoresultado NULL.

Figura 6.4. NULL no es igual a NULL

De ahí la existencia del operador "a prueba de NULL".Vea:

SELECT 7 <=> 7, NULL <=> NULL;

El resultado de esta consulta sí es cierto en amboscasos, como puede verse en la figura 6.5.

Figura 6.5. Bueno, ahora NULL sí es igual a NULL

Las comparaciones se pueden hacer entre cualquier tipode valores, cadenas de texto, por ejemplo. El comparadorde igualdad se puede utilizar para localizar aquellascadenas iguales a una dada. Por ejemplo, para localizar enla base de datos de actores todos aquellos cuyo apellido

Page 161: Desarrollo Web Con PHP y MySQL

fuese Crow. Resulta que está buscando un determinadoactor con ese apellido, pero no recuerda su nombre. Podríautilizar esta consulta:

USE videoteca;

SELECT

*

FROM

actor

WHERE

apellidos = 'Crow';

El resultado: todos los actores con ese apellido, porejemplo Russell, el famoso protagonista de "Gladiador"...¿que no? Ah, claro, es que su apellido es Crowe, no Crow.Bueno, para esos casos existe un operador especial paracadenas, LIKE.

El operador LIKE permite realizar comparaciones concadenas parciales, utilizando algunos caracteresespeciales. Antes buscaba todos los actores cuyo apellidofuese Crow, pero ahora quiere que la consulta devuelvatodos los actores con Crow como comienzo de su apellido.Utilice la siguiente consulta:

USE videoteca;

SELECT

*

FROM

actor

WHERE

apellidos LIKE 'Crow%';

Como ve, se ha utilizado el carácter del tanto por cientoa continuación de la cadena de comparación. Ese carácterconcordará con cuantos caracteres aparezcan tras Crow enlos apellidos de la tabla de actores; aunque el apellidoconcuerde exactamente, se obtendrá un resultado.

Si lo desea, puede utilizar el carácter del guión bajo parabuscar concordancias con un solo carácter, por ejemplo:

USE videoteca;

SELECT

*

FROM

actor

WHERE

apellidos LIKE 'Crow_';

Esta consulta sólo devuelve aquellos registros cuyoapellido sea Crow más un carácter al final. Amboscaracteres (% y _) se conocen como comodines.

Operadores lógicos

Están basados en las premisas de la lógica booleana, en

Page 162: Desarrollo Web Con PHP y MySQL

la que las operaciones básicas son NOT , AND, OR y XOR.Y precisamente éstos son los nombres de los operadores.

Nada hay nada más sencillo que saber cómo funcionanestos operadores. Por ejemplo, en la figura 6.6 se estáinvestigando el funcionamiento del operador AND. Laspruebas con NOT deben hacerse de forma distinta, ya quese trata del operador de negación y actúa sobre un únicovalor.

Figura 6.6. ¿Cómo funciona AND?

Ah, no se olvide de hacer estas mismas pruebas con elvalor NULL, ya sabe que no siempre se obtiene elresultado esperado.

Cambiando la precedencia

Se entiende por precedencia el orden en el que MySQLefectúa las operaciones de una determinada consulta. Essencillo saber el resultado de la operación 2 + 2, aunque noes evidente si el resultado de 2 + 2 * 5 será 12 o 20.Dependerá de si MySQL efectúa antes la suma o lamultiplicación.

Puede comprobar que el resultado es 12. MySQL norealiza las operaciones según las va encontrando: existeuna prioridad. Las multiplicaciones o divisiones se evalúanantes que las sumas o las restas, por ejemplo.

Sin embargo, es posible modificar esa prioridad siempreque lo desee, con sólo utilizar paréntesis. Aquellasoperaciones rodeadas por paréntesis se realizan antes.Esto permite modificar la operación anterior para que lasuma se realice antes que la multiplicación: (2 + 2) * 5 sídará como resultado 20.

Puede comprobarlo ejecutando la siguiente consulta:

SELECT

2 + 2 * 5,

(2 + 2) * 5;

En la figura 6.7 puede ver el resultado.

Figura 6.7. Uso de paréntesis

Page 163: Desarrollo Web Con PHP y MySQL

Manipulación de bases de datos

Durante los capítulos anteriores (incluso en éste) hemoscreado y eliminado bases de datos, pero no hemos visto lasintaxis exacta de la instrucción de creación de bases dedatos.

Creación

Las sintaxis de la sentencia de creación de base dedatos es muy sencilla:

CREATE DATABASE [IF NOT EXISTS] nombre;

Donde nombre es el nombre que quiera darle a la basede datos. Si intenta crear una base de datos cuyo nombreya esté asignado a otra base de datos, se producirá unerror del que MySQL avisará.

Si no desea que dicho error se produzca, incluya IF NOTEXISTS. El resultado: si existe una base de datos con esenombre, no se continúa con la instrucción de creación debases de datos actual.

Borrado

Tan sencilla como la creación, el borrado de bases dedatos sigue la sintaxis:

DROP DATABASE [IF EXISTS] nombre;

Si la base de datos no existe, MySQL avisará de ello,aunque puede evitar el mensaje si utiliza IF EXISTS. Enese caso, MySQL sólo ejecutará el borrado en caso de quela base de datos exista.

Advertencia: Tenga mucha precaución antes de ejecutar una instrucción deborrado de una base de datos. Tanto la base de datos como la carpeta y losarchivos que conforman la ubicación en disco de la misma serán eliminados.

Consultas de selección

La sintaxis de las consultas SELECT o de selección devalores no es tan sencilla como las vistas hasta ahora, demanera que vamos a simplificar su definición. Sinembargo, veremos las consultas más frecuentementeutilizadas, las que más útiles le serán durante su trabajo.

Simplificando, una instrucción SELECT debe seguir lasiguiente sintaxis:

SELECT

lista de columnas

[FROM

lista de tablas]

[WHERE

lista de condiciones]

Page 164: Desarrollo Web Con PHP y MySQL

[ORDER BY

campos por los que ordenar]

La lista de columnas que quiera obtener siempre debeestar presente aunque, como vio con los ejemplos de losoperadores, no es necesario que sean nombres decolumnas de tablas, pueden ser operaciones de algún tipo.

La razón es la misma que hace opcional la lista de tablasde la que obtener las columnas: es posible que la consultano necesite tabla alguna. La lista de tablas determinaráqué columnas podrá mostrar en la primera sección de laconsulta, es decir, las tablas sobre las que se realizará laselección.

En tercer lugar, puede indicar una serie de condicionesque quiera que cumplan los campos de los registros sobrelos que realiza la consulta, utilizando operadores decomparación: un valor debe ser mayor que otro, o igual aotro, una cadena debe parecerse a otra, etcétera.

Por último, podrá determinar la ordenación del resultadopor una o más columnas.

A continuación veremos algunos ejemplos de lasconsultas que más útiles pueden serle en su quehacerdiario. Trabajaremos con la base de datos de películas queconstruimos al empezar el capítulo.

Nota: Para los ejemplos necesitaremos trabajar con la misma base de datos. Esnecesario que haya ejecutado las instrucciones mostradas al principio de estecapítulo. Estas instrucciones están también en los archivos 01 - Crear la basede datos.sql, 02 - Insertar valores iniciales.sql y 03 - Resto deinserciones.sql que se encuentran en la Web de esta guía.

Listados de una tabla

En primer lugar, ¿qué actores están dados de alta en labase de datos? Seguro que sabe cómo obtener ese listado:

USE videoteca;

SELECT * FROM actor;

El resultado debería ser similar al que se puede ver en lafigura 6.8.

Figura 6.8. Listado de actores

Page 165: Desarrollo Web Con PHP y MySQL

El asterisco permite seleccionar todos los campos de lastablas afectadas por las consultas. Podría indicar quécampos quiere obtener como, por ejemplo, el identificador,el nombre y los apellidos:

USE videoteca;

SELECT

id,

nombre,

apellidos

FROM

actor;

Aunque también puede concatenar nombre y apellidosen un solo campo:

USE videoteca;

SELECT

id,

CONCAT(nombre, ' ', apellidos)

FROM

actor;

Esta última consulta tiene un problema "estético":observe el encabezado de la columna que muestra laconcatenación en la figura 6.9.

Figura 6.9. Encabezado de una concatenación

Es muy sencillo cambiar este comportamiento. Paraasignar un nombre a esa columna ha de indicarlo tras sudefinición en la instrucción de selección:

USE videoteca;

SELECT

id,

CONCAT(nombre, ' ', apellidos) AS nombre

FROM

actor;

Puede ver en la figura 6.10 cómo cambia el resultado,ahora la columna de la concatenación se llama nombre.

Figura 6.10. Cambio del nombre de un resultado

Un posible cambio en esta consulta sería obtener elresultado ordenado por apellido:

USE videoteca;

SELECT

id,

CONCAT(nombre, ' ', apellidos) AS nombre

FROM

actor

Page 166: Desarrollo Web Con PHP y MySQL

actor

ORDER BY

apellidos;

Como puede ver, se ha añadido al final de la consulta lacláusula ORDER BY, indicando a continuación los campospor los que se quiere ordenar el resultado. Podría cambiarel orden de los resultados utilizando DESC después decada campo, así la ordenación sería descendente (en lugarde ascendente).

Pero, ¿cómo ordenar el resultado usando un campocalculado (como la concatenación)? Es posible si se indicala posición que tiene ese campo en la lista de la selección.Por ejemplo, la función CONCAT es el segundo campoescrito tras SELECT . La siguiente consulta ordena elresultado de la consulta por el resultado de laconcatenación de nombre y apellidos de los actores:

USE videoteca;

SELECT

id,

CONCAT(nombre,' ',apellidos) AS nombre

FROM

actor

ORDER BY

2;

Otra consulta que le resultará muy útil es la que permitecontar el número de elementos en una determinada tabla.La siguiente le dirá el número de actores que tiene en labase de datos:

USE videoteca;

SELECT

COUNT(*)

FROM

actor;

Puede cambiar el nombre de las columnas devueltas:

USE videoteca;

SELECT

COUNT(*) actores

FROM

actor;

El resultado de esta consulta puede verse en la figura6.11.

Page 167: Desarrollo Web Con PHP y MySQL

Figura 6.11. Actores y películas

Listados de varias tablas

Para sacar partido al modelo relacional es necesariopoder extraer información a partir de datos repartidos porvarias tablas; hasta ahora no podemos hacer algo así yaque sólo hemos visto cómo realizar operaciones sobre unasola tabla.

Para realizar consultas de selección sobre más de unatabla es preciso indicarle a MySQL de qué tablas se trata ycómo están relacionadas. De nada serviría hacer unaconsulta como ésta:

USE videoteca;

SELECT

*

FROM

pelicula,

actores_por_pelicula,

actor;

El resultado es caótico, 120 registros resultantes: haobtenido todas las combinaciones posibles de los registrosde las tres tablas envueltas en la selección.

Para poder organizar la información de estas tres tablasha de utilizar de forma diferente la parte del FROM de laconsulta, indicando ahí cómo se relacionan las tablas. Parasimplificar las consultas se utilizarán seudónimos para losnombres de las tablas, como se hizo con los campos de lasconsultas.

Construya una consulta que devuelva la lista depelículas, con sus actores. En primer lugar, necesita saberqué campos desea obtener. Bastará con el título de lapelícula y la concatenación del nombre y los apellidos delactor. La primera parte de la consulta podría ser algo así:

...

SELECT

titulo,

CONCAT(nombre, ' ', apellidos) AS interprete

FROM

...

La parte "complicada" viene a partir del FROM. Es mejorir poco a poco. El primer paso es determinar qué tablasestán envueltas en la consulta. En la figura 6.12 puede verun fragmento del modelo relacional de la base de datos, el

Page 168: Desarrollo Web Con PHP y MySQL

dedicado a películas y actores.

Figura 6.12. Actores y películas, seleccionados

Considere como tabla principal la de películas, a la quellamaremos p en la consulta. La tabla de actores porpelícula une a los actores con las películas guardandoparejas de identificadores de películas y actores. A estatabla la llamaremos app. Por último, la tabla de actorestendrá el seudónimo a. Está claro que debemos utilizar losidentificadores de actores y películas para enlazar lastablas entre sí. La parte del FROM de la consulta queintentamos crear es similar a la siguiente:

...

FROM

pelicula p

JOIN actores_por_pelicula app

ON p.id = app.idpelicula

JOIN actor a

ON app.idactor = a.id

...

Aunque parezca algo enrevesado, en realidad no lo es.En primer lugar aparece la primera tabla, la de películas. Acontinuación de su nombre se indica su seudónimo. Comove, no es necesario utilizar AS.

La siguiente línea comienza con la palabra reservadaJOIN. Cuando utiliza esa palabra le está indicando aMySQL que quiere unir la tabla anterior (pelicula en estecaso) con la indicada a continuación(actores_por_pelicula).

La palabra reservada ON se utiliza para especificar quécampos se utilizarán como enlace entre los resultados.Tras ella, la pareja de campos que han de ser iguales. Enel primer caso, el identificador de la película debe ser igualal campo idpelicula de la tabla de actores por película.

Truco: Fí jese en que ut ilizamos los seudónimos de las tablas inmediatamente.De esa manera se simplifica enormemente el código, que de otra forma deberíaincluir los nombres completos de las tablas.

A continuación puede ver la consulta completa:

USE videoteca;

SELECT

titulo,

CONCAT(nombre, ' ', apellidos) AS interprete

FROM

Page 169: Desarrollo Web Con PHP y MySQL

pelicula p

JOIN actores_por_pelicula app

ON p.id = app.idpelicula

JOIN actor a

ON app.idactor = a.id;

La figura 6.13 muestra el resultado de esta consulta deselección sobre varias tablas, muy diferente al obtenidocon el primer intento, sin JOIN.

Figura 6.13. Actores y películas, seleccionados

Vamos a incluir en esta consulta el director de lapelícula. Para ello necesitamos incluir más campos en laselección, más tablas en la parte del FROM y másrelaciones entre campos.

Comencemos viendo los nombres de los campos:

...

SELECT

titulo,

CONCAT(nombre, ' ', apellidos) AS interprete,

CONCAT(nombre, ' ', apellidos) AS director

...

Parece correcto, pero no lo es. Existe un problema enesta selección: los nombres de los campos de la tabla deactores y de directores son los mismos. Si intenta haceruna consulta de esta forma, MySQL no será capaz dedeterminar a qué tabla pertenece cada campo y leinformará de un error.

Solucionar este error es bien simple: sólo necesitamosindicar también la tabla a la que pertenecen los campos,usando el seudónimo de la misma como prefijo del nombrede columna, separando ambos con un punto. La siguientees la consulta que buscamos:

USE videoteca;

SELECT

p.titulo,

CONCAT(a.nombre, ' ', a.apellidos) interprete,

CONCAT(d.nombre, ' ', d.apellidos) director

FROM

pelicula p

JOIN actores_por_pelicula app

Page 170: Desarrollo Web Con PHP y MySQL

ON p.id = app.idpelicula

JOIN actor a

ON app.idactor = a.id

JOIN directores_por_pelicula dpp

ON p.id = dpp.idpelicula

JOIN director d

ON dpp.iddirector = d.id;

El resultado de esta consulta puede verse en la figura6.14.

Figura 6.14. Películas, actores y directores

Las consultas que involucran datos de muchas tablas sepueden utilizar de varias formas. Una de ellas, la queacabamos de ver, para mostrar información conjunta. Otraaplicación interesante sería calcular el número de películasen las que aparece un determinado actor.

Podríamos saberlo de un vistazo, mirando el resultadode la figura 6.14, pero si el resultado de la consulta fuesenmiles de registros lo tendríamos mucho más complicado.

La siguiente consulta devuelve dos columnas: el nombredel actor en una de ellas, el número de películas en las queha participado en la otra:

USE videoteca;

SELECT

CONCAT(a.apellidos, ', ', a.nombre) actor,

COUNT(app.idpelicula) peliculas

FROM

actor a

JOIN actores_por_pelicula app

ON a.id = app.idactor

ORDER BY

a.apellidos,

a.nombre;

El resultado, mostrado en la figura 6.15, no parecedemasiado de fiar. ¿El señor Ford, protagonista de trespelículas en nuestra base de datos? Que sepamos, sólo dedos.

Page 171: Desarrollo Web Con PHP y MySQL

Figura 6.15. ¿Cuántas películas t iene un actor?

Para utilizar de forma conjunta y correcta COUNT y otrosvalores en la parte de selección de campos de unaconsulta es necesario indicar cómo agrupar la información.

Fíjese, le está diciendo a MySQL que quiere que cuentelas veces que aparece idpelicula en la tablaactores_por_pelicula, pero esa cuenta puede realizarsede muchas formas: contando todos los registros queaparecen en la tabla, o para una determinada película, opara un determinado actor.

En este caso particular, quiere ver las películas de cadaactor, así que tendría que agrupar por idactor, así:

USE videoteca;

SELECT

CONCAT(a.apellidos, ', ', a.nombre) actor,

COUNT(app.idpelicula) peliculas

FROM

actor a

JOIN actores_por_pelicula app

ON a.id = app.idactor

GROUP BY

a.id

ORDER BY

a.apellidos,

a.nombre;

Esto es otra cosa: ahora puede ver en la figura 6.16 lainformación que buscaba.

Figura 6.16. Todos los actores y sus películas

Page 172: Desarrollo Web Con PHP y MySQL

Sin embargo, aquí hay algo que no cuadra, ¿verdad?Como sabe, en la tabla de actores hay más de dosregistros, pero no aparecen como resultado de estaconsulta.

La razón: esos actores sin película no tienen ningúnregistro en la tabla actores_por_pelicula, de manera quela consulta anterior no los incluye en el resultado. Pero, ¿ysi quiere que aparezcan también los actores sin película eneste listado? Podría utilizar esta otra consulta:

USE videoteca;

SELECT

CONCAT(a.apellidos, ', ', a.nombre) actor,

COUNT(app.idpelicula) peliculas

FROM

actor a

LEFT JOIN actores_por_pelicula app

ON a.id = app.idactor

GROUP BY

a.id

ORDER BY

a.apellidos,

a.nombre;

Al usar LEFT JOIN se obtienen todos los registros de latabla de actores (que está a la izquierda de LEFT JOIN),aunque no exista correspondencia en la tabla de laderecha. El resultado de esta consulta puede verse en lafigura 6.17.

Figura 6.17. Todos los actores y sus películas

Suponga que cambia la forma en la que está construidala consulta, el orden de aparición de las tablas:

...

FROM

actores_por_pelicula app

LEFT JOIN actor a

ON app.idactor = a.id

...

Page 173: Desarrollo Web Con PHP y MySQL

El resultado variará. Volverá a obtener lo que vio en lafigura 6.16 porque ahora la tabla de la izquierda nocontiene más que esos dos actores.

Pero es sencillo volver a obtener el resultado de la figura6.17, utilice RIGHT JOIN en lugar de LEFT JOIN:

...

FROM

actores_por_pelicula app

RIGHT JOIN actor a

ON app.idactor = a.id

...

Truco: La clave es: ¿en qué parte (izquierda o derecha) está la tabla que sícont iene registros que no están en la otra tabla? Si la que sí cont iene esosregistros está a la izquierda, use LEFT JOIN, en caso contrario, use RIGHT JOIN.

Algunos de estos actores están dados de alta porqueparticipan en una de las películas, pero aún no se les haasociado a ella. Es el caso de Rutger Hauer y Sean Young,presentes en "Blade Runner". Inserte los registrosnecesarios para que esa asociación exista. Primeronecesita saber el identificador de la película "BladeRunner":

USE videoteca;

SELECT

id

FROM

pelicula

WHERE

titulo = 'Blade Runner';

Su identificador debería ser el 1. Ahora, losidentificadores de los dos intérpretes:

USE videoteca;

SELECT

id

FROM

actor

WHERE

nombre = 'Rutger' AND

apellidos = 'Hauer';

Esta consulta le... ¿no? ¿No devuelve nada? Pruebe abuscar sólo por el nombre, pero obtenga todos los campos,no sólo el identificador. Ahora sí, ¿verdad? Fíjese en lafigura 6.18, que muestra el resultado de la consulta.

Figura 6.18. Aquí hay algo raro...

Efectivamente, fíjese en la separación que hay entre

Page 174: Desarrollo Web Con PHP y MySQL

Rutger y la línea de la izquierda. ¿No le parece que haymás separación entre Hauer y la línea correspondiente?

Quizá haya un espacio antes del nombre. Inténtelo conesta consulta:

USE videoteca;

SELECT

id

FROM

actor

WHERE

nombre = 'Rutger' AND

apellidos = ' Hauer';

Fíjese en que se ha dejado un espacio entre la comillasimple y Hauer. Ejecute la consulta. Ahora sí, ¿verdad?

Nota: En breve verá cómo modificar este registro para solucionar el problema.

El identificador de este actor es el 8. ¿Y el de SeanYoung?

USE videoteca;

SELECT

id

FROM

actor

WHERE

nombre = 'Sean' AND

apellidos = 'Young';

El último que necesita, su identificador es el 9.

Fíjese en cómo se han utilizado condiciones en la partedel WHERE de la consulta en las consultas anteriores. Setrata de comparaciones entre valores, utilizando losoperadores que vimos anteriormente.

A continuación veremos cómo se modifican los valoresalmacenados en una tabla.

Actualizaciones

Las actualizaciones de datos se rigen por la siguientesintaxis:

UPDATE tabla [, tabla ...]

SET columna = valor [, columna2 = valor2 ...]

[WHERE condiciones]

Tras la palabra reservada UPDATE se indican las tablassobre las que se quiere realizar la operación deactualización de datos, a continuación los valores que setienen que asignar a los campos que interesa modificar.

Page 175: Desarrollo Web Con PHP y MySQL

Por último, es posible utilizar una lista de condiciones querestringirán el conjunto de registros cuyo valor semodificará. Estas condiciones son similares a las utilizadasen las consultas de selección.

Es necesario hacer un cambio en un determinadoregistro de la tabla de actores. Recuerde que el apellido deRutger Hauer tenía un espacio al comienzo, algo quecausó problemas en el apartado anterior. Esta modificaciónse puede realizar de la siguiente forma:

USE videoteca;

UPDATE

actor

SET

apellidos = 'Hauer'

WHERE

nombre = 'Rutger';

Aunque puede que le asalte la duda: ¿existirá algúnactor más con un espacio delante del apellido, o delnombre? Lo ideal sería poder eliminar esos espacios detodas las columnas donde sea necesario.

Puede hacerlo con una consulta de actualización sobrela tabla de actores y directores, que afecte a todos losregistros, utilizando la función TRIM. Esta función eliminalos espacios que anteceden o preceden a una cadena detexto. Ejecute esta consulta:

SELECT TRIM(' cadena ');

En la figura 6.19 puede comparar el aspecto de la cadenacon sus espacios antes y después, y el resultado deaplicarle la función TRIM.

Figura 6.19. Uso de TRIM

Puede eliminar los espacios que no le interesen denombres y apellidos en las tablas de actores y directoresutilizando la siguiente consulta:

USE videoteca;

UPDATE

actor a,

director d

SET

a.nombre = TRIM(a.nombre),

a.apellidos = TRIM(a.apellidos),

d.nombre = TRIM(d.nombre),

d.apellidos = TRIM(d.apellidos);

Como ve, no se ha utilizado la cláusula WHERE, lo quesignifica que se actualizarán todos los registros de ambastablas.

El apellido del actor Rutger Hauer ya es correcto, pero

Page 176: Desarrollo Web Con PHP y MySQL

aún no aparece como intérprete de ninguna película. Elsiguiente apartado está dedicado a las inserciones dedatos, viendo de paso cómo realizar las asociaciones entrepelículas.

Inserciones

La sintaxis de la instrucción de inserción es la siguiente:

INSERT INTO tabla [(columna,...)]

VALUES (expression,...);

La parte en la que se indican los nombres de lascolumnas se puede omitir si en la parte de los valoreséstos se escriben en el orden en el que se definieron alcrear la tabla, y además existe un valor para cada columna.

Inserte los valores necesarios en la tabla de actores porpelícula para que Rutger Hauer y Sean Young aparezcanen el reparto de "Blade Runner". Podría insertar el primeroasí:

USE videoteca;

INSERT INTO actores_por_pelicula(

idpelicula, idactor

)

VALUES(1, 8);

Pero también puede hacer esto otro:

USE videoteca;

INSERT INTO actores_por_pelicula

VALUES(1, 9);

La primera instrucción hace referencia a Rutger Hauer, lasegunda a Sean Young. Vea el efecto que han tenido estasinserciones:

USE videoteca;

SELECT

titulo,

CONCAT(nombre, ' ', apellidos) AS interprete

FROM

pelicula p

JOIN actores_por_pelicula app

ON p.id = app.idpelicula

JOIN actor a

ON app.idactor = a.id

WHERE

p.titulo = 'Blade Runner';

Puede ver el resultado de esta consulta en la figura 6.20.

Page 177: Desarrollo Web Con PHP y MySQL

Figura 6.20. Varios actores para una película

Como ve, es posible saber si una película tiene más deun actor si su título aparece más de una vez. Tambiénpodría construir una consulta que contase el número deactores que tiene cada película. Ya debe tener losconocimientos suficientes para hacerla por sí mismo, asíque le proponemos que lo intente por su cuenta antes demirar la solución que se incluye a continuación:

USE videoteca;

SELECT

p.titulo,

COUNT(app.idactor) interpretes

FROM

pelicula p

LEFT JOIN actores_por_pelicula app

ON p.id = app.idpelicula

GROUP BY

p.id;

El resultado de esta consulta puede verse en la figura6.21. Como puede comprobar, "Blade Runner" tiene tresactores, ya lo sabíamos. Pero esta consulta devuelve otrainformación digna de mención. Hay una película sinactores: Naves misteriosas.

Figura 6.21. Intérpretes por película

Gracias a esta consulta de selección hemos localizadouna inconsistencia en la base de datos: una película sinactores. ¿Existirá algún actor de esa película en la tabla deactores?

"Naves misteriosas" fue protagonizada por Bruce Dern,entre otros. Si lo buscamos en la base de datos verá queaparece con el identificador 6. Para añadirlo como actornecesitamos conocer el identificador de la película, que esel 4.

Una nueva inserción en la tabla de actores por películasolucionará el problema:

USE videoteca;

INSERT INTO

actores_por_pelicula(idpelicula, idactor)

VALUES(4, 6);

Si vuelve a repetir la consulta que dice cuántosintérpretes tiene asociados una determinada película,podrá comprobar que "Naves misteriosas" ya tiene uno.

Nota: Queda como ejercicio para el lector repet ir el mismo proceso con losdirectores. En caso de que encuentre alguna película sin director, podemosdecirle que Douglas Trumbull dirigió "Naves misteriosas".

Page 178: Desarrollo Web Con PHP y MySQL

Borrados

Una de las operaciones más peligrosas es el borrado deregistros. Una simple equivocación en la condición deborrado y se perderán datos.

La sintaxis de esta instrucción es la siguiente:

DELETE FROM tabla

[WHERE condición];

La parte del WHERE es similar a la utilizada enconsultas de selección y permite restringir los registrosque se borrarán. Si no indica ninguna condición seeliminarán todos los registros de la tabla.

Quizá necesite hacer algún borrado en la base de datos.Compruebe qué formatos de grabación están disponibles:

USE videoteca;

SELECT

*

FROM

soporte;

La figura 6.22 muestra el resultado. ¿Existen películasen todos esos formatos?

Figura 6.22. Formatos de grabación

Puede averiguarlo con la siguiente consulta:

USE videoteca;

SELECT

s.nombre,

COUNT(p.id) peliculas

FROM

soporte s

LEFT JOIN pelicula p

ON s.id = p.idsoporte

GROUP BY

s.id;

El resultado de esta consulta puede verse en la figura6.23: no existe ninguna película en formato LaserDisc.

Figura 6.23. Películas en cada formato

Puede que se haya deshecho de todas sus grabacionesen LaserDisc, o que el lector haya dejado de funcionar y las

Page 179: Desarrollo Web Con PHP y MySQL

películas ya no sean útiles. Elimine ese formato de la tablade soportes de grabación:

USE videoteca;

DELETE FROM

soporte

WHERE

id = 3;

¡Adiós, LaserDisc!

Durante este capítulo hemos visto la sintaxis de lasinstrucciones de selección, inserción, actualización yborrado de registros en tablas. También hemos visto cómocrear y borrar bases de datos.

La sintaxis real de las instrucciones que este capítulo hacubierto es más compleja, en realidad. Las opciones y losmodificadores son muchos, y el espacio disponible en estaguía es limitado. Sin embargo, ahora tiene la basenecesaria para enfrentarse a la documentación que MySQLproporciona en su Web sobre la sintaxis completa de suversión del lenguaje SQL con muchas más posibilidadesde éxito.

Lo más importante de este capítulo es que comprendaque con SQL se puede extraer cualquier información deuna base de datos, siempre que la base de datos estédiseñada correctamente. Quizá unas consultas sean máscomplicadas que otras, pero las herramientas están ahí. Ytan importante como extraer la información es saberguardarla, manteniendo la consistencia de los datos.

Otra conclusión que debe sacar de este capítulo es queel empleo de archivos de órdenes es mejor que el uso deherramientas visuales para tareas repetitivas.

Page 180: Desarrollo Web Con PHP y MySQL

7

PHP y MySQL

Hasta ahora nos hemos dedicado a adquirir losconocimientos básicos de MySQL y PHP. Hemos visto lomás destacado de ambas tecnologías, pero sin llegar amezclarlas (exceptuando la toma de contacto del capítuloprimero, claro). Pero incluso en ese capítulo nos limitamosa utilizar la cara funcional de MySQLi, la nueva forma deacceder MySQL desde PHP que apareció en la versión 5.

Durante este capítulo veremos cómo utilizar MySQLi ensu vertiente orientada a objetos. Ha de prestar especialatención a esta forma de trabajo, puesto que es la queutilizaremos en el resto de capítulos.

Comenzaremos viendo cómo se realiza una conexióncon un servidor de bases de datos, nuestro primer pasopara trabajar con MySQL.

Utilizando esa conexión realizaremos operaciones deconsulta, inserciones, actualizaciones y borrados sobrebases de datos existentes. Además de éstas, también esposible realizar operaciones de creación de bases de datosy tablas.

No dejaremos de ver las técnicas necesarias paracontrolar los errores que se puedan producir en nuestrosintentos de conexión y en posteriores consultas. Es muyimportante que sepamos cómo reaccionar ante situacionesno previstas.

Para terminar el capítulo veremos cómo modificar elarchivo de configuración de PHP para influir en elcomportamiento predeterminado de MySQLi. Estasopciones de configuración también pueden incluirse en lassecciones que se refieran a nuestro servidor Web, dentrode la configuración de Apache.

Acceso mejorado a MySQL

Aunque el equipo de desarrollo de PHP 5 se centró enmejorar aspectos del lenguaje como la orientación aobjetos, no por ello se descuidaron otros. Sin ir más lejos,la interfaz de acceso a MySQL fue mejorada.

Nota: No vamos a entrar en los detalles que hacen mejor a esta versión, pero nose trata sólo de aspecto técnicos: acceder a MySQL resulta mucho más sencillocon esta nueva interfaz.

PHP agrupa las funciones dentro de extensiones.Existen extensiones para acceder a MySQL, para gestionararchivos XML, para trabajar con archivos en formato PDF yun largo etcétera. Realmente largo: PHP dispone deextensiones para casi cualquier operación que puedaimaginar.

Page 181: Desarrollo Web Con PHP y MySQL

Mientras que el nombre de la versión primigenia esMySQL, el nombre de la nueva versión es MySQLi. Lacreencia más extendida es que la última "i" latina significamejorado (improved) aunque no es descabellado pensarque su significado sea otro. A fin de cuentas, PHP son lassiglas de PHP: Hypertext Preprocessor.

La "compatibilidad hacia atrás" (backwards compatibility)es un aspecto fundamental en la vida de un lenguaje deprogramación, las nuevas versiones deben ser capaces deejecutar programas desarrollados para versionesanteriores. Para que los programas ya existentes fuesencompatibles con las nuevas versiones de PHP eranecesario mantener las anteriores funciones de acceso,incluyendo las nuevas bajo una denominación diferente.

También se hizo un esfuerzo para que aquellos que yasupiesen cómo utilizar la extensión original de acceso aMySQL no encontrasen complicado dar el salto a la nuevaversión. Si es su caso, no tendrá que desandar el camino:todo lo que sepa de MySQL podrá aprovecharlo enMySQLi.

Sólo una cosa más antes de empezar: esta extensiónsólo funciona con servidores MySQL a partir de la versión4.1.

El ciclo de la vida

De la vida en común de PHP y MySQL, se entiende.Todas las operaciones que realicemos desde PHP conMySQL van a seguir los mismos pasos: conexión,operación y desconexión.

Conexión

El paso primordial de su relación con MySQL es laconexión. Sin conexión no habrá nada que pueda hacercon su servidor de bases de datos.

Durante el proceso de conexión indique dónde está elservidor de bases de datos, con qué usuario quiereconectar, cuál es su clave y cuál es la base de datos con laque va a trabajar.

Nota: Aunque, opcionalmente, puede indicar otros valores al realizar la conexión,como el puerto o el socket, en la mayoría de las ocasiones bastará con los cuatroparámetros antes enumerados.

Puede realizar la conexión en el mismo momento decrear el objeto que utilizará para conectar con la base dedatos. Por ejemplo, recuerde el ejemplo del primer capítulo.Entonces, conectábamos con la base de datos de películasutilizando el siguiente código:

<?php

Page 182: Desarrollo Web Con PHP y MySQL

$conexion = mysqli_connect(

'localhost',

'root',

'clave',

'videoteca'

);

if ($conexion == FALSE){

echo('Error en la conexión.');

exit();

}

...

Nota: Recuerde que, si instaló XAMPP para seguir el contenido de este libro, elusuario root de MySQL, por defecto, no tendrá contraseña alguna asignada. Porlo tanto tendrá que sust ituir 'clave' por '' (una cadena vacía).

Este código muestra cómo conectar con un servidorMySQL utilizando la versión funcional de MySQLi. Elservidor de bases de datos se encuentra en la mismamáquina que el servidor de páginas, el nombre del usuarioes root, la clave es clave y el nombre de la base de datoses videoteca.

Nota: Sabemos que ambos servidores están en la misma máquina porque seut iliza localhost como nombre del servidor. Este nombre se corresponde con la IP127.0.0.1, que siempre se asigna al ordenador con el que estamos trabajando.

Volvamos a escribir el código de conexión, pero ahorautilizando la versión orientada a objetos de MySQLi:

<?php

$videoteca = new mysqli(

'localhost',

'root',

'clave',

'videoteca'

);

if ($videoteca->errno != 0) {

echo('Error en la conexión.');

exit();

}

...

Si recuerda lo aprendido sobre programación orientada aobjetos en el capítulo 4 reconocerá que la primera línea delfragmento de código anterior crea un ejemplar de la clasemysqli, que hemos llamado videoteca.

Como parámetros del constructor de la clase hemospasado el nombre del servidor, el nombre del usuario, la

Page 183: Desarrollo Web Con PHP y MySQL

clave y el nombre de la base de datos con la que queremostrabajar.

Es posible que ocurra algún error durante el intento deconexión: el servidor MySQL puede estar apagado, noexistir la base de datos o quizá se haya equivocado en elnombre de usuario o en la contraseña. Para controlar esoscasos, no tiene más que utilizar la propiedad errno de laclase, que en caso de error devuelve el código asociado almismo. Si no se produjo ningún error, devolverá cero. Así,en caso de que no sea cero, informará de que ha ocurridoun error al realizar la conexión.

Pero si no ha ocurrido ningún error, podrá comenzarrealizar operaciones con la base de datos.

Operación

Una vez establecida la conexión, la más común de todaslas operaciones que vamos a realizar es la recuperación deinformación a través de consultas.

El objetivo de utilizar PHP y MySQL de forma conjuntaes, por lo general, la creación de aplicaciones Web. Porejemplo, una tienda a través de Internet. Por lo general losusuarios de estas aplicaciones realizarán consultas,mientras que los administradores se encargarán delmantenimiento de la base de datos.

En la tienda que acabamos de mencionar, los clientesbuscarían los productos que les interesasen (realizandoconsultas), mientras que los administradores seencargarían de añadir nuevos productos a la tienda,modificar los ya existentes o eliminar aquellos queestuviesen descatalogados.

Siguiendo con nuestro ejemplo del primer capítulo, estefragmento de código era utilizado para obtener la lista degéneros cinematográficos que hay en la base de datos:

...

$resultado = mysqli_query(

$conexion,

'SELECT * FROM genero'

);

if ($resultado == FALSE){

echo('Error en la consulta.');

}

...

La primera de las líneas anteriores utiliza la variable$conexión, que contiene la información devuelta por lafunción mysqli_connect() en el primer fragmento decódigo. Es el primer parámetro de la funciónmysqli_query(). El segundo es la consulta que queremosrealizar en la base de datos.

Page 184: Desarrollo Web Con PHP y MySQL

De igual forma que $conexion almacenaba lainformación necesaria para que MySQLi pudiese realizaroperaciones con la base de datos tras realizar la conexión,$resultado contiene la información necesaria para poderrecuperar todos los registros devueltos por la consulta.Puede recuperar esos registros utilizando el siguientecódigo:

...

while($fila = mysqli_fetch_row($resultado)){

printf(

"(%u) %s - %s<br/>",

$fila[0], $fila[1], $fila[2]

);

}

...

Cada llamada a mysqli_fetch_row() devuelve unregistro que se almacena en la variable $fila. Esta variablees, a su vez, una matriz, siendo cada uno de suselementos un campo del registro. Utilizamos printf() paramostrar los datos que acabamos de obtener.

Esta forma de trabajo es similar en otros lenguajes deprogramación con acceso a bases de datos. Sin embargo,existe una ventaja que PHP tiene sobre algunos de ellos.Al obtener un elemento de la lista de registros devueltos,avanzamos automáticamente al siguiente.

Esto, que puede parecer una tontería, en realidad nosevita muchos problemas. Suponga que escribe el mismobucle anterior, pero el avance automático no se realiza. Siolvidase avanzar al siguiente registro, el bucle noterminaría nunca y el programa no avanzaría, quedando,como se suele decir coloquialmente, "colgado".

Acaba de ver cómo se ejecuta una consulta y seobtienen los datos utilizando la versión funcional deMySQLi. El siguiente fragmento de código muestra elequivalente utilizando la versión orientada a objetos, conla que se obtiene el mismo resultado:

...

$resultado = $videoteca->query(

'SELECT * FROM genero'

);

if ($resultado == FALSE){

echo('Error en la consulta.');

}

while ($fila = $resultado->fetch_row()){

printf(

"(%u) %s - %s<br/>",

$fila[0], $fila[1], $fila[2]

);

Page 185: Desarrollo Web Con PHP y MySQL

);

}

...

Una de las ventajas de la programación orientada aobjetos es que el código resultante es más fácil decomprender que el equivalente funcional. Veamos lainstrucción que permite obtener uno por uno todos losregistros, en su versión funcional:

$fila = mysqli_fetch_row($resultado)

Comparémosla con el equivalente orientado a objetos:

$fila = $resultado->fetch_row()

En la versión funcional, llamamos a una función querecibe como parámetro el resultado de realizar la consulta.Estamos trabajando con una función. Sin embargo, en laversión orientada a objetos trabajamos directamente conel resultado de la consulta, la variable $resultado. Y,efectivamente, lo ha adivinado: en este caso esa variableno es otra cosa que un objeto.

Para terminar este ciclo de operaciones hemos de cerrarla conexión con la base de datos.

Desconexión

No por ser la última es la menos importante. El buenfuncionamiento de sus aplicaciones depende de que seacivilizado en el empleo de los recursos a su disposición.

El servidor de bases de datos puede respondersimultáneamente a varios clientes, pero hasta un límite.Una vez alcanzado ese techo, MySQL no podrá respondermás peticiones.

Una conexión no cerrada estará consumiendo recursos.El servidor de bases de datos es lo suficientementeinteligente para detectar aquellas conexiones ociosas, queno están realizando alguna tarea, y pasado un tiempo,cerrarlas. Pero mientras pasa ese tiempo, los recursosseguirán malgastándose.

Es curioso que, en muchas ocasiones, ese consumo derecursos se deba a que no se cierran las conexiones con labase de datos cuando se termina de trabajar con ella, algotan sencillo de hacer utilizando la versión funcional deMySQLi como el código que puede verse a continuación:

...

mysqli_free_result($resultado);

mysqli_close($conexion);

?>

Mientras que la primera línea elimina de memoria elresultado de la consulta a la base de datos, la segundacierra la conexión con MySQL. El mismo objetivo puedeobtenerse con las siguientes líneas, utilizando la versión

Page 186: Desarrollo Web Con PHP y MySQL

orientada a objetos de MySQLi:

...

$resultado->close();

$videoteca->close();

?>

Acabamos de recorrer el ejemplo del primer capítulo,viendo cómo se obtendría el mismo resultado utilizando laversión orientada a objetos de MySQLi. Veámoslocompleto:

<?php

$videoteca = new mysqli(

'localhost',

'root',

'clave',

'videoteca'

);

if ($videoteca->errno != 0) {

echo('Error en la conexión.');

exit();

}

$resultado = $videoteca->query(

'SELECT * FROM genero'

);

if ($resultado == FALSE){

echo('Error en la consulta.');

}

while ($fila = $resultado->fetch_row()){

printf(

"(%u) %s - %s<br/>",

$fila[0], $fila[1], $fila[2]

);

}

$resultado->close();

$videoteca->close();

?>

Aunque dista mucho de ser un programa profesional,cumple su función con dignidad, mostrando lo que lepedimos: la lista de géneros cinematográficos que hay ennuestra base de datos. La figura 7.1 muestra el resultadode ejecutar esta página. Como puede comprobar esidéntico al que se obtiene con la versión funcional deMySQLi, que pudo ver en la figura 1.19.

Page 187: Desarrollo Web Con PHP y MySQL

Figura 7.1. La lista de géneros, con objetos

Resumiendo, las operaciones que hemos tenido querealizar para realizar una consulta a nuestra base de datosde películas son siempre las mismas. La figura 7.2 describelas operaciones que tendrá que realizar para lograr suobjetivo.

Figura 7.2. El ciclo de la vida y los géneros

Nota: Como recordará, en el primer capítulo ya realizamos estas operaciones,aunque entonces con la versión funcional de MySQLi. Durante este capítulout ilizaremos la versión orientada a objetos.

Ahora que sabe cómo utilizar MySQLi para realizar lasoperaciones básicas (conexión, consulta y desconexión)vamos a profundizar en algunos aspectos interesantes deesta biblioteca de funciones.

Conjuntos de registros

Ni la conexión ni la desconexión con MySQL guardanningún misterio. Sin embargo, el resultado de realizar unaconsulta a la base de datos sí. Recordemos cómorecuperamos los registros devueltos por una consulta:

...

$resultado = $videoteca->query(

'SELECT * FROM genero'

Page 188: Desarrollo Web Con PHP y MySQL

'SELECT * FROM genero'

);

if ($resultado == FALSE){

echo('Error en la consulta.');

}

while ($fila = $resultado->fetch_row()){

printf(

"(%u) %s - %s<br/>",

$fila[0], $fila[1], $fila[2]

);

}

...

En primer lugar, realice la consulta llamando al métodoquery() del ejemplar de la clase la clase mysqli que estéutilizando. En este caso, ese ejemplar se llama$videoteca.

Si la consulta tiene éxito, podrá acceder a los resultadosgracias a la variable $resultado. Puede comprobar el tipode esta variable utilizando la función gettype():...

printf("%s", gettype($resultado));

...

El resultado será la cadena object. Es decir, ha obtenidouna referencia a un objeto, con sus métodos y susatributos. Pero, ¿qué resultado obtendrá si la consulta notiene éxito?

Para comprobarlo, cambie en la consulta el nombre de latabla (genero), de manera que no se corresponda con elnombre de ninguna tabla existente en la base de datoscon la que está trabajando (por ejemplo, generos). Siintenta realizar la consulta ocurrirá un error. Entonces, eltipo de la variable $resultado será boolean, lo quepermitirá localizar el problema.

Nota: A estas variables, que pueden adoptar varios t ipos en función de lascircunstancias, se les da el nombre de mixed.

La variable $resultado es un ejemplar de la clasemysqli_result. Tras realizar una consulta con éxito, puedeacceder a sus métodos y atributos. Veamos algunas de laspropiedades más interesantes:

num_rows: Contiene el número de registros que laconsulta ha devuelto. En nuestro ejemplo de la lista degéneros, puede ser interesante mostrar el número deregistros encontrados. Sólo tendría que incluir elsiguiente fragmento de código, siendo el resultado elque puede verse en la figura 7.3:

...

Page 189: Desarrollo Web Con PHP y MySQL

printf(

"Registros encontrados: %s.<br/><br/>",

$resultado->num_rows

);

...

Figura 7.3. Número de registros encontrados

field_count: Devuelve el número de columnas quetiene cada uno de los registros devueltos. Este valorpuede resultar interesante para controlar el ancho deuna tabla en la que mostrar el resultado de la consulta,por ejemplo.

También merecen especial mención los siguientesmétodos:

fetch_field: Si fetch_row() permite obtener uno poruno los registros devueltos por la consulta,fetch_field() devuelve información sobre los camposdel registro actual. El resultado lo devuelve en unamatriz, como hacía fetch_row(). La tabla 7.1 muestralos diferentes elementos en los que esta informaciónestá repartida, siendo cada uno un elemento de lamatriz devuelta. Podría utilizar estos valores comoencabezados de cada columna de una tabla HTML sidecidiese mostrar la información de los géneros dentrode una.

Tabla 7.1. Elementos de fetch_field()

Propiedad Descripción

name Nombre de la columna.

orgname Nombre original de la columna, en caso de que se utilizasen alias en la consulta.

table Nombre de la tabla.

orgtable Nombre original de la tabla, en caso de que se utilizasen alias en la consulta.

def Valor predeterminado.

max_length Tamaño del campo.

flags Atributos del campo, expresados de forma numérica.

type Tipo del campo.

decimals Si el campo es entero, indica el número de decimales empleados.

data_seek: Permite que nos desplacemos a un registroen concreto dentro de los resultados. Puede ser útilcuando no quiera realizar una iteración por todo elconjunto de resultados devuelto por la consulta quehaya realizado. Por ejemplo si sólo quiere mostrar losresultados en páginas de un número de elementoscada una, puede utilizar un bucle for controlado poruna variable cuyo valor irá incrementando. Ese mismo

Page 190: Desarrollo Web Con PHP y MySQL

valor será el que pasaremos a data_seek() paraobtener uno por uno los registros que nos interesen. Siobtiene cuatro registros, para obtener el primero debepasarle a la función un cero, para obtener el segundoun uno, y así sucesivamente. El siguiente fragmento decódigo ilustra el concepto, recuperando sólo el primerelemento devuelto por la consulta. Sustituya el buclewhile por:

...

$resultado->data_seek(0);

$fila = $resultado->fetch_row();

printf(

"(%u) %s - %s<br/>",

$fila[0], $fila[1], $fila[2]

);

...

Nota: Si lo desea puede encontrar más información acerca de la clasemysqli_result , sus métodos y sus atributos en la documentación de PHP.

Otras consultas

Como ya hemos comentado, el método query() puedeutilizarse para ejecutar consultas, pero no tienen que sersólo consultas de selección: también puede tratarse deconsultas de borrado, inserción o actualización.

La única diferencia está en que el resultado de ejecutareste tipo de consultas sólo devolverá TRUE en caso deéxito y FALSE en caso contrario, pero no un conjunto deregistros.

Como ejemplo, el siguiente fragmento de código, quenos permitiría insertar un nuevo género en la base dedatos, una vez establecida la conexión:

...

$sConsulta = <<<CONSULTA

INSERT INTO genero(

nombre,

descripcion

)VALUES(

'TH',

'Thriller'

);

CONSULTA;

$resultado = $videoteca->query($sConsulta);

if ($resultado == FALSE){

echo('Error en la consulta.');

Page 191: Desarrollo Web Con PHP y MySQL

echo('Error en la consulta.');

}

...

Como resultado, en la carga de la página que muestralos géneros podrá ver el que acabamos de añadir. Si lainserción no tuvo éxito podrá saberlo gracias al valordevuelto por el método query().

Consultas escapadas

No se trata de aquellas consultas que se fugaron (perdónpor el chiste fácil y malo). En la jerga de los informáticos,"escapar" se entiende en algunos contextos como "realizaruna conversión". En nuestro caso, el objetivo de estaconversión es hacer válida una cadena que no lo es. Y estacadena no es otra que una consulta.

Existen ciertos caracteres que no pueden incluirse enuna consulta, como las comillas simples. La siguienteinserción no sería válida:

<?php

$videoteca = new mysqli(

'localhost',

'usuario',

'clave',

'videoteca'

);

if (mysqli_connect_errno() != 0) {

echo('Error en la conexión.');

exit();

}

$sTitulo = "Ocean's Eleven";

$sConsulta =

"INSERT INTO pelicula(".

" titulo,".

" idsoporte,".

" idgenero".

")VALUES(".

" '".$sTitulo."',".

" 1,".

" 4".

")";

$resultado = $videoteca->query(

$sConsulta

);

if($resultado == FALSE){

echo('Error en la consulta.');

Page 192: Desarrollo Web Con PHP y MySQL

echo('Error en la consulta.');

echo($videoteca->error);

}

$videoteca->close();

...

El problema se debe, simplemente, a que el título tieneuna comilla simple, y MySQL lo entiende como el cierre deuna cadena. Pero luego encuentra otro carácter deapertura de cadena, no cerrado y se hace un verdadero lío.

Hay soluciones para todo. Inserte la siguiente líneaantes de crear la variable $sConsulta:

...

$sTitulo =

$videoteca->real_escape_string(

$sTitulo

);

...

El método real_escape_string() hará los cambiosnecesarios en el título para que la consulta de inserciónpueda realizarse.

Configuración

Al comienzo del libro hablamos sobre cómo programarusando PHP, aunque no entramos en detalles tales comolas posibles opciones de configuración existentes paraeste lenguaje. Tampoco vamos a verlas todas ahora,debido a que son demasiadas y no es éste un manual dereferencia. Existe numerosa documentación al respecto enla Web de PHP; concretamente en la siguiente dirección:

http://php.net/manual/es/configuration.php

Lo que sí trataremos en este apartado son las opcionesde configuración de PHP que afectan al funcionamiento deMySQLi. Y el primer paso es consultar los valores queestas opciones tienen en nuestro sistema.

Valores de configuración

Aunque existen varias formas de consultar los valores deconfiguración de MySQLi vigentes en nuestro sistema, lamás inmediata consiste en crear una página PHP con elsiguiente contenido:

<?php

phpinfo();

?>

Page 193: Desarrollo Web Con PHP y MySQL

Una vez la tenga, puede acceder a ella con cualquiercliente Web. Utilizando las herramientas de su clienteWeb, busque dentro de esa página el texto mysqli. Elcliente le mostrará la sección de parámetros deconfiguración de la biblioteca de funciones MySQLi.Debería ver algo parecido a lo que muestra la figura 7.4.

Figura 7.4. Configuración de MySQLi

Truco: El comportamiento de la función phpinfo() no es siempre el mismo.Compare el logot ipo de PHP que aparece al principio de la información devueltapor la función, con la imagen que muestra si usted cambia la fecha de suordenador al 1 de abril (el día de las inocentadas de los angloparlantes, april'sfools). No cabe duda: t ienen sent ido del humor.

La información respecto a la configuración de MySQLiestá divida en dos partes. La primera de ellas muestradetalles sobre el funcionamiento de MySQL, la versión dela API y la ubicación del socket (relacionado con lacomunicación del servidor MySQL y sus clientes).

Nota: API son las siglas de interfaz de programación de aplicaciones (Applicat ionProgramming Interface), es decir, del propio MySQLi.

La segunda sección es la que nos interesa, ya quemuestra los parámetros de configuración aplicables eneste momento, y que puede cambiar si lo consideraoportuno. Son los siguientes:

mysqli.default_host: Le permite indicar cuál será elservidor MySQL al que se conecte por defecto, si alestablecer la conexión no ha indicado ninguno. Comopuede ver en la figura 7.4, este parámetro no tieneningún valor asociado, por lo que cualquier intento deconexión sin indicar servidor será fallido.mysqli.default_port: Especifica el número de puertopredeterminado al que realizar las solicitudes deconexión. En este caso el valor predeterminado es

Page 194: Desarrollo Web Con PHP y MySQL

3306, el puerto estándar de MySQL. Es la existencia deeste parámetro el que permite realizar la conexión sinindicar valor alguno para el puerto. Sin este parámetrode configuración tendría que incluir el número depuerto al realizar la conexión, tras el nombre de la basede datos.mysqli.default_pw: Clave de acceso predeterminada,es decir, la que sus intentos de conexión utilizarán sino indica ninguna al intentar conectar. Por defecto nocontiene ningún valor.mysqli.default_socket: Permite indicar el socket quese utilizará durante la comunicación entre el servidorde bases de datos y el cliente. Si no se indica ningúnvalor (como es el caso) PHP utilizará los valoresinternos de los que dispone.mysqli.default_user: Nombre del usuariopredeterminado si al intentar conectar no indicaninguno. Está obligado a especificar el nombre delusuario porque, por defecto, este parámetro nocontiene ningún valor.mysqli.max_links: Número máximo de conexiones conMySQL permitidas desde sus aplicaciones PHP. Pordefecto, sin límite. Dependiendo de la naturaleza delas aplicaciones que esté desarrollando, o de lapotencia y recursos de su servidor, puede que quieraindicar un límite, de forma que su servidor no secolapse ante un aluvión de peticiones.mysqli.reconnect: Por defecto desactivado. Permiteque PHP intente, de forma automática, la reconexióncon el servidor MySQL en caso de que ésta seperdiese.

Nota: En la figura 7.4 habrá podido comprobar que existen dos columnasasociadas a valores: Local Value y Master Value (valores locales y maestros,respect ivamente). La primera se refiere a los valores aplicables a la página queestamos viendo ahora, mientras que la segunda a los aplicables a todas laspáginas. En breve veremos cómo hacer esta dist inción.

Ahora ya conoce los valores predeterminados de estosparámetros de configuración y cómo afectan alfuncionamiento de la biblioteca de funciones MySQLi.Pero, ¿cómo puede cambiar los valores de estosparámetros?

Modificación de la configuración

Todos los parámetros de configuración de PHP seencuentran en el archivo php.ini. La ubicación de estearchivo varía dependiendo del sistema operativo queutilice y de cómo haya instalado PHP.

Si utiliza Linux o Mac OS X, es más que probable quepueda encontrar este archivo en algún lugar de la carpeta/etc. En cambio, en Windows, es una buena ideamantenerlo en la carpeta del sistema (C:\WINNT puedeser uno de los nombres que tome), aunque también puedeestar en la carpeta en la que instaló PHP.

Page 195: Desarrollo Web Con PHP y MySQL

Independientemente del sistema operativo, si utilizóXAMPP para instalar Apache, PHP y MySQL, el archivophp.ini se encontrará en la carpeta /apache/bin/php.inidentro de la carpeta en la que XAMPP se instaló.

Esté donde esté el archivo, ábralo con su editor detextos favoritos y busque la sección MySQLi, indicando sunombre entre corchetes. En la figura 7.5 realizamos dichabúsqueda con el bloc de notas.

Figura 7.5. Sección MySQLi en php.ini

Haga una prueba sencilla: cambie el servidorpredeterminado al que conectar de manera que el valor deesta variable, que ahora mismo no tiene ningunoasignado, sea localhost.

Cuando haya realizado el cambio y guardado el archivo,sólo tiene que reiniciar el servidor de páginas Web,Apache. Una vez reiniciado podrá utilizar la página PHPque llama a la función phpinfo() para comprobar que elvalor del parámetro de configuración es el que hemosindicado en el archivo php.ini. El resultado debería sersimilar al que se puede ver en la figura 7.6.

Page 196: Desarrollo Web Con PHP y MySQL

Figura 7.6. Servidor MySQL predeterminado

¿Cómo puede aprovecharse de este cambio en susprogramas? Por ejemplo, no indicando el servidor MySQLal que quiere conectar. El siguiente fragmento de código lepermite conectar con el servidor MySQL que tenga en elmismo ordenador en el que esté trabajando:

<?php

$conexion = new mysqli(

'',

'root',

'clave',

'videoteca'

);

if ($conexion == FALSE){

echo('Error en la conexión.');

exit();

}

...

Como puede ver, el primer parámetro que pasamos alconstructor de la clase, que debería ser el nombre delservidor, ahora es una cadena vacía. Anteriormente esacadena era localhost. Sin embargo, podrá comprobar quela página sigue conectando, recuperando la lista degéneros cinematográficos y mostrándolos perfectamente.

Recapacitemos durante un momento: ¿qué beneficiopuede obtener modificando estos parámetros deconfiguración?

Ventajas

Suponga que tiene una página PHP por cada lista devalores de la base de datos. En cada una de esas páginasdebe realizar una conexión con el servidor MySQL para

Page 197: Desarrollo Web Con PHP y MySQL

posteriormente obtener los registros que quiere mostrar enla página, indicando el servidor, el nombre de usuario y laclave.

Tiene entonces el nombre de usuario y su contraseña entodos los archivos que conectan con la base de datos. ¿Nosería mejor tenerlos escritos en un solo sitio, una solavez? De esa forma, si por cualquier motivo tuviese quecambiar el nombre de usuario o su contraseña, podríahacerlo sabiendo que ese cambio en la configuración deMySQL sólo implica un cambio en su aplicación Web.

Esta ventaja supone comodidad para usted que, comoprogramador, debe asegurarse de que la aplicaciónfunciona correctamente bajo cualquier circunstancia. Peroexiste otra ventaja, relacionada esta vez con la seguridad.

Digamos que tiene cinco páginas PHP y, en cada una deellas, el nombre de usuario y la contraseña. Si logra queese nombre de usuario y esa contraseña estén en un sololugar habrá reducido cinco veces la probabilidad de quealguien se haga con la forma de acceder a su base dedatos.

Además, esta información se encuentra en un archivo deconfiguración del sistema. El acceso por parte dedesaprensivos a estos archivos es más complicado, algoque puede ayudarle a mejorar la seguridad de su aplicaciónWeb.

Inconvenientes

No todo iban a ser ventajas, este método también tienesus inconvenientes. Uno de ellos, aunque no demasiadoimportante, es que tiene que dejar claro a otros quepuedan trabajar con usted dónde están almacenados tantoel nombre de usuario como la contraseña de acceso.Imagine lo desconcertante que puede ser ver una línea decódigo que conecta con un servidor MySQL que no seespecifica, sin utilizar ni nombre de usuario ni contraseña.

También ha de asegurarse que en ninguna página de laWeb se muestre la información devuelta por phpinfo(), yaque esa página mostraría a todo el mundo la forma deconectar con el servidor de bases de datos.

Nota: Existen otras técnicas para almacenar en un único lugar los parámetros deconexión al servidor MySQL. Podría ut ilizar archivos de inclusión, de los quehablamos en el capítulo cuatro, o sus propios archivos INI.

Y por último, estos valores son globales, es decir, seaplican a todas las aplicaciones Web que se ejecuten bajosu servidor PHP. Obviamente, no todas las aplicacionesutilizarán los mismos parámetros de conexión.

Sin embargo, existe una forma de modificar las opcionesde configuración de MySQLi para sus aplicaciones,conservando las opciones globales del archivo php.ini tal ycomo estaban, antes de sus cambios.

Page 198: Desarrollo Web Con PHP y MySQL

Opciones de PHP en Apache

La opción más simple para probar los programas PHP deejemplo que hemos estado estudiando durante esta guíaes guardar los archivos correspondientes en la carpetahtdocs, en la ruta en la que Apache esté instalado.

Vamos a crear una nueva carpeta, dentro de htdocs,llamada pruebas. Guarde dentro de esta nueva carpetauna copia de la página PHP que llama a la funciónphpinfo() para mostrar las opciones de configuración.

Si abre dos clientes Web para observar la informacióndevuelta por cada página podrá comprobar que sonidénticas. Es justo esto lo que queremos cambiar.

PHP y Apache pueden trabajar de forma conjunta. Esposible incluir ciertas directivas en los archivos deconfiguración de Apache que serán pasadas a PHP.Usando estas directivas, puede separar sus aplicacionesPHP, todas basadas en las opciones de configuracióncontenidas en el archivo php.ini, pero cada una con susparticularidades.

Vamos a editar el archivo de configuración de Apache.Su nombre es httpd.conf y, si utiliza XAMPP, lo encontraráen la carpeta /apache/conf/, dentro de la carpeta en la queXAMPP se instaló.

Una vez tenga el archivo abierto con su editor preferido,busque la cadena de texto htdocs dentro de un elemento<Directory>. Debería ser algo así en Windows:

<Directory "C:/xampp/htdocs">

La ruta será diferente en Linux y Mac OS X. Ahora,localice la etiqueta que cierra esta sección de laconfiguración:

</Directory>

A continuación de esta etiqueta escriba las siguientesdirectivas de configuración:

<Directory "C:/xampp/htdocs/pruebas">

Options Indexes FollowSymlinks

AllowOverride None

Order allow,deny

Allow from all

php_admin_value mysqli.default_host localhost

</Directory>

Guarde los cambios, reinicie el servidor Apache y ahorarecargue las dos páginas que muestran el resultado dellamar a la función phpinfo() que están en las carpetashtdocs y htdocs/pruebas. Ahora, si revisa las opciones deconfiguración de MySQLi que dichas páginas muestran,comprobará que han dejado de contener la mismainformación. Mientras que la primera no tiene valordefinido para el servidor MySQL predeterminado, lasegunda muestra el valor localhost, como en la figura 7.7.

Page 199: Desarrollo Web Con PHP y MySQL

Figura 7.7. Diferentes valores locales y globales

La línea importante es la siguiente:

php_admin_value mysqli.default_host localhost

Puede ignorar las otras opciones de configuración. Conphp_admin_value le indica a Apache que lo que viene acontinuación es una variable de configuración de PHP, eneste caso sólo aplicable a la carpeta pruebas.

Ahora sí que podría establecer un nombre de usuario yuna clave diferente por cada aplicación, siempre que lascolocase en carpetas diferentes, pudiendo realizar lasconexiones con las bases de datos así:

<?php

$conexion = new mysqli('', '', '', '');

if ($conexion == FALSE){

echo('Error en la conexión.');

exit();

}

...

Y cada una de sus aplicaciones utilizaría los valores deconfiguración de PHP que hubiera indicado en el archivode configuración de Apache.

Y no sólo puede establecer estas diferentesconfiguraciones para cada carpeta que le interese, tambiénpuede diferenciar entre servidores virtuales, por ejemplo.

Nota: Los pasos descritos anteriormente son aplicables a configuracionesestándar en las que t iene acceso a los archivos de configuración de Apache. Si not iene acceso a ellos o no puede solicitar estos cambios al administrador delsistema, sepa que puede ut ilizar archivos .htaccess para modificar las opcionesde Apache de las carpetas Web a las que tenga acceso. Para más informaciónconsulte la documentación de Apache y póngase en contacto con eladministrador de sus sistemas.

Page 200: Desarrollo Web Con PHP y MySQL

Anteriormente hicimos un comentario no del todofavorable acerca de la profesionalidad de las páginas quehemos programado durante este capítulo. Esto es así portres motivos. El primero salta a la vista: el aspecto quetiene la lista de categorías no es demasiado vistoso. Losolucionaremos en el capítulo dedicado a Smarty.

El segundo motivo es la falta de interactividad. Aunquese trata de una página dinámica, cuyo aspecto cambia amedida que cambia el contenido de la base de datos con laque está trabajando, no permite que realicemos cambios,es necesario llevarlos a cabo en la base de datos parapoder mostrarlos en la página. En el capítulo dedicado alos formularios HTML verá cómo modificar el contenido dela base de datos directamente desde una página Web.

El último motivo que vamos a mencionar es la gestión deerrores. Y nunca más cierto que en este caso: no por ser elúltimo es el menos importante de los motivos. Sí, es ciertoque en el código que acabamos de escribir hemosintroducido algunos controles para los errores: al conectary al realizar consultas. Pero, ¿estamos seguros de quefuncionan?

La prueba más simple consiste en parar el servidor debases de datos y volver a cargar la página. Cuando elservidor de bases de datos esté detenido, intente cargarde nuevo la página que muestra la lista de categorías.Podrá ver el desastre que muestra la figura 7.8. La gestiónde errores que hemos realizado hasta ahora no ha servidode nada.

Figura 7.8. Control de errores

Sin embargo, se trata de un proceso muy importante quecon más frecuencia de la deseada se descuida. Veremoscómo combinar las herramientas que PHP nos proporcionapara procesar los errores con las propias de MySQL en elcapítulo dedicado a la gestión de errores.

Hasta ahora, ha aprendido lo básico de PHP, MySQL,además de a usarlos de forma conjunta. A partir de aquícomienza la parte divertida.

Page 201: Desarrollo Web Con PHP y MySQL

8

Formularios

No sólo de mostrar información vive la Web.

Uno de los principales atractivos de la programación conPHP y MySQL está en la interactividad, entendiéndolacomo la posibilidad de modificar desde nuestro propiocliente Web la forma en la que nos presentan los datosque solicitamos, e incluso los propios datos.

El único requisito necesario para que los usuarios denuestras aplicaciones puedan decirnos qué quieren haceres aprender a utilizar una de las características delestándar HTML: los formularios.

Un formulario no es más que un conjunto de elementosque podemos incluir en nuestras páginas HTML sobre losque los usuarios pueden realizar acciones y que,posteriormente, pueden enviarse de vuelta al servidor. Aligual que el servidor envía las páginas a los clientes, losclientes pueden responder con los valores que hayanintroducido en los campos de los formularios.

Durante este capítulo verá cómo crear sus propiosformularios, qué tipo de elementos puede incluir dentro deellos para permitir que los usuarios le envíen información ycómo procesar esa información en sus páginas PHP parapoder atender así a sus peticiones.

Verá también cómo orientar a los usuarios para que noenvíen valores incorrectos, como cadenas de texto dondese esperaba un número. Lograremos este objetivoutilizando scripts en el lado del cliente.

Si con lo visto hasta este capítulo ha logrado mostrar elcontenido de una base de datos en una página Web, apartir de ahora será capaz de modificarlo.

Cómo funcionan los formularios

Hablar de formularios es hablar de intercambio deinformación. ¿Recuerda cómo, en el primer capítulo,describimos la forma en la que un cliente Web solicitabainformación a un servidor, y éste se la devolvía?

En el caso de los formularios se trata de algo parecido:desde una página, el usuario puede enviar, junto con lapetición de una nueva página, una serie de valores. Lafigura 8.1 ilustra el proceso.

Page 202: Desarrollo Web Con PHP y MySQL

Figura 8.1. Intercambio entre páginas

Es decir, desde el formulario (sea lo que sea) enviamosde forma simultánea la petición de una nueva página yalgunos valores. El servidor Web pasa esos valores a lapágina, que los procesa y devuelve un resultado.

Si es la primera vez que se enfrenta a un formularioahora veremos con un poco más de detalle el aspecto deun formulario. En la figura 8.2 se puede apreciar el aspectode un hipotético formulario para dar de alta nuevosgéneros cinematográficos.

Figura 8.2. Formulario para nuevos géneros

Nota: El aspecto de la página de la figura 8.2 es muy rudimentario, pero lomejoraremos notablemente en el capítulo dedicado a las plant illas.

En esta página hemos creado un formulario con treselementos: dos cuadros de texto y un botón. Los cuadrosde texto nos permiten introducir el nombre del nuevogénero y su descripción.

Al hacer clic en el botón Guardar (el tercer elemento delformulario), los datos que el cliente introduzca en los doscuadros de texto se enviarán a la página de destino. Esapágina se encargará de dar de alta un nuevo génerocinematográfico con el nombre y la descripción que elusuario de nuestra aplicación Web haya introducido en loscuadros de texto.

Para los formularios disponemos de muchos otroselementos, además de los cuadros de texto y los botones.Veamos cómo crear utilizarlos.

Formularios HTML

Los formularios son como cualquier otro elemento que

Page 203: Desarrollo Web Con PHP y MySQL

pueda definir en una página HTML. Su declaración siguelas mismas reglas que la creación de tablas o la inserciónde imágenes.

Creación de formularios

Un formulario HTML debe comenzar con la etiqueta<form> y terminar con la etiqueta </form>. Se consideranelementos del formulario todos los que haya entre estasdos etiquetas, aunque sólo algunos de ellos enviaráninformación al servidor.

El elemento de apertura de un formulario dispone dealgunos atributos con los que se puede modificar sucomportamiento. Los más importantes de estos aparecenen la tabla 8.1.

Tabla 8.1. Atributos de un formulario

At ributo Descripción

name Nombre con el que puede referirse al formulario.

action Página a la que se enviará la información del formulario.

method Forma en la que dicha información es enviada al servidor.

target Nos permite indicar en qué ventana se abrirá la página indicada en el atributo action del formulario.

Es decir, la siguiente sería la declaración del comienzode un formulario:

...

<form

name="frm_alta_genero"

action="genero.php"

method="get">

...

El nombre de este formulario es frm_alta_genero. Es unnombre que describe adecuadamente la función delformulario, puesto que se utilizará para dar de alta unnuevo género cinematográfico en nuestra base de datos.

La información del formulario se enviará a la páginagenero.php. Es esa página la que tendrá que procesar losvalores que el usuario haya introducido en el formulario ycrear un nuevo género con ellos.

Por último, el método determina cómo se enviarán losdatos entre las dos páginas. No es sencillo de comprendersin ver un ejemplo, algo que haremos en breve. Por ahora,baste decir que el método GET envía los datos en elmismo URL de llamada a la página de destino, mientrasque el método POST los incluye en los encabezadosHTTP. Cada método tiene sus ventajas e inconvenientes,que también comentaremos en este capítulo.

Truco: Puede provocar que la página de dest ino del formulario, la indicada enaction, se abra en una nueva ventana con sólo añadir target="_blank" comoatributo de la declaración del formulario.

Page 204: Desarrollo Web Con PHP y MySQL

Elementos de un formulario

Hasta ahora ha visto dos de los elementos que puedencomponer un formulario: cuadros de texto y botones. Perotambién dispone de otros, como casillas de verificación,botones de opción, menús desplegables, listas e inclusoelementos ocultos. Antes de hablar de ellos, en la figura8.3 puede verlos todos juntos.

Figura 8.3. Elementos de un formulario

Seguro que los elementos mostrados en la figura 8.3 leson familiares: son los mismos que puede encontrar en losprogramas de su gestor de ventanas y se comportan deigual forma que en ellos. La única diferencia está en queahora es usted el que crea la aplicación y no otraspersonas.

Nota: Aunque existen otros elementos que puede incluir en un formulario HTML,con los que vea en este capítulo podrá sat isfacer la mayoría de las necesidadesde sus aplicaciones Web.

Estos elementos se crean de igual forma que cualquierotro elemento dentro de una página HTML: utilizandoetiquetas. Todos ellos comparten el nombre de la etiqueta,<input> y algunos atributos:

type: Su valor determina de qué elemento se trata(cuadro de texto, botón, etcétera).name: El nombre por el que tendrá que referirse a loselementos del formulario para recuperar su valor.value: El valor que toma el elemento.

Veamos ahora uno por uno todos los elementos quepodemos incluir en un formulario, así como sus atributos.

Cuadros de texto

El más sencillo de todos los elementos de un formulario,y con diferencia, es el cuadro de texto. Para crear unodentro de sus formularios ha de crear un elemento input yasignar el valor text al atributo type.

Un cuadro de texto puede tener los siguientes atributos:

Page 205: Desarrollo Web Con PHP y MySQL

size: Determina el ancho del cuadro de texto.maxlength: Limita el número máximo de caracteresque se pueden incluir en el cuadro de texto. Un cuadrode texto podría tener un tamaño de 16 caracteres, loque modificaría su aspecto, su ancho, pero el númeromáximo de caracteres podría ser 32.type: Si este atributo está presente y su valor espassword, cada carácter que introduzca en el cuadrode texto aparecerá como un asterisco, para evitar quemiradas indiscretas sepan lo que está escribiendo.

En la figura 8.4 puede ver un cuadro de texto de 16caracteres de ancho, con un máximo de 32 caracteres, ycuyo atributo type tiene el valor password.

Figura 8.4. Cuadro de texto

El código HTML para generar este cuadro de texto es elsiguiente:

...

<input

name="texto"

type="password"

value=""

size="16"

maxlength="32">

...

Casillas de verificación

Una casilla de verificación puede tener dos estados:marcada o no marcada. Son ideales para representarvalores de tipo booleano, TRUE o FALSE. Las casillas deverificación también pueden tener asociado un valor, peroes el atributo checked el que determina si la casilla estámarcada o no.

Si checked está presente en los atributos de la casillade verificación, ésta aparecerá marcada,independientemente de si ha asignado un valor a dichoatributo. Así, por ejemplo, el siguiente código HTML sirvepara generar una casilla de verificación, marcada pordefecto:

...

<input

name="casilla"

Page 206: Desarrollo Web Con PHP y MySQL

name="casilla"

type="checkbox"

value="checkbox"

checked="true">

...

Botones de opción

En contraste con las casillas de verificación, quepermiten seleccionar entre dos valores (cierto o falso,activo o no), los botones de opción suelen ir por grupos ypermiten escoger entre valores con más de una opción.

Si selecciona uno de los botones de opción cancelará laselección de otro. Para lograr este comportamiento ha dellamar igual a todos los botones de opción, utilizando elatributo name.

Igual que las casillas de verificación, el estado de unbotón de opción depende de la existencia o no del atributochecked. Si está presente, independientemente de suvalor, el botón de opción estará marcado. Si no estápresente, no lo estará.

La figura 8.5 muestra cómo puede utilizar estoselementos en un formulario.

Figura 8.5. Botones de opción

Y a continuación, el código de los botones de opcióndentro del formulario que puede verse en la figura 8.5:

...

<input

name="lenguaje"

type="radio"

value="php"

checked="true">

PHP<br/>

<input

name="lenguaje"

type="radio"

value="asp">

ASP<br/>

<input

name="lenguaje"

type="radio"

Page 207: Desarrollo Web Con PHP y MySQL

type="radio"

value="perl">

Perl<br/>

<input

name="lenguaje"

type="radio"

value="mande">

¿Páginas dinámicas? ¿Mande?<br/>

...

Menús desplegables

Podríamos establecer parecidos entre los botones deopción y los menús desplegables, ya que ambos ofrecenuna serie de opciones de las que sólo puede seleccionaruna. La figura 8.6 es una buena muestra de ello.

Figura 8.6. Géneros disponibles

Para crear una lista desplegable necesita dos elementos.El primero de ellos es el menú, el segundo las opciones; elmenú contiene las opciones. Así, el menú de la figura 8.6se crea con el siguiente código:

...

<select name="genero">

<option value="1" selected="true">

Ciencia Ficción

</option>

<option value="2">

Aventuras

</option>

<option value="3">

Drama

</option>

<option value="4">

Comedia

</option>

</select>

...

La declaración del menú sólo precisa de un nombre. Porotra parte, cada una de las opciones necesita un valor yuna de ellas, la seleccionada, dispondrá del atributoselected. El valor de este atributo es indiferente. El textoque aparecerá en cada una de las opciones del menú debe

Page 208: Desarrollo Web Con PHP y MySQL

estar entre las etiquetas de apertura y cierre del elementooption.

Listas

Una lista es una variedad de menú desplegable cuyoaspecto es el de una lista. Con la misma sintaxis que losmenús y sólo añadiendo el atributo size con un valormayor de uno podrá ver las opciones disponibles con otroaspecto. Por ejemplo, en la figura 8.7 puede ver una listacon los mismos valores que el menú de la figura 8.6.

Figura 8.7. Los géneros, en una lista

Pero existe una diferencia, ya que la declaración de estalista es la siguiente:

...

<select name="genero" size="4">

...

Es decir, tiene un tamaño de 4 elementos.

Aún existe una variante más que permite que se puedaseleccionar más de un elemento de la lista, de nuevomodificando la declaración de la lista. Observe el siguientecódigo:

...

<select name="genero" size="4" multiple="true">

...

Como puede apreciar existe un atributo más, multiple.Su valor es indiferente, basta con su existencia. Elresultado: podrá seleccionar más de un elemento de lalista, como puede verse en la figura 8.8. Para lograrlo sólotiene que seleccionar un elemento y, posteriormente,mientras mantiene la tecla Control (o Comando en MacOS X) pulsada, hacer clic sobre otro elemento.

Figura 8.8. Más de un género seleccionado

Botones

Page 209: Desarrollo Web Con PHP y MySQL

Botones

Se trata de uno de los elementos más importantes detodo formulario: es el que permite enviar la informaciónintroducida en el formulario de vuelta al servidor, para quela página de destino (la indicada en el atributo action delformulario) la procese.

Dos son los tipos de botón más utilizados. El primero deellos se utiliza para devolver a sus valorespredeterminados a todos los elementos del formulario delque forma parte. El atributo type de estos botones toma elvalor reset.

El segundo tipo es el que permite enviar el formulario ala página de destino. En este caso, el atributo type toma elvalor submit.

Nota: Existe un tercer t ipo de botón que se ut iliza cuando se desea que seejecute alguna tarea al hacer clic sobre el botón, en lugar de provocar el envío delos campos del formulario.

Campos ocultos

Hemos dejado para el final aquellos campos que, aunqueno se vean, pueden formar parte de un formulario. Estoscampos son muy útiles para enviar a la página de destinoalgún valor que no sea introducido o modificado por elusuario.

Para crear un campo oculto, el atributo type delelemento input debe tomar el valor hidden, como muestrael siguiente fragmento de código:

...

<input

type="hidden"

name="servidor"

value="pruebas"/>

...

Cuando se envíe la información a la página de destino,además de todos los campos visibles, también se enviaráuna variable llamada servidor cuyo valor será test.

Y con esto ya hemos visto cómo crear un formulario y loselementos que lo integran. Seguramente estará deseandoponerse manos a la obra. Y a ello vamos.

Envío de información

Vamos a crear un formulario para enviar a otra página lainformación necesaria para dar de alta un nuevo génerocinematográfico. El aspecto de esta página pudo verse enla figura 8.2, pero no así su código. Es el siguiente:

<html>

Page 210: Desarrollo Web Con PHP y MySQL

<head>

<title>Nuevo género</title>

</head>

<body>

<form name="frm_genero"

method="get" action="">

<strong>Nombre:</strong><br>

<input type="text" name="nombre"><br>

<strong>Descripción:</strong><br>

<input type="text"

name="descripcion"><br>

<input type="submit" value="Guardar">

</form>

</body>

</html>

Puede guardar esta página con el nombre genero.html.Tras la descripción que vimos anteriormente sobre loscomponentes de un formulario, y el mismo formulario,llaman la atención dos cosas.

La primera, que el atributo action del formulario no tieneningún valor asociado. En estos casos, el cliente Webasume que el destino de la página será la misma página.

En segundo lugar, no hemos dado nombre al botón,entre otras cosas porque no nos interesa el nombre quetenga, sólo que realice la acción de enviar los datos. Nopasa lo mismo con los cuadros de texto: precisamentequeremos enviar su contenido.

Cree una página HTML cuyo código sea el anterior ycárguela en su cliente Web. Introduzca algún valor en losdos cuadros de texto, haga clic en el botón Guardar yfíjese en el URL de la página que se cargará. Se tratará dela misma, no lo olvide. Ese URL puede verse en la figura8.9.

Figura 8.9. Envío de información

Page 211: Desarrollo Web Con PHP y MySQL

¿Qué hemos logrado al hacer clic en el botón Guardar?El cliente Web ha recogido los nombres y los valores detodos los elementos del formulario al que pertenece elbotón. Luego, ha construido un URL que comienza con eldestino del formulario.

A continuación de ese URL ha situado un signo deinterrogación para marcar el final del mismo y, tras dichosigno, el nombre de cada elemento de formulario y suvalor, con un signo de igualdad entre ambos. Cada parejaestá separada por un ampersand (&). Así, tras lainterrogación tenemos nombre=T , que indica que elcampo nombre tenía el valor T , y descripcion=Terror, quenos indica que la descripción del género es Terror.

Esto es así porque hemos utilizado el método GET paraenviar los valores del formulario. Si hubiésemosseleccionado el método POST no veríamos ningún valoren el URL puesto que todos se envían en los encabezadosHTTP, sólo visibles por el servidor, pero con los que deigual forma podrá trabajar en sus páginas PHP.

Hemos realizado esta primera prueba con una páginaHTML, que no nos permite trabajar con la informaciónenviada desde un formulario. Por fortuna, con PHPpodemos.

Recuperación de información

El primer paso: convertir la página anterior a PHP. Esfácil, sólo tiene que cambiar la extensión del archivo yseguirá funcionando como hasta ahora. Su nombre serágenero.php.

El segundo paso es añadir al principio de la página elcódigo PHP necesario para realizar alguna operación conlos valores recibidos. Pero antes, veamos dónde encontraresos valores.

En el segundo capítulo vimos una de las característicasque más sorprende a los que llegan a PHP desde otroslenguajes de programación: las matrices.

Como vimos, en PHP podemos utilizar lo que se conocecomo matrices asociativas, en las que cada elemento de lamisma dispone de un nombre y un valor asociado. ¡Vaya,qué casualidad! Es justo lo que un formulario pasa a lapágina de destino, ¿verdad?

Para facilitarle la tarea, PHP pone a su disposición dosmatrices globales, disponibles en todas sus páginas,dentro de las que se encuentran todos los valores pasadosdesde una página a otra: $_GET y $_POST . Lógicamente,la primera de las matrices contendrá los valores pasados ala página cuando el método seleccionado sea GET ,mientras que la segunda lo hará cuando el método seaPOST .

La forma más sencilla, más rápida, pero también la

Page 212: Desarrollo Web Con PHP y MySQL

menos elegante, de utilizar estas variables es incluir elsiguiente código al comienzo de la página PHP:

<?php

echo('<pre>');

print_r($_GET);

echo('</pre>');

?>

...

Cargue de nuevo la página genero.php tras añadir esecódigo al principio de la página. Verá algo parecido a lo queaparece en la figura 8.10, algo no demasiado agradable.

Figura 8.10. Aún no vemos nada

Y cuando introduzca valores en los cuadros de texto yhaga clic en el botón Guardar, el aspecto de la página nova a mejorar, pero sí podrá ver que algo está empezando afuncionar: habrá conseguido mostrar en la página losvalores del formulario, como puede verse en la figura 8.11.

Figura 8.11. Mostramos los valores pasados

Como ve, la matriz $_GET tiene un elemento por cadauno de los pasados en el URL. De igual forma, si el métodoempleado fuese el POST , utilizaríamos la matriz $_POST .

Pero ¿qué ocurre cuando no sabe qué método se empleópara enviar la información a la página actual? La páginaque vamos a crear a continuación le será de mucha

Page 213: Desarrollo Web Con PHP y MySQL

utilidad, tanto ahora como en sus futuros desarrollos, paracomprobar los valores que una página pasa a otra.

Esta página, a la que llamaremos formulario.php,averiguará el método empleado para el paso de valoresdesde el formulario que la llama y mostrará una tabla contodos los valores pasados.

El primer paso será aprovecharnos de una circunstancia:los valores se deben pasar con el método POST o con elmétodo GET , pero no con los dos a la vez. Tanto $_GETcomo $_POST son matrices, de forma que puede saber elnúmero de elementos que contienen.

Así que podemos tener una variable que apunte a una delas dos matrices, aquella que tenga elementos, noteniendo que elegir entre trabajar con una o con otra. Elcódigo de formulario.php comienza así:

<?php

$pParametros = FALSE;

if(count($_GET) != 0){

$pParametros = $_GET;

}elseif(count($_POST) != 0){

$pParametros = $_POST;

}

...

Con este bloque de código hemos logrado nuestroobjetivo. Creamos una variable llamada $pParametros. Lap viene de puntero, apuntador, un lastre de tiempospasados que tendrá connotaciones malignas para aquellosque conozcan lenguajes como C.

El valor predeterminado de esta variable será FALSE. Sino se han pasado parámetros a la página, podrá saberlocomprobando que $pParametros es FALSE. En ese casono tendrá que mostrar ninguna información.

A continuación, compruebe si $_GET contiene algúnelemento. Si es así, sabrá también que $_POST nocontendrá ninguno, así que haga que $pParametrosapunte a $_GET . En caso contrario, $pParametrosapuntará a $_POST .

El resultado: sea cual sea el método empleado para elpaso de los valores a esta página, $pParametroscontendrá esos parámetros. Sólo queda mostrar lainformación pasada a la página:

...

if($pParametros == FALSE){

echo('No se ha pasado valor alguno.');

exit();

}

echo('<table border="1">');

Page 214: Desarrollo Web Con PHP y MySQL

echo('<tr>');

echo('<th>Nombre</th><th>Valor</th>');

echo('</tr>');

foreach($pParametros as $nombre => $valor){

echo('<tr>');

printf(

"<td>%s</td><td>%s</td>",

$nombre,$valor);

echo('</tr>');

}

echo('</table>');

?>

Guarde en una página llamada formulario.php el códigoque acaba de ver.

Ahora, en cualquiera de las páginas que hemos creadoen este capítulo como, por ejemplo, aquella cuyo código sepodía ver al principio del apartado 8.3, cambie el valor delatributo action por formulario.php. Así, al hacer clic en elbotón Guardar, la página de destino será esta nueva.

Abra la página HTML en un cliente Web, asigne valoresa los cuadros de texto y haga clic en Guardar. Podrá veralgo parecido a lo que muestra la figura 8.12.

Figura 8.12. Todos los valores pasados

Pruebe dos cosas más. La primera, cambie el método deenvío de la página HTML, de get a post. Recargue lapágina en su cliente Web, introduzca valores en loscuadros de texto y haga clic en el botón. Seguirá viendo lomismo que en la figura 8.12, salvo que ahora los valorespasados no aparecerán en el URL.

En segundo lugar, intente cargar la páginaformulario.php directamente, sin llamarla desde ningunaotra. La página le informará de que no se le ha pasadoningún valor.

A medida que vaya creando sus propios formularios, estapágina le será de mucha ayuda, ya que le permitirácomprobar que una página pasa a la otra los valores queusted esperaba.

Ahora ya puede emprender la tarea que era el objetivodesde que comenzó este capítulo: crear una página PHP

Page 215: Desarrollo Web Con PHP y MySQL

que le permita dar de alta nuevos géneros.

Inserción de registros

La verdad es que casi disponemos de todos loselementos necesarios para crear una página que nospermita insertar nuevos géneros cinematográficos en labase de datos de películas: tenemos el formulario ysabemos cómo obtener los valores que necesitamos pararealizar la inserción. Sólo nos queda ponerlo todo junto.

Vamos a utilizar una sola página, a la que llamaremosgenero.php. Aunque ya hemos visto su código, no está demás recordarlo. Es el siguiente:

<html>

<head>

<title>Nuevo género</title>

</head>

<body>

<form name="frm_genero"

method="get" action="">

<strong>Nombre:</strong><br>

<input type="text" name="nombre"><br>

<strong>Descripción:</strong><br>

<input type="text"

name="descripcion"><br>

<input type="submit" value="Guardar">

</form>

</body>

</html>

Como sólo vamos a utilizar una página, introduciremoslas instrucciones PHP al comienzo de ella. El primer pasoconsiste en crear la referencia a la matriz de valorespasados que corresponda, ya sea el método GET o POST ,con la misma intención que en el apartado 8.4. El resultadoes que tendremos todos los parámetros pasados a lapágina en $pParametros:

<?php

$pParametros = FALSE;

if(count($_GET) != 0){

$pParametros = $_GET;

}elseif(count($_POST) != 0){

$pParametros = $_POST;

Page 216: Desarrollo Web Con PHP y MySQL

}

...

En la página formulario.php, el siguiente paso eracomprobar si $pParametros era FALSE, pero ahora nosinteresa hacer justo lo contrario. Por lo tanto, sólorealizaremos alguna acción si se pasó algún parámetro ala página:

...

if($pParametros != FALSE){

...

}

...

Lo que nos interesa ahora es ver qué código escribimosdentro del bloque if, puesto que ese será el que realizará lainserción en la base de datos.

Debemos llevar a cabo tres tareas:

1. Obtener los valores que necesitamos y comprobar queson válidos.

2. Realizar la inserción en la base de datos.3. Informar del éxito o fracaso de la operación.

El primer paso es bien simple:

...

$sNombre = $pParametros['nombre'];

$sDescripcion = $pParametros['descripcion'];

if(($sNombre == '') or

($sDescripcion == '')){

$sMensaje =

'El nombre y la descripción '.

'del nuevo género no pueden '.

'ser cadenas vacías.';

echo($sMensaje);

}else{

...

}

...

Es en la parte del else en la que realizaremos lainserción en la base de datos. Ya disponemos de todos losvalores necesarios, así que vamos a ello. Primero, creamosla consulta:

Page 217: Desarrollo Web Con PHP y MySQL

...

$sConsulta = <<<CONSULTA

INSERT INTO genero(

nombre,

descripcion

)VALUES(

'$sNombre',

'$sDescripcion'

);

CONSULTA;

...

Ahora sólo tenemos que establecer la conexión con labase de datos, ejecutar la consulta y cerrar la conexión:

...

$videoteca = new mysqli(

'', '', '', 'videoteca');

if ($videoteca == FALSE){

echo('Error en la conexión.');

exit();

}

$resultado = $videoteca->query($sConsulta);

if($resultado == FALSE){

echo('Error en la consulta.');

echo($videoteca->error);

exit();

}

echo('Nuevo género añadido.<hr/>';

$videoteca->close();

...

Nota: Si le parece raro cómo realizamos la conexión con la base de datos, quizánecesite echar un vistazo al apartado 7.6 del capítulo 7, en la que se comentanalgunos aspectos de la configuración de las aplicaciones PHP. En concreto, cómoincluir el nombre del servidor MySQL, el del usuario y su clave en los archivos deconfiguración de Apache.

Nada más sencillo, ¿verdad? A continuación puede ver elcódigo completo de está página, HTML incluido:

<?php

$pParametros = FALSE;

if(count($_GET) != 0){

$pParametros = $_GET;

}elseif(count($_POST) != 0){

Page 218: Desarrollo Web Con PHP y MySQL

$pParametros = $_POST;

}

if($pParametros != FALSE){

$sNombre = $pParametros['nombre'];

$sDescripcion =

$pParametros['descripcion'];

if(($sNombre == '') or

($sDescripcion == '')){

$sMensaje =

'El nombre y la descripción '.

'del nuevo género no pueden '.

'ser cadenas vacías.';

echo($sMensaje);

}else{

$sConsulta = <<<CONSULTA

INSERT INTO genero(

nombre,

descripcion

)VALUES(

'$sNombre',

'$sDescripcion'

);

CONSULTA;

$videoteca = new mysqli(

'', '', '', 'videoteca');

if ($videoteca == FALSE){

echo('Error en la conexión.');

exit();

}

$resultado =

$videoteca->query($sConsulta);

if($resultado == FALSE){

echo('Error en la consulta.');

echo($videoteca->error);

exit();

}

echo('Nuevo género añadido.<hr/>');

$videoteca->close();

}

}

?>

Page 219: Desarrollo Web Con PHP y MySQL

<html>

<head>

<title>Nuevo género</title>

</head>

<body>

<form name="frm_genero"

method="get" action="">

<strong>Nombre:</strong><br>

<input type="text" name="nombre"><br>

<strong>Descripción:</strong><br>

<input type="text"

name="descripcion"><br>

<input type="submit" value="Guardar">

</form>

</body>

</html>

La figura 8.13 muestra el aspecto de esta página trasañadir una nueva categoría a la base de datos. En el URLse pueden ver los parámetros que se han pasado a lapágina.

Figura 8.13. Nuevo género añadido

En el capítulo anterior creamos una página que nospermitía ver la lista de géneros disponibles en nuestrabase de datos. Pruebe a cargarla ahora, podrá comprobarque dispone de un género más: el que acaba de añadirgracias a nuestro formulario.

Puede mejorar el funcionamiento de sus formulariosañadiendo un nivel más de control, verificando en el ladodel cliente, además de en el lado del servidor, que losvalores que se van a enviar cumplen los criterios quenecesita.

Page 220: Desarrollo Web Con PHP y MySQL

Control en el lado del cliente

Este libro es como una torre de Babel: hasta ahorahablamos HTML, PHP y SQL. Como puede que a alguien leparezca poco, vamos a por otro lenguaje más: JavaScript.

JavaScript es un lenguaje que permite comprobar quelos valores que los clientes intentan enviar en losformularios son correctos, ajustándose a los parámetrosque usted decida.

Su sintaxis es muy similar a la de PHP (¿o deberíamosdecir lo contrario?). Aunque puede incluir el códigoJavaScript en el mismo archivo PHP o HTML, lo normal esguardarlo en archivos independientes de la propia página.

En concreto, ¿qué nos interesa hacer con la página paradar de alta nuevos géneros? Comprobar, antes de enviarnada al servidor, que se han introducido tanto un nombrecomo una descripción para el género. De esta formaevitaremos más de una llamada errónea a la página.

La siguiente función realiza la tarea que nos interesa:

function comprobar_valores(){

var frm = document.frm_genero;

var sNombre = frm.nombre.value;

var sDescripcion = frm.descripcion.value;

if(sNombre == ''){

alert('Falta el nombre.');

frm.nombre.select();

return(false);

}

if(sDescripcion == ''){

alert('Falta la descripción.');

frm.descripcion.select();

return(false);

}

return(true);

}

Antes de ver cómo insertar este código en su página,veamos qué hace. En primer lugar, la variable frm es unareferencia a document.frm_genero, el formulario quecontiene los valores que queremos comprobar.

Desde JavaScript dispone de una jerarquía de clases quele permite acceder a cualquier elemento o atributo de lapágina. Ahora mismo sólo nos interesan los formularios ylos valores de sus elementos. El elemento que comienza lajerarquía es document y representa a la página Web.Dentro de él está nuestro formulario, al que asignamos elnombre frm_genero, así que podremos acceder a él

Page 221: Desarrollo Web Con PHP y MySQL

mediante document.frm_genero.

De igual forma, accedemos a los elementos delformulario por su nombre: frm.nombre será el cuadro detexto para el nombre, y frm.descripcion el cuadro de textopara la descripción.

De ambos cuadros de texto nos interesa su valor. Loguardamos en sendas variables. Posteriormentecomprobamos que no estén vacías, comparando su valorcon una cadena vacía. Si una de ellas está vacía,mostramos un mensaje al respecto y seleccionamos elcuadro de texto que corresponda.

Ahora, ¿cómo asociamos este código a la página PHP?Con una sencilla línea:

...

<script

language="javascript"

src="genero.js">

<!--

-->

</script>

...

Esta instrucción debe ir antes del fin la etiqueta <head>,de forma que la parte HTML de la página genero.php debequedar así:

<html>

<head>

<title>Nuevo género</title>

<script

language="javascript"

src="genero.js">

<!--

-->

</script>

</head>

<body>

<form name="frm_genero"

method="get" action="">

<strong>Nombre:</strong><br>

<input type="text" name="nombre"><br>

<strong>Descripción:</strong><br>

<input type="text"

name="descripcion"><br>

<input type="submit" value="Guardar">

Page 222: Desarrollo Web Con PHP y MySQL

</form>

</body>

</html>

Ahora sólo tenemos que asociar la funcióncomprobar_valores() al botón Guardar, para que cuandose haga clic en dicho botón el cliente Web intenteejecutarla. Para ello utilizamos el evento onClick delbotón, que se lanza cada vez que se hace clic sobre dichobotón. El código de la etiqueta del botón sería el siguiente:

...

<input

type="submit"

value="Guardar"

onClick="return comprobar_valores()">

...

Cada vez que se haga clic, el cliente Web llamará a lafunción. Si todos los valores necesarios han sidointroducidos, la función devolverá true. En ese caso, elformulario se enviará a la página de destino. Pero si no secumple algún requisito, como la función devuelve false, elenvío del formulario se cancela.

La figura 8.14 muestra lo que ocurriría si intentásemoscrear un nuevo género sin descripción asociada.

Figura 8.14. Sin descripción, no hay género

Truco: ¿Quiere acceder y manipular aún más fácilmente los elementos de losformularios desde el código JavaScript? Eche un vistazo a jQuery:ht tp://jquery.com/.

Durante este capítulo ha visto una colección dediferentes tecnologías trabajando juntas para conseguir elmismo resultado: que desde una página Web, un usuariopueda modificar valores de una base de datos.

El mayor esfuerzo debe ponerse en asegurar que lainformación que el cliente envía cumpla los criterios quebuscamos. La existencia del campo es el primer paso, pero

Page 223: Desarrollo Web Con PHP y MySQL

buscamos. La existencia del campo es el primer paso, perono el único.

Si pide al cliente que introduzca una fecha, un precio ouna dirección de correo electrónico en algún campo delformulario habrá de comprobar que se trata de una fecharazonable, un valor numérico o una dirección de correoelectrónico con el formato correcto, respectivamente.

Page 224: Desarrollo Web Con PHP y MySQL

9

Gestión de errores

Es curioso como, a veces, las tareas más importantesson relegadas a un segundo plano. Los programadorestendemos a pensar que, cuando logramos que unprograma se comporte de la forma esperada, nuestrotrabajo está hecho. Y, bueno, aunque es cierto, no lo es deltodo.

Un programa sólo puede darse por bueno cuando sucomportamiento es el adecuado, bajo cualquiercircunstancia. Concretando, en nuestro caso, las páginasPHP que hagamos deben devolver información de lasbases de datos: por ejemplo, una lista de registros.

Pero como hemos dicho, la página debe comportarseadecuadamente bajo cualquier circunstancia: cuando elservidor de bases de datos no esté funcionando debeavisar de ello, así como cuando la consulta que se estéintentando ejecutar no sea correcta tanto porque loselementos involucrados en ella no existan como porqueesté mal construida.

Las herramientas que proporciona PHP para la gestiónde errores son muchas y muy variadas. De igual forma,MySQL también proporciona medios para informar sobrelos errores que se produzcan y profundizar en las causasde los mismos.

Durante este capítulo verá cómo configurar PHP paraque su comportamiento frente a los errores sea el queusted desee. También verá cómo MySQL informa de loserrores que ocurren. Y aprenderá a utilizar de formaconjunta la gestión de errores de PHP y MySQL parasacarles el mayor partido.

Porque, a veces, el problema no está en que ocurra unerror en una de sus páginas sino en no saber tratarloadecuadamente.

PHP y los errores

Incluso antes de saber nada sobre la gestión de erroresde PHP ya nos estamos aprovechando de ella. ¿Recuerdacómo terminamos el capítulo 7? El comportamiento de lapágina que mostraba la lista de los géneros disponiblesfallaba miserablemente cuando el servidor de bases dedatos no estaba funcionando. Aquellos que intentasenconsultar el listado en ese momento se encontrarían conalgo parecido a lo que se puede ver en la figura 9.1.

Page 225: Desarrollo Web Con PHP y MySQL

Figura 9.1. No hay servidor de bases de datos

¿Qué determina la forma en la que se presentan estosmensajes de error? La configuración de PHP.

Configuración

Situémonos de nuevo en el capítulo 7. En su apartado7.6 explicábamos cómo modificar la configuración de PHPpara que pudiésemos conectar con el servidor de bases dedatos sin especificar ni su nombre, ni el nombre delusuario ni su contraseña, sólo indicando la base de datospredeterminada.

En ese capítulo consultábamos los parámetros deconfiguración de PHP con una página en la quellamábamos a la función phpinfo(). Vamos a repetir lajugada, pero ahora nos vamos a fijar en otros valores. Lafigura 9.2 muestra los valores que más nos interesan de lasección PHP Core de la configuración de PHP, tal y comonos la muestra la función antes mencionada.

Figura 9.2. Configuración para los errores

Como puede ver, existen tres columnas. La primera(Directive) es el nombre de la opción de configuración. Lasegunda (Local Value) es el valor de esa opción deconfiguración para la zona de la Web en la que seencuentra la página, mientras que la tercera (MasterValue) determina el valor global de esa opción, el que seaplica por defecto a todas las zonas de Web.

Nota: Recuerde del sépt imo capítulo que puede tener una configuración

Page 226: Desarrollo Web Con PHP y MySQL

diferente para algunas de las carpetas del servidor de páginas Web que ut ilice.Dependiendo de la ubicación de la página PHP dentro del árbol de directorios delservidor se aplicará una configuración u otra.

Son estos valores los que determinan cómo secomportarán nuestras aplicaciones en caso de que ocurraun error. Veamos para qué sirve cada uno de ellos.

display_errors

Dependiendo del valor de esta variable, los errores quese provoquen en nuestras páginas producirán mensajes ono. En la figura 9.2 se puede observar que estos mensajesestán activos, como pudo comprobar en la figura 9.1.

Veamos el impacto que desactivar esta opción tienesobre los mensajes de error. Suponga que está trabajandoen la ruta predeterminada de Apache, la carpeta htdocs.Cree una carpeta llamada errores dentro de esa carpeta y,dentro de ella, ponga un archivo PHP que llame a lafunción phpinfo().

Ahora vamos a editar el archivo de configuración deApache para que pueda modificar los valores deconfiguración de PHP de esa carpeta, como ya hicimos enel capítulo 7.

En concreto, deberá añadir las siguientes líneas alarchivo de configuración de Apache:

...

<Directory "C:/xampp/htdocs/errores">

Options Indexes FollowSymlinks

AllowOverride None

Order allow,deny

Allow from all

php_admin_value display_errors "0"

</Directory>

...

Nota: La ruta de la carpeta en el fragmento de configuración de Apache, como esobvio, se corresponde con un sistema Windows. Más detalles al respecto en elapartado 7.6.5.

Tras reiniciar el servidor Apache, si carga la página quemuestra las opciones de configuración de PHP podrácomprobar que ahora el valor local de display_errors esOff, como pretendíamos, algo que puede verse en la figura9.3.

Figura 9.3. Desact ivamos display_errors

¿Qué efecto tendrá este cambio en la página quepudimos ver en la figura 9.1? Si intenta cargarla cuando

Page 227: Desarrollo Web Con PHP y MySQL

MySQL esté detenido podrá ver algo similar a lo quemuestra la figura 9.4.

Figura 9.4. Controlamos los mensajes de error

La conclusión: durante el proceso de desarrollo, en elque esté probando el funcionamiento de sus páginas, estaopción de configuración debe estar activada, mientras quedurante su vida útil debe desactivarla y ser usted quiencontrole los mensajes de error.

Pero, ¡un momento! Aquí hay algo que no cuadra. ¿Cómoes que, si ha fallado la conexión, el mensaje de error quevemos es "Error en la consulta."? Algo no es del todocorrecto.

Si recuerda, el código de esta página era el siguiente:

<?php

$videoteca = new mysqli(

'localhost',

'usuario',

'clave',

'videoteca'

);

if ($videoteca->errno != 0){

echo('Error en la conexión.');

exit();

}

$resultado = $videoteca->query(

'SELECT * FROM genero'

);

if ($resultado == FALSE){

echo('Error en la consulta.');

}

while ($fila = $resultado->fetch_row()){

printf(

"(%u) %s - %s<br/>",

$fila[0], $fila[1], $fila[2]

);

print_r($resultado->fetch_field());

}

$resultado->close();

$videoteca->close();

Page 228: Desarrollo Web Con PHP y MySQL

?>

¿Por qué no se informa de un error en la conexión?Porque, al no llegar a realizarse, la instrucción new mysqlino ha logrado crear un ejemplar de la clase mysqli y, por lotanto, $videoteca->errno no contiene información algunadel código de error.

Lo correcto es utilizar una función para comprobar sihubo errores durante el proceso de conexión:

...

if (mysqli_connect_errno()){

echo('Error en la conexión.');

exit();

}

...

Si prueba a cargar esta página, ahora que hemosmodificado la comprobación de los errores de conexiónpodrá ver que sí obtiene la información correcta, comodemuestra la figura 9.5.

Figura 9.5. Ahora sí , error en la conexión

display_startup_errors

No sólo se producen errores al cargar una página. Esposible que, durante el proceso de carga de PHP enmemoria, se produzca algún error. Estos errores no seránvisibles a menos que el valor de esta opción deconfiguración sea On.

docref_ext y docref_root

Como hemos visto, cuando se produce un error al llamara una función PHP muestra un mensaje de error alrespecto sólo si la opción display_errors está activa.

En dicha página aparece, además, un enlace a ladocumentación de PHP donde se describe la forma deutilizar la función en la que se produjo el fallo. Vamos aprovocar un error. Con el servidor MySQL detenido ydisplay_errors activa, cree una página con el siguientecódigo y ábrala:

<?php

$videoteca = mysqli_connect();

?>

Page 229: Desarrollo Web Con PHP y MySQL

Y se produce un error como el que muestra la figura 9.6.El cuadro de diálogo que acompaña a la figura es elresultante de hacer clic con el botón derecho sobre elenlace y seleccionar la opción Propiedades del menúdesplegable que aparece. En él puede ver que dicho enlaceapunta al servidor local. Sin embargo, si hace clic sobreese enlace no encontrará ayuda alguna porque esa páginano existe.

Figura 9.6. Error en la conexión

Las opciones de configuración docref_ext y docref_rootpermiten modificar la forma en la que se crean estosenlaces. El primero de ellos determina la extensión de laspáginas a las que apuntan mientras que el segundo laubicación de las mismas.

Añadamos dos líneas a la configuración de la carpetaerrores en Apache:

...

php_admin_value docref_ext

".php"

php_admin_value docref_root

"http://php.net/manual/es/"

...

Reinicie el servidor Web y vuelva a cargar la página de lafigura 9.6. Ahora, el enlace será el que se puede ver en lafigura 9.7.

Page 230: Desarrollo Web Con PHP y MySQL

Figura 9.7. Enlaces a la documentación

Si hace clic sobre dicho enlace verá la documentación dela función mysqli_connect(), y en español.

Truco: Para aprovechar al máximo estas opciones de configuración es necesarioque disponga de conexión a Internet mientras t rabaja. De lo contrario no podráacceder a esta documentación. Si lo desea, puede instalar la documentación ensu propio servidor para poder consultarla en cualquier momento. Deberá modificarla configuración de PHP adecuadamente.

error_prepend_string y error_append_string

Asocie una cadena de texto a estas opciones deconfiguración. A partir de ese momento, dichas cadenasaparecerán antes y después del mensaje de error,respectivamente.

error_reporting

Quizás una de las más importantes de las opciones deconfiguración relacionadas con la gestión de errores.Contiene un valor numérico que determina el nivel dedetalle de los mensajes de error. Las posibles constantesque se pueden combinar para asignar un valor a estaopción de configuración son las siguientes:

E_ERROR: Errores fatales. Se detiene la ejecución delprograma.E_WARNING: Errores no fatales. No se detiene laejecución del programa.E_PARSE: En nuestro código hay algo que no siguelas reglas sintácticas de PHP.

Page 231: Desarrollo Web Con PHP y MySQL

E_NOTICE: Avisos sobre posibles fallos en nuestrocódigo.E_CORE_ERROR: Error fatal ocurrido durante la cargade PHP en memoria.E_CORE_WARNING: Error no fatal ocurrido durante lacarga de PHP en memoria.E_COMPILE_ERROR: Relacionado con Zend ScriptEngine, está fuera del alcance de este libro.E_COMPILE_WARNING: Relacionado con Zend ScriptEngine, está fuera del alcance de este libro.E_USER_ERROR: Error generado por el programadormediante el uso de la función trigger_error().E_USER_WARNING: Advertencia generada por elprogramador mediante el uso de la funcióntrigger_error().E_USER_NOTICE: Aviso generado por el programadormediante el uso de la función trigger_error().E_ALL: Todos los errores, salvo E_STRICT antes dela versión 5.4.0 de PHP. A partir de esa versión, E_ALLincluye a E_STRICT .E_STRICT: Consejos dados por PHP acerca de cómomejorar el código que escribimos.E_RECOVERABLE_ERROR: Error fatal que quizá nodejó en un estado inutilizable al motor de PHP.

Consejo: Por defecto, el valor de esta opción de configuración es E_ALL &~E_NOTICE. Le recomendamos que cambie ese valor por E_ALL & E_STRICT,con lo que PHP le ayudará en sus programas todo lo que pueda.

html_errors

Sólo si esta opción de configuración está activa podráver los mensajes de error con formato HTML, con enlacesa la documentación de PHP cuando sea necesario. Si estádesactivada, los mensajes de error tendrán el aspecto quepuede ver en la figura 9.8.

Figura 9.8. Formato HTML desact ivado

La dirección de la página de la documentacióndescribiendo la función en la que se produjo el error sigueestando ahí pero ya no como un enlace.

ignore_repeated_errors

Si activa esta opción y un mensaje de error se producede forma consecutiva en varias ocasiones en la mismapágina PHP no se informará de él más que la primera vez.

ignore_repeated_source

Page 232: Desarrollo Web Con PHP y MySQL

Si activa esta opción y un mensaje de error se producede forma consecutiva en varias ocasiones, sin importar sise produjo en la misma página o en otra, no se informaráde él más que la primera vez.

log_errors y error_log

Si log_errors está activo, podrá modificar el valor deerror_log. Este último le permite seleccionar un archivo enel que se guardará un registro de todos los errores que suspáginas PHP vayan mostrando.

Es imprescindible que indique un archivo de este tipouna vez sus aplicaciones estén en funcionamiento parapoder estudiar su comportamiento y localizar la causa deposibles errores.

Existe un valor especial para esta opción deconfiguración. Si en lugar de la ruta de acceso a un archivoindica el valor syslog, los mensajes de error se guardaránen el log del sistema, que en Windows es el registro deeventos (accesible a través del visor de eventos) y enLinux y Mac OS X es syslog.

log_errors_max_len

Tamaño máximo de los mensajes que se almacenará enel registro de errores. Si no se indica ningún valor no habrálímites de tamaño.

report_memleaks

Si en sus programas se produce algún problemarelacionado con la gestión de memoria y esta opción deconfiguración está activa, PHP informará de dichoproblema.

track_errors

Si esta opción de configuración está activa, siemprepodrá acceder en sus programas a la información delúltimo error que se produjo a través de la variable$php_errormsg. Esta variable sólo contiene la descripcióndel error.

Tras conocer las posibles opciones de configuraciónrelacionadas con la gestión de errores, veamos quéfunciones pone PHP a su disposición para gestionarlos.

Funciones

PHP es, posiblemente, uno de los lenguajes de su claseque proporciona las funciones de gestión de errores mássencillas y útiles. No son sólo las que vamos a ver, noscentraremos en las más importantes.

error_log()

Permite enviar un mensaje de error a cuatro destinosdiferentes: al sistema de registro de PHP (ver seccióndedicada a log_errors y error_log), a una dirección de

Page 233: Desarrollo Web Con PHP y MySQL

correo electrónico, a un depurador de errores remoto o a unarchivo (al final del cual se añade el mensaje).

Esta función acepta cuatro argumentos, en este orden: elmensaje de error, el tipo de destino (cualquiera de loscuatro antes mencionados), el destino propiamente dichoy, por último, información asociada al tipo de destino, encaso de que sea necesario.

Suponga que su aplicación está terminada, instalada yfuncionando en los sistemas de su cliente, aquel que leencargó su desarrollo. Se trata de una aplicación Web,continuamente conectada a Internet.

No se engañe: las aplicaciones pueden fallar, por cientosde razones diferentes. A veces, incluso no es por su culpa.

¿No sería fantástico que, cuando algún fallo ocurriera enlas aplicaciones que ha desarrollado, se le enviase unmensaje de error a su dirección de correo electrónico?Antes incluso de que el cliente le llamase por teléfonopara, indignado, decirle que lo que ha programado no sirvepara nada, usted tendría constancia de ello, ¡y por correoelectrónico!

Volvamos a nuestro ejemplo, la lista de géneros.Suponga que, efectivamente, no se ha podido estableceruna conexión con la base de datos. Suponga también que,en lugar del código que informa sobre el error en laconexión, tiene este otro:

...

if (mysqli_connect_errno()){

echo('Error en la conexión.');

error_log(

"No se pudo conectar con MySQL.",

1,

"[email protected]",

"Subject: Error en la videoteca\n".

"From: Servidor en producción\n"

);

exit();

}

...

Cada vez que se produzca un error al conectar con labase de datos le llegará un mensaje de correo electrónicoa la dirección [email protected], con el remitenteServidor en producción, para que sepa de qué servidor lellega el mensaje, y con el asunto describiendo qué es loque ha pasado.

Truco: Además de esta información, sería muy interesante incluir otra en elcuerpo del mensaje como, por ejemplo, las variables pasadas a la página, en casode que esta página se intentase cargar t ras enviar información con un formulario,o cualquier otro detalle que pueda ayudarle a resolver el problema que provocóque se le enviase el mensaje de correo electrónico.

Page 234: Desarrollo Web Con PHP y MySQL

error_reporting()

Esta función permite modificar en tiempo de ejecución,es decir, desde el mismo código de una página, el nivel dedetalle con el que se informará de los errores.

Utilizar esta función modifica el parámetro deconfiguración error_reporting, del que acabamos dehablar.

trigger_error()

Utilice esta función cuando ocurra alguna circunstanciaque PHP no entienda como error pero que usted desea quese trate como tal.

Por ejemplo, recuerde el capítulo anterior, la página PHPque le permitía dar de alta nuevos géneroscinematográficos. Cuando esta página no recibía elnombre del género o su descripción, mostraba un mensaje:

...

if($pParam != FALSE){

$sNombre = pParametros['nombre'];

$sDescripcion = pParametros['descripcion'];

if(

($sNombre == '') or

($sDescripcion == '')

){

$sMensaje =

'El nombre y la descripción '.

'del nuevo género no pueden '.

'ser cadenas vacías.';

echo($sMensaje);

}else{

...

Podríamos cambiar la llamada a la función echo() poruna llamada a la función trigger_error():...

$sMensaje =

'El nombre y la descripción '.

'del nuevo género no pueden '.

'ser cadenas vacías.';

trigger_error($sMensaje, E_USER_ERROR);

...

Page 235: Desarrollo Web Con PHP y MySQL

El resultado, en lugar de un simple mensaje, vieneadornado como un mensaje de error de los que yaconocemos, como puede ver en la figura 9.9.

Figura 9.9. Error definido por el usuario

Pero cuando quizá resulta más interesante informarsobre errores de este tipo es cuando definimos nuestraspropias funciones para gestionarlos.

set_error_handler()

¿No le gusta la información que PHP sobre los errores?No se preocupe, puede solucionarlo ya que existe laposibilidad de que cree su propia rutina de gestión errores.

La función de gestión de errores sólo tiene que ser capazde recibir cuatro parámetros que, en este orden,representan:

1. El código del error.2. La descripción del error.3. El archivo PHP en el que se produjo el error.4. La línea en la que se produjo el error.

Nota: Existe un quinto argumento que puede ut ilizarse en este t ipo de funcionespero su significado queda fuera del alcance de esta guía. Si desea másinformación al respecto consulte la documentación de PHP.

La siguiente es una versión minimalista de una funciónde gestión de errores:

function informar_error(

$codigo, $descripcion, $archivo, $linea

){

printf("Ha ocurrido un error.<br/>");

printf("<b>Código:</b> %s.<br/>", $codigo);

printf("<b>Descripción:</b> %s.<br/>",

$descripcion);

printf("<b>Archivo:</b> %s.<br/>",

$archivo);

printf("<b>Línea:</b> $s.<br/>", $linea);

error_log(

"Error.",

1,

"[email protected]",

Page 236: Desarrollo Web Con PHP y MySQL

"Subject: ".$descripcion."\n".

"From: Servidor en producción\n"

);

}

Si quiere que esta función informe sobre los errores queocurran en sus páginas sólo tiene que colocarla en unlugar al que todas ellas tengan acceso, utilizar lasinstrucciones de inclusión que vimos durante el capítulo 4y hacer la siguiente llamada al comienzo de la página:

...

$gestor_anterior =

set_error_handler("informar_error");

...

La variable $gestor_anterior contendrá lo necesariopara poder restaurar el anterior gestor de errores cuando loconsideremos oportuno utilizando la función que veremosa continuación, restore_error_handler.

La única ventaja que nuestra función aporta sobre lapredeterminada de PHP es que, además de informar sobreel error de forma diferente, se envía un mensaje de correoelectrónico con información al respecto: así que nosevitamos tener que añadir esa línea tras cada error que seproduzca. La figura 9.10 muestra el aspecto de losmensajes de error utilizando nuestra función.

Figura 9.10. Nosotros informamos del error

Nota: Por otra parte, el resultado de ut ilizar esta función para informar sobre loserrores es mucho más pobre, visualmente hablando. Queda como ejercicio para ellector mejorarla.

restore_error_handler()

Llamando a esta función restauramos la función degestión de errores que pasemos como parámetro. En elejemplo del apartado anterior se trataría de la variable$gestor_anterior.

Excepciones

La gestión de errores que hemos realizado hasta ahoraes la más utilizada, podríamos hasta decir que es la

Page 237: Desarrollo Web Con PHP y MySQL

clásica. Sin embargo, PHP ofrece la posibilidad degestionarlos utilizando excepciones, igual que muchosotros lenguajes modernos.

El primero paso para utilizar excepciones consiste enlocalizar aquellos fragmentos de código susceptibles defallo. Un buen candidato podría ser el momento de realizaruna consulta en una base de datos:

...

$resultado = $videoteca->query(

'SELECT * FROM genero'

);

...

Para controlar las excepciones que pudiesen tener lugarsólo es necesario incluir el código en cuestión en unbloque try:

...

try{

$resultado = $videoteca->query(

'SELECT * FROM genero'

);

}

...

La gestión de la posible excepción (es decir, del error)tiene lugar en el bloque catch definido a continuación delbloque try:

...

catch (Exception $e) {

echo 'Error: ' . $e->getMessage() . '<br/>';

}

...

Entre paréntesis, un objeto de tipo Exception quecontiene toda la información que necesite mostrar parainformar sobre el error como, por ejemplo, el código, lalínea o el archivo en el que tuvo lugar el error.

La principal ventana de utilizar bloques try y catch esque el código resultante está mucho más estructurado,más organizado, que si no se utilizasen.

MySQL y los errores

Cada vez que ejecuta una consulta cuya sintaxis no escorrecta o sobre unos datos inexistentes, el cliente deMySQL que utilice (como, por ejemplo, MySQL QueryBrowser o MySQLi) le informará sobre dichos errores. Pero¿qué podría hacer si le interesase conocer lo ocurrido haceunos días en un servidor de bases de datos MySQL? Paraesos casos, MySQL proporciona gran cantidad de datos en

Page 238: Desarrollo Web Con PHP y MySQL

sus archivos de registro (log en inglés).

Archivos de registro

Las capacidades de administración de MySQLAdministrator son suficientes si quiere saber qué estapasando en el servidor en un preciso instante, pero ¿y si leinteresa saber qué pasó hace unos días? Para esos casos,MySQL proporciona gran cantidad de datos en susarchivos de registro (log en inglés).

MySQL mantiene registros de su actividad en diferentesarchivos:

1. El registro de errores: Guarda información sobre loserrores aparecidos durante el proceso de arranque o deparada de MySQL, además de durante sufuncionamiento. También registra las paradas yarranques del servicio. Examinar este archivo puedeayudarle a determinar por qué el servidor no se poneen marcha.

2. El registro de consultas: O registro general. Todaslas conexiones que se establezcan con MySQL y lasposteriores consultas quedan registradas aquí.

3. El registro binario: Aquellas instrucciones querealicen algún cambio quedan registradas en estearchivo.

4. El registro lento: Almacena información sobreaquellas consultas que tardan mucho tiempo encompletarse, o aquellas que no utilizan índices.

Nota: Si t iene algún problema ut ilizando MySQL y necesita buscar ayuda sobre elmismo, examine los archivos de registro. A veces no bastará con la descripción delproblema, le hará falta incluir información que aparezca en estos archivos. Elbuscador de mensajes en los grupos de not icias ht tp://groups.google.com/ puedeserle út il.

Existen otros archivos de registro de los que no sehablará porque no le serán útiles por el momento. Puedeencontrar más información sobre ellos en ladocumentación de MySQL.

El registro de errores será el que más utilice cuandocomience a trabajar con MySQL, para localizar problemasen caso de que los tenga. La ubicación de este archivovariará, dependiendo de si el servidor está instalado enWindows, Linux o Mac OS X. Esta ruta dependerá de cómoy dónde haya instalado MySQL. Por lo general, se trataráde la carpeta data, dentro de la ruta de instalación deMySQL. El nombre del archivo se compone del nombre delordenador con la extensión err (linux.err si el nombre delequipo fuese linux), aunque también puede ser mysql.err.

La ubicación del archivo de registro de errores se puedecambiar si le pasa al servidor el siguiente parámetro alarrancar:

--log-error [= ruta]

Page 239: Desarrollo Web Con PHP y MySQL

Fíjese en que la ruta del archivo es opcional. Si pasa elparámetro sin ella estará indicando que quiere activar elregistro de errores pero deja la decisión del nombre delarchivo a MySQL.

La figura 9.11 muestra el contenido típico del archivo deregistro de errores de un servidor MySQL instalado en MacOS X.

Figura 9.11. Contenido del registro de errores

Cada línea del archivo de registro comienza con unnúmero de seis dígitos que representa la fecha con elformato AAMMDD (año, mes y día). A continuación la horaen la que se produjo en mensaje y, por último, el mensaje.

En cuanto al registro de consultas, puede seleccionar suubicación si, en el momento de arrancar, le pasa al servidorel parámetro:

--log [= ruta]

Este archivo de registro es especialmente útil si conocela existencia de algún problema, por ejemplo durante laconexión de algún programa con el servidor de bases dedatos, pero no dispone de suficiente información parasolucionarlo.

El tercer archivo de registro que puede resultarleinteresante es el binario. Éste se diferencia del resto enque no es posible su examen directo, con un editor detexto, al contrario que los dos anteriores.

Para activar este archivo de registro pase el siguienteparámetro al servidor durante el arranque:

--log-bin [= ruta]

Para examinar un archivo de registro binario debe haceruso de la utilidad mysqlbinlog.exe, que se encuentra en lacarpeta bin, dentro de la carpeta en la que MySQL estéinstalado. Para que le muestre el contenido de un archivode registro binario debe pasarle su ruta como argumento.

La figura 9.12 muestra el resultado de intentar leerdirectamente el contenido de un archivo de registro binario

Page 240: Desarrollo Web Con PHP y MySQL

recién creado, en lugar de leerlo utilizandomysqlbinlog.exe.

Figura 9.12. Archivo de registro binario

Si el número de operaciones realizadas en su servidor debases de datos es muy grande, el tamaño de los archivosde registro puede llegar a ser excesivo. Además desuponer un posible problema para el mismo servidor, quepuede quedarse sin espacio en disco, su tarea comoadministrador se verá dificultada: trabajar con archivosdemasiado extensos puede ser un problema.

Puede obligar a MySQL a crear nuevos archivos deregistro utilizando la siguiente instrucción, como siestuviese ejecutando instrucciones SQL:

FLUSH LOGS;

Los archivos de registro binario utilizan una extensióncompuesta de varios dígitos: mayor número, archivo másreciente.

Nota: Le recomendamos que realice esta operación de forma periódica y hagauna copia de seguridad de los archivos de registro, por lo que pueda pasar.

Archivos de registro en tablas

MySQL permite guardar las entradas del registro entablas, en lugar de en archivos. Se trata de algo muyinteresante por varias razones. Tras el repaso a losarchivos de registro que hicimos en el apartado anterior, lamás evidente salta a la vista: resulta mucho más sencillobuscar información en la tabla de una base de datos queen un archivo de texto. Los datos de cada línea del archivode registro se desgajan, yendo cada uno a una columna dela tabla correspondiente.

Ya dispone de dos tablas de registro en su servidorMySQL, dentro de la base de datos mysql: general_log yslow_log. Por defecto, estas tablas no se están utilizando,así que estarán vacías, como puede ver en la figura 9.13.

Figura 9.13. Tablas de registro, vacías

Page 241: Desarrollo Web Con PHP y MySQL

La tabla general_log se utiliza para guardar las entradasdel registro de consultas, o registro general. En la tablaslow_log se guardan las entradas del registro lento.

Antes de nada tenemos que saber dónde guarda MySQLlos datos de registro, en archivos o en tablas. Para elloejecute la siguiente consulta:

SHOW VARIABLES LIKE 'log_output';

La figura 9.14 muestra el resultado de realizar estaoperación en un servidor MySQL con la configuración pordefecto: la información de registro se guarda en archivos.

Figura 9.14. Registro en archivos

La opción de configuración log_output, que se pasacomo parámetro durante el arranque del servidor (--log-output), puede tomar tres valores: FILE, TABLE o NONE.Con el primero (--log-output=FILE) se utilizarán archivospara el registro, mientras que con el segundo se utilizarántablas. El tercero desactiva la generación de informaciónde registro. Si lo desea, esta información se puede guardarsimultáneamente en archivos y tablas utilizando elparámetro --log-output=FILE,TABLE.

Ahora bien, no es necesario reiniciar el servidor paraempezar a utilizar el registro en tablas, nos basta conutilizar la siguiente sentencia:

SET GLOBAL log_output='TABLE';

El valor de la opción de configuración cambiará y MySQLla tendrá en cuenta de inmediato. En la figura 9.15 puedever cómo hemos cambiado el valor de esta opción y laposterior consulta que demuestra que el cambio ha tenidolugar.

Figura 9.15. El registro, ahora en tablas

Aunque hayamos configurado MySQL para que guarde elregistro en tablas, recordemos que sólo dos de ellos se venafectados: el general y lento. Como vimos anteriormente,estos registros se activan a través de parámetros de iniciode MySQL. Pero, como ya sospecha, es posible activarlosutilizando la misma técnica que acaba de ver. Así quecomencemos comprobando si el registro general estáactivo:

Page 242: Desarrollo Web Con PHP y MySQL

SHOW VARIABLES LIKE 'general_log';

Si el valor de esta opción de configuración es OFFsignificará que está desactivado. Utilice la siguientesentencia para activarlo:

SET GLOBAL general_log='ON';

La figura 9.16 muestra el resultado de llevar a cabo estasdos operaciones.

Figura 9.16. Act ivación del registro general

A partir de este momento, con el registro en tablas activoy el registro general en funcionamiento, la tablageneral_log comenzará a recibir datos de MySQL. Paracomprobarlo, realice la siguiente consulta:

USE mysql;

SELECT * FROM general_log\G

El resultado, en la figura 9.17, muestra, precisamente,las consultas que hemos estado realizando: en la fila 7pedimos que se nos mostrase el valor de la variablegeneral_log, en la 8 seleccionamos la base de datos queaparece en la fila 9 (mysql) y, en la 10, realizamos laconsulta de los datos de la tabla en cuestión.

Figura 9.17. Contenido de la tabla de registro

Cada registro tiene 6 columnas:

event_time: ¿Cuándo tuvo lugar el evento registrado?

Page 243: Desarrollo Web Con PHP y MySQL

user_host: ¿Quién generó el evento en cuestión?thread_id: Identificador del subproceso.server_id: Identificador del servidor.command_type: Tipo de orden. Por ejemplo, unaconsulta (Query) o la selección de una base de datos(Init DB).argument: Parámetros pasados a la orden. En el casode una consulta será la consulta en sí.

Al guardar la información de registro en tablas resultasencillo obtener la lista de operaciones realizadas a lolargo de un día, o desde cierto equipo conocida su IP, o lalista de todas las consultas, por citar sólo algunosejemplos.

Una de las ventajas de mantener los registros en tablases que podemos guardar información de diferentesservidores en la misma ubicación. Configure los servidoresa su cargo para que guarden sus registros en las tablas deuno de ellos. Así sólo tendrá que consultar esa tabla,filtrando los registros por servidor.

Otra ventaja: podríamos utilizar desencadenadores paraque MySQL realizase ciertas tareas en caso de que seinsertasen ciertos valores en la tabla de registro.

Si se produce un error, ya sabe dónde encontrar ladescripción del mismo. ¿No le gustaría, además, poderentender esos mensajes de error, en caso de que no sepainglés?

Idioma de los errores

En este apartado describiremos la solución a unproblema que seguramente habrá notado desde quecomenzó a trabajar con MySQL: los mensajes de error noaparecen, por defecto, en español.

Puede comprobarlo si intenta conectarse con el servidorde MySQL proporcionando una contraseña incorrecta oejecutando una consulta de selección sin especificar unabase de datos, por ejemplo. La figura 9.18 es una buenamuestra de ello.

Figura 9.18. Mensaje de error en inglés

Para cambiarlo, sólo tiene que utilizar un parámetro en elarranque del servidor:

--language=spanish

Para pasar dicho parámetro durante el inicio del serviciodebe recordar lo aprendido durante el capítulo dedicado ala administración de MySQL. En concreto, la figura 9.19muestra el aspecto de las propiedades del servicio alincluir dicho parámetro.

Page 244: Desarrollo Web Con PHP y MySQL

Figura 9.19. Para obtener mensajes en español

Una vez reinicie el servicio podrá comprobar que losmensajes de error del servidor aparecen en español.Prueba de ello es la figura 9.20, en la que puede ver elresultado de ejecutar la misma consulta con la queobtuvimos el mensaje de error de la figura 9.18, unaconsulta de selección sin indicar sobre qué base de datos.

Figura 9.20. Mensaje de error en español

Como puede comprobar si compara la figura 9.18 con la9.20, independientemente del idioma en el que semuestren los mensajes de error el código es el mismo (eneste caso, el 1046). Gracias a ello le será más sencilloresponder a estos errores en sus programas de formasistemática en caso de que se produzcan.

MySQLi y los errores

La gestión de los errores en MySQLi sigue unas pautasmuy sencillas. Si está utilizando la versión orientada aobjetos de la misma, cada objeto con el que estétrabajando dispondrá de una pareja de propiedades que,en caso de error, expondrán el código del mismo y sudescripción. Se trata de errno y error, respectivamente.

Como ya sabe, existe una excepción a esta regla. En elcaso de que el error se produzca al intentar establecer unaconexión con un servidor de bases de datos, no podráutilizar las propiedades errno y error de la clase, puestoque no se habrá podido crear.

Para esta eventualidad dispone de otras dos funciones,mysqli_connect_errno() y mysqli_connect_error(), quedevuelven el código del error y su descripción,respectivamente.

Page 245: Desarrollo Web Con PHP y MySQL

respectivamente.

En caso de que esté trabajando con la versión funcionalde esta biblioteca, podrá utilizar las funcionesmysqli_errno() y mysqli_error(). Estas dos funcionesnecesitan una referencia a la variable con la que se realizóla operación que generó el error. Por ejemplo, un gestor deconexión, el valor obtenido tras establecer una conexióncon una base de datos de MySQL.

De cómo utilizar estas funciones poco podemos contar,puesto que ya las hemos utilizado en numerosasocasiones a lo largo del libro. Sin embargo, para sacar elmayor partido de ellas utilícelas conjuntamente con todaslas herramientas de gestión de errores que haya visto a lolargo de este capítulo.

Page 246: Desarrollo Web Con PHP y MySQL

10

Plantillas

Si la calidad de un lenguaje de programación tuviese quemedirse por la utilidad de las herramientas desarrolladascon él, la nota de PHP sería de las más altas.

Las aplicaciones que hemos desarrollado hasta ahora,por su sencillez, sólo dejaban entrever uno de losproblemas que entraña la programación con PHP: lamezcla de la lógica con la representación.

Suponga que está desarrollando una aplicación para unaempresa. En este proyecto, usted está al cargo de la partede la programación (lo que se conoce como la lógica de laaplicación) pero no del diseño de las páginas (larepresentación).

El proceso de unir las dos partes del trabajo no resultademasiado complejo: copiamos un poco de código PHP enuna página HTML, un bucle allá, unas variables acá, ycambiamos la extensión de las páginas HTML por PHP.

El verdadero problema viene cuando hemos de hacer uncambio, ya sea en la parte del diseño o en la parte de laprogramación. Por lo general, los diseñadores no tienennoción alguna sobre PHP, así que siguen trabajando consu diseño.

Somos nosotros los que tenemos que volver a modificarsus páginas HTML para incluir el código PHP en ellas, traslos cambios que hayan realizado. Así una y otra vez.

Aunque existen herramientas que le permiten localizardiferencias entre archivos y mezclar sólo aquellas partesque le interesen, tiene otra opción mucho más interesantey útil: las plantillas de Smarty.

¿Qué es Smarty?

Smarty es una capa más dentro de nuestra particulartorre de Babel. Hasta ahora hemos apilado un buenmontón de tecnologías: un servidor de bases de datosMySQL, un servidor de páginas Web, PHP, HTML yJavaScript. Como puede ver en la figura 10.1, Smartypodría situarse entre PHP y HTML.

Page 247: Desarrollo Web Con PHP y MySQL

Figura 10.1. ¿Dónde está Smarty?

La principal misión de Smarty es aislar la lógica de larepresentación de las páginas. El resultado: no hay códigoPHP en las páginas HTML, ni código HTML en las páginasPHP. Esto permite que el equipo de desarrollo puedatrabajar de forma independiente al equipo de diseño.

Lo mejor para entender lo que estamos diciendo es verloen funcionamiento.

Un pequeño ejemplo

Este ejemplo le mostrará de qué es capaz Smarty. Aúnno lo hemos instalado (lo haremos en el siguienteapartado), así que aún queda un poco para que puedaponer en funcionamiento lo que vamos a ver. Sin embargo,es interesante que sepa, antes de nada, lo que se puedeconseguir con Smarty.

Se trata de algo muy sencillo. De hecho, vamos aretomar el primer ejemplo que vimos en el capítulo 2, aquelque mostraba la hora. El código de esa página era elsiguiente:

La hora es: <?= date("H:i:s") ?>.

Una sola línea de código cuyo resultado variaba enfunción de la hora a la que la página se cargase. Elresultado de cargar esa página puede verse en la figura10.2.

Figura 10.2. ¿Qué hora es?

HTML y PHP entremezclados en la misma línea. Pocodiseño hay en esta página, pero podemos dejarlo libre decódigo PHP.

Con Smarty, tendríamos dos archivos: el PHP y unaplantilla con el diseño correspondiente, un archivo que, porlo general, tiene la extensión TPL (template, plantilla). Paranuestro ejemplo, podría ser el siguiente:

Page 248: Desarrollo Web Con PHP y MySQL

La hora es: {$hora}.

Si guardase ese archivo con el nombre smarty.tpl y lointentase cargar en un cliente Web podría ver algoparecido a lo que muestra la figura 10.3.

Figura 10.3. Plant illa sin aplicar

Un diseñador podría trabajar con este archivo,añadiendo lo que le plazca, con tal de que cumpla unacondición: incluir {$hora} donde deba ir la hora.

Y ahora, le toca al programador. El código de la páginaPHP sería el siguiente:

<?php

include('Smarty.class.php');

$smarty = new Smarty;

$smarty->assign('hora', date("H:i:s"));

$smarty->display('smarty.tpl');

?>

El primer requisito: tener acceso al archivoSmarty.class.php. En este archivo está la descripción de laclase Smarty, que utilizaremos para llevar a cabo la magia.

Sólo tiene que crear un ejemplar de dicha clase y utilizarel método assign() para crear la variable $hora que laplantilla utiliza para mostrar la hora. El método display()se encarga de localizar la ubicación de dicha variable en laplantilla y mostrar el resultado de la sustitución. Elresultado será idéntico al que vimos en la figura 10.2.

Seguro que está impaciente por empezar a utilizar estaherramienta en sus páginas. No es extraño. Además de laventaja que supone separar el diseño de la lógica en susprogramas, existen muchas otras.

Una de las más importantes es que podrá cambiar elaspecto de las páginas sin que cambie la lógica delprograma. Hablando claro: una vez tenga el programa querecupera la lista de géneros, podrá disponer de variosdiseños diferentes para la página únicamente cambiandoel nombre de la plantilla que quiera utilizar.

Instalación

El primer paso para instalar Smarty es descargarlo desdesu página Web:

Page 249: Desarrollo Web Con PHP y MySQL

http://smarty.net/

Localice la página de descarga en la Web de Smarty.Debido a la naturaleza de la Web, no es seguro que éstesea enlace del que descargar Smarty cuando lea estaslíneas pero, por si acaso:

http://smarty.net/download.php

Descargue la última versión estable. Por lo general, setrata de un archivo con la extensión tar.gz, aunquetambién está disponible una versión en formato zip.Herramientas como 7-Zip (http://7-zip.org/), tar y gunzip(disponibles casi con total seguridad en su distribución deLinux) o Stuffit (http://my.smithmicro.com/mac/stuffit/) leayudarán a extraer el contenido del archivo en una carpetatemporal.

Nota: Esto es para aquellos que ut ilicen Windows. La extensión tar.gz es muyfrecuente en sistemas Unix. La parte final, gz, indica que el archivo ha sidocomprimido con gzip, mientras que tar indica que se trata de un paquete dearchivos.

El contenido de esa carpeta temporal será otra con elnombre de la versión actual de Smarty dentro de la quepodrá ver una serie de archivos y carpetas, como en lafigura 10.4.

Figura 10.4. Los archivos de Smarty

El proceso de instalación es tan sencillo como colocaresta carpeta donde desee. En este caso vamos a copiarladentro de la carpeta en la que XAMPP se haya instalado.Esta ruta será diferente dependiendo del sistemaoperativo que utilice. Obviamente, si no utiliza XAMPPtendrá que guardar la carpeta de Smarty en otra ubicación.

Posteriormente, modifique la configuración de PHP paraque sepa dónde encontrar a Smarty. Existe una variable deconfiguración llamada include_path. Como ya sabe porcapítulos anteriores, estas opciones de configuraciónpueden incluirse en el archivo php.ini, para que esténdisponibles de forma global, o en Apache, limitando suámbito a una carpeta en particular.

Page 250: Desarrollo Web Con PHP y MySQL

Vamos a optar por la segunda opción. Como ya hicimosen el capítulo anterior y en el 7, vamos a crear una nuevacarpeta dentro de la predeterminada de Apache, la carpetahtdocs. El nombre de esta carpeta será plantillas.

Modifique entonces la configuración de Apache para quelas páginas PHP que estén en esa carpeta sepan dóndeencontrar a Smarty. Para ello, incluya una directivaphp_admin_value con la que asignar un valor a la opciónde configuración include_path. En esa variable debeincluir dos carpetas. La primera, aquella en la que hayainstalado Smarty. La segunda, la carpeta en la que vaya aponer las plantillas.

La configuración de Apache para la carpeta plantillaspodría ser algo así:

...

<Directory "C:/xampp/htdocs/plantillas">

Options Indexes FollowSymlinks

AllowOverride None

Order allow,deny

Allow from all

php_admin_value include_path \

"C:/xampp/smarty/libs;C:/xampp/htdocs/plantillas"

</Directory>

...

Al reiniciar Apache podrá ver las opciones deconfiguración de PHP en la carpeta plantillas utilizando lafunción phpinfo() dentro de un archivo PHP con uncontenido como éste, que ya vimos en anteriorescapítulos:

<?php

phpinfo();

?>

El valor de la variable include_path puede verse en lafigura 10.5.

Figura 10.5. La ruta de Smarty

Nota: En Windows, las rutas a incluir se separan con punto y coma (;). En el restode sistemas operat ivos, con dos puntos (:).

La prueba más sencilla para saber si Smarty estácorrectamente instalado es crear una página PHP dentrode la carpeta plantillas, que se encuentra en el interior dehtdocs, con el siguiente código:

<?php

require('Smarty.class.php');

Page 251: Desarrollo Web Con PHP y MySQL

require('Smarty.class.php');

$smarty = new Smarty;

?>

Si al cargar esta página no se produce ningún error, todoha ido bien. En caso contrario, lo más seguro es que PHPno haya sido capaz de encontrar los archivos necesarios.Revise la configuración y vuelva a cargar la página.

Una posible solución, si no localiza el problema, esindicar la ruta completa del archivo requerido:

<?php

require(

'C:/xampp/smarty/libs/Smarty.class.php'

);

$smarty = new Smarty;

?>

Y ahora que tiene Smarty en su sistema, vamos aretomar la página que muestra el listado de géneros.

Lista de géneros

En el capítulo 7 vimos cómo cargar la lista de génerosexistentes en nuestra base de datos. Tras lo visto en loscapítulos siguientes a ese, el código de dicha página es elsiguiente:

<?php

$videoteca = new mysqli(

'', '', '', 'videoteca');

if (mysqli_connect_errno() != 0){

echo('Error en la conexión.');

exit();

}

$resultado = $videoteca->query(

'SELECT * FROM genero'

);

if ($resultado == FALSE){

echo('Error en la consulta.');

}

while ($fila = $resultado->fetch_row()){

printf(

"(%u) %s - %s<br/>",

$fila[0], $fila[1], $fila[2]

);

Page 252: Desarrollo Web Con PHP y MySQL

);

}

$resultado->close();

$videoteca->close();

?>

Analice el código PHP anterior. Olvidando los mensajesque envíe en caso de error en la conexión o la consulta, elpunto que tendríamos que modificar para cambiar elaspecto de los datos mostrados será el bucle while,encargado de representar la información de los géneros.Es ahí donde tendremos que utilizar Smarty.

Guarde el código anterior en un archivo llamadogeneros.php, dentro de la carpeta plantillas que creóanteriormente. En esa misma carpeta necesitará otras dos:templates y templates_c. En la primera guarde losarchivos con la extensión TPL, la segunda es para usointerno de Smarty.

Vamos a comenzar haciendo algo sencillo: lograr que elaspecto de la página sea el mismo que tenía sin utilizarSmarty.

La plantilla

De golpe, no hay dolor, esta es la plantilla:

<html>

<head>

<title>Smarty - géneros</title>

</head>

<body>

{section name=i loop=$generos}

({$generos[i].id}) {$generos[i].nombre}

-

{$generos[i].descripcion}<br/>

{/section}

</body>

</html>

Debe guardarla en la carpeta templates, dentro de lacarpeta plantillas, con el nombre generos.tpl.

¿Y qué es lo que hace esta plantilla? Primero fíjese enlos elementos {section}. Gracias a ellos puede realizariteraciones.

Smarty permite definir secciones de código en las queiterar por algunas de las variables que pase a través delmétodo assign(). En este caso, el nombre de la variable es$generos. Se trata de una matriz que contendrá la lista degéneros disponible, y en cada iteración se referirá a cadaelemento de la matriz con el nombre i.

Page 253: Desarrollo Web Con PHP y MySQL

Dentro del bucle se accede al identificador del géneroasí:

$genero[i].id

El atributo loop de la sección determina sobre quévariable va a iterar, mientras que el atributo name le da elíndice del elemento actual.

Esto en cuanto a la plantilla pero, ¿cómo queda lapágina PHP?

La página PHP

El siguiente es el código PHP de la página que muestrala lista de géneros, pero utilizando Smarty para ello:

<?php

include('Smarty.class.php');

$videoteca = new mysqli(

'', '', '', 'videoteca');

if (mysqli_connect_errno() != 0) {

echo('Error en la conexión.');

exit();

}

$resultado = $videoteca->query(

'SELECT * FROM genero'

);

if ($resultado == FALSE){

echo('Error en la consulta.');

}

$generos = array();

while ($fila = $resultado->fetch_assoc()){

array_push($generos, $fila);

}

$resultado->close();

$videoteca->close();

$smarty = new Smarty;

$smarty->assign('generos', $generos);

$smarty->display('generos.tpl');

?>

Hasta que llegamos al bucle while, todo es más o menosigual que antes de utilizar Smarty, salvo por el uso de lainstrucción include. La primera diferencia la encontramosen este bucle, que en lugar de mostrar los detalles de cadagénero, se dedica a guardarlos todos en una matriz.

Page 254: Desarrollo Web Con PHP y MySQL

Tras este bucle, se cierra tanto el resultado de laconsulta como la conexión con la base de datos. Ahíempieza la diferencia.

Creamos un ejemplar de la clase Smarty, le pasamos lalista de géneros, que tenemos en una matriz y llamamos almétodo display() para que la magia tenga lugar. Elresultado es indistinguible del obtenido sin Smarty, comopuede verse en la figura 10.6.

Figura 10.6. Géneros, con Smarty

Pero sí que hay una importante diferencia. Veamos losencillo que resulta cambiar el aspecto de una página.

Otra plantilla

Haga un pequeño cambio en la página PHP que muestralos géneros utilizando Smarty. Va a recibir el nombre de laplantilla a través de la URL. Si no recibe ningún nombre seutilizará uno predeterminado. Entonces, pase ese nombrede plantilla al método display(). Algo así:

...

include('Smarty.class.php');

$plantilla = $_GET['plantilla'];

if($plantilla == ''){

$plantilla = 'generos.tpl';

}

$videoteca = new mysqli(

'', '', '', 'videoteca');

...

$smarty->display($plantilla);

...

Si carga la página tal y cual, como antes, todo seguiráfuncionando correctamente.

Ahora, vamos a crear una nueva plantilla, basada en laanterior. En lugar de mostrar la lista de géneros tal cual,como texto, lo hará dentro de una tabla.

Esta plantilla tendría el siguiente código:

<html>

Page 255: Desarrollo Web Con PHP y MySQL

<html>

<head>

<title>Smarty - géneros</title>

</head>

<body>

<table border="1">

<tr>

<th>Id</th>

<th>Nombre</th>

<th>Descripción</th>

</tr>

{section name=i loop=$generos}

<tr>

<td>{$generos[i].id}</td>

<td>{$generos[i].nombre}</td>

<td>{$generos[i].descripcion}</td>

</tr>

{/section}

</table>

</body>

</html>

Guarde esta plantilla con el nombre tabla.tpl dentro dela carpeta templates que creó anteriormente. La magiavuelve a ocurrir cuando carga la página pasando un valorpara el nombre de la plantilla, como puede verse en lafigura 10.7. Un mundo de posibilidades, abierto antenosotros.

Figura 10.7. Mismo PHP, varias plant illas

Page 256: Desarrollo Web Con PHP y MySQL

11

Procedimientos almacenados

La posibilidad de utilizar procedimientos almacenadosen MySQL es, quizá, una de las características másesperadas. La ausencia de los mismos en versionesanteriores a la 5 suponía una traba para el desarrollo dealgunas aplicaciones, razón por la que muchos decidíanutilizar otros sistemas gestores de bases de datos. Porfortuna, esto ha dejado de ser una excusa.

Los procedimientos almacenados facilitan la ejecuciónde conjuntos de instrucciones SQL, permitiendo agruparlosbajo un nombre común. Además, gracias a su empleo sepuede lograr cierto nivel de independencia entre la base dedatos y las aplicaciones que hacen uso de ella.

Este capítulo sirve como presentación de losprocedimientos almacenados. Para que pueda leerseindependientemente del resto del libro utilizaremos unsubconjunto de la base de datos de ejemplo desarrolladaen capítulos anteriores, aunque también podrá utilizar labase de datos completa, si lo desea.

Empezaremos creando una base de datos con una solatabla, que utilizaremos para probar el funcionamiento deun sencillo procedimiento almacenado de ejemplo. Lasintaxis será explicada en apartados posteriores. A partirde ese momento veremos procedimientos almacenadosmás complejos.

También veremos cómo crear funciones almacenadas,consideradas por muchos como una variedad deprocedimientos almacenados. Como comprobará, lasdiferencias existentes entre ambos no son demasiadas.

Introducción

A lo largo de los capítulos que preceden a éste ha podidocomprobar cómo evoluciona una base de datos, partiendode una sencilla idea que se va complicando a medida quese convierte en realidad.

Quizá algunos lectores de este libro hayan acudidodirectamente a los capítulos finales (como éste), en los quese tratan en detalle las más importantes características deMySQL. Aunque no es recomendable, para hacerlo posiblees necesario que dichos capítulos sean independientes, dealguna manera, del resto del libro.

Supondremos que el lector tiene ciertas nocionesbásicas tanto sobre el funcionamiento del servidor debases de datos MySQL como sobre las herramientasnecesarias para trabajar con él. Además, deberá conocer ellenguaje SQL.

Base de datos reducida

Page 257: Desarrollo Web Con PHP y MySQL

Seguramente ya esté familiarizado con la base de datosque hemos creado a lo largo de este libro. Puede ver undiagrama de la misma en la figura 11.1. En lo que a estecapítulo respecta, vamos a trabajar con una versión muyreducida de la misma. De hecho, la base de datos queutilizaremos sólo contendrá la tabla actor.

Figura 11.1. Diagrama de la videoteca

En la única tabla de esta base de datos insertaremos losmínimos registros necesarios para poder obtenerresultados interesantes con los procedimientosalmacenados que crearemos en este capítulo.

En los siguientes dos apartados crearemos la base dedatos de prueba e insertaremos algunos registros en suúnica tabla.

Creación

Para crear la base de datos con la que trabajaremos eneste capítulo sólo es necesario dar las siguientes órdenesa MySQL:

DROP DATABASE IF EXISTS videoteca;

CREATE DATABASE videoteca;

Advertencia: Tenga cuidado: si ya dispone de una base de datos con esenombre, las instrucciones anteriores la borrarán junto con su contenido.

Una vez disponga de la base de datos es necesario crearla tabla que contendrá los detalles de los actores. Lassiguientes instrucciones cumplen tal misión:

USE videoteca;

DROP TABLE IF EXISTS actor;

CREATE TABLE actor (

id INT NOT NULL AUTO_INCREMENT,

nombre VARCHAR(64) NOT NULL,

Page 258: Desarrollo Web Con PHP y MySQL

nombre VARCHAR(64) NOT NULL,

apellidos VARCHAR(64) NOT NULL,

imdb VARCHAR(32) NOT NULL DEFAULT '',

PRIMARY KEY(id)

) ENGINE = InnoDB;

La figura 11.2 muestra un diagrama de la tabla queacaba de crear. Está realizado con MySQL Workbench.

Figura 11.2. Subconjunto de la videoteca

Inserción

El último paso consiste en insertar algunos registros enla tabla actor de la base de datos que acabamos de crearpara poder trabajar con ellos. Utilice las siguientesinstrucciones:

USE videoteca;

INSERT INTO actor(nombre, apellidos, imdb)

VALUES('Harrison', 'Ford', 'nm0000148');

INSERT INTO actor(nombre, apellidos, imdb)

VALUES('Russell', 'Crowe', 'nm0000128');

Tras crear esta versión reducida de la base de datosdesarrollada durante los capítulos anteriores estamos endisposición de comenzar a trabajar con procedimientosalmacenados.

Un sencillo ejemplo

Una de las tareas más simples que se pueden realizarutilizando procedimientos almacenados es recuperarinformación. Por ejemplo, la lista de actores almacenadosen la tabla actor.

El siguiente código crea un procedimiento almacenadode tales características:

USE videoteca;

CREATE PROCEDURE pa_actores_lista()

SELECT

*

FROM

actor;

Fíjese en cómo está construido el nombre delprocedimiento almacenado. Como separador de palabrashemos utilizado el guión bajo (_), lo más parecido a unespacio que nos permiten las normas de MySQL para los

Page 259: Desarrollo Web Con PHP y MySQL

nombres. El nombre comienza con pa, las iniciales deprocedimiento almacenado. Así es posible diferenciarloclaramente de una tabla. El resto del nombre intentadefinir claramente la finalidad del procedimientoalmacenado. Se trata de una elección personal quedepende de las preferencias de cada uno.

Posteriormente nos centraremos en la sintaxisnecesaria para crear procedimientos almacenados. Yaconoce la misión de la primera línea del listado anterior:indicar la base de datos con la que queremos trabajar. Lasiguiente, que comienza con la instrucción CREATEPROCEDURE, le será desconocida, pero no así el resto.De hecho, se trata de una simple consulta de selección.

Lo que diferencia las instrucciones anteriores de unaconsulta de selección es, precisamente, la instrucciónCREATE PROCEDURE. Se podría decir que dicha línea leda al servidor de bases de datos la siguiente orden: "Ahorate voy a mostrar una serie de instrucciones SQL, guárdalascon el nombre pa_actores_lista porque luego las voy anecesitar".

Para crear el procedimiento almacenado, ejecute lasinstrucciones anteriores como si estuviese ejecutandocualquier otro conjunto de instrucciones. La figura 11.3muestra la respuesta que MySQL debería dar.

Figura 11.3. Creación del primer ejemplo

Ha llegado el momento de obtener los frutos del trabajorealizado hasta ahora. Ejecute el procedimientoalmacenado utilizando las siguientes instrucciones:

USE videoteca;

CALL pa_actores_lista();

La figura 11.4 muestra el resultado devuelto por elprocedimiento almacenado que acabamos de crear.

Figura 11.4. Lista de actores

Como puede comprobar si lo desea, ejecutar elprocedimiento almacenado devuelve el mismo resultado

Page 260: Desarrollo Web Con PHP y MySQL

que esta consulta:

USE videoteca;

SELECT

*

FROM

actor;

Entonces, ¿por qué utilizar procedimientosalmacenados? Aunque existen muchas otras ventajas,existe una muy obvia: quien ejecute este procedimientoalmacenado no necesita saber nada en absoluto sobre laestructura de la base de datos. Se podría decir que hemosdivido la base de datos en dos partes: una estructural yotra lógica.

La parte estructural estaría compuesta tanto por eldiseño de la base de datos como por los registrosalmacenados en las tablas. El conjunto de procedimientosalmacenados creados para recuperar información de esabase de datos sería la parte lógica.

¿Y por qué supone esta división una ventaja? Porqueofrece la posibilidad de trabajar con dos equipos. Supongaque esta base de datos va a ser el núcleo de un sitio Webdedicada al cine y que sus páginas estarán escritasusando el lenguaje PHP. Esas páginas serán el cliente dela base de datos. Como ya hemos visto, este lenguajedispone de las herramientas necesarias para comunicarsecon MySQL.

Así que podría existir un equipo dedicado almantenimiento de la base de datos, diseñando tablas,definiendo sus campos y creando los procedimientosalmacenados que devuelvan información a partir de losdatos contenidos en la base de datos.

Y, por otro lado, el equipo dedicado a la creación de laspáginas PHP. Para incorporar la información obtenida apartir de la base de datos, este equipo nunca utilizaríaconsultas, sólo procedimientos almacenados. Por lo tanto,no sería necesario que conociesen la estructura de la basede datos, sólo tendrían que llamar a un determinadoprocedimiento almacenado para obtener la lista de actores,otro les proporcionaría todos los detalles del mismo, untercero les mostraría la lista de películas protagonizadaspor dicho actor, y así para cada caso.

Nota: Esta independencia entre equipos t iene ventajas añadidas. Por ejemplo, laposibilidad de modificar el diseño de la base de datos sin por ello tener quemodificar las páginas PHP, siempre y cuando los procedimientos almacenadossigan devolviendo los mismos datos.

Sintaxis

Las posibilidades ofrecidas por el uso de losprocedimientos almacenados van mucho más allá de lovisto en el ejemplo anterior. Para poder sacarles todo su

Page 261: Desarrollo Web Con PHP y MySQL

visto en el ejemplo anterior. Para poder sacarles todo sujugo es necesario conocer cómo construirloscorrectamente, precisamente lo que veremos a partir deahora.

Creación

La sintaxis de la instrucción para la creación deprocedimientos almacenados en MySQL es la siguiente:

CREATE PROCEDURE nombre_pa

([parámetro, [...])

instrucciones

Tras las palabras reservadas CREATE PROCEDURE seincluye el nombre del procedimiento almacenado. Si fuesenecesario, puede recibir una serie de parámetros (más alrespecto en el apartado “Funciones almacenadas”, másadelante).

El procedimiento almacenado estará completo cuando seincluyan las instrucciones asociadas al mismo. La primeralínea que se puede ver en la definición de la sintaxis delprocedimiento almacenado se conoce como cabecera,mientras que la segunda es el cuerpo del procedimiento.

El siguiente ejemplo calcula y muestra el número deregistros de la tabla actor:

USE videoteca;

CREATE PROCEDURE pa_actores_cantidad()

SELECT

COUNT(*)

FROM

actor;

El resultado de ejecutar este procedimiento almacenadopuede verse en la figura 11.5.

Figura 11.5. Número de actores

Variables

Los datos no son etéreos y, en ocasiones, necesitaráalmacenarlos en algún lugar. Una variable es ese lugar. Enellas se guardarán aquellos valores que haya que consultaro modificar posteriormente.

El lenguaje SQL es un lenguaje de programación. En lajerga de los programadores, reservar el espacio necesariopara guardar dichos valores se conoce como declarar unavariable. Este espacio se encuentra en la memoria

Page 262: Desarrollo Web Con PHP y MySQL

principal del ordenador, es decir, en la RAM.

Para declarar una variable es necesario seguir lasiguiente sintaxis:

DECLARE nombre_variable[, ...] tipo

[DEFAULT valor_predeterminado]

La palabra reservada DECLARE va seguida del nombrede la variable que se quiera declarar. Incluya acontinuación el tipo de datos de dicha variable, es decir, lanaturaleza de los datos que contendrá.

Por ejemplo, la siguiente instrucción sirve para crear unavariable de tipo entero llamada actores:

...

DECLARE actores INT;

...

Consejo: Si quiere refrescar sus conocimientos sobre los t ipos de datos, acuda ala sección 6 del capítulo 3, “Tipos de datos”. En ella se hace un repaso de los másimportantes ofrecidos por MySQL.

Inicialmente, el valor almacenado en una variable esNULL. El primer paso consiste en asignar un valor inicial alas variables que cree, algo que se logra gracias a lapalabra reservada DEFAULT , que se incluye en la sintaxisde DECLARE.

Así, es posible declarar la variable actores para que suvalor inicial sea 0:

...

DECLARE actores INT DEFAULT 0;

...

Existen dos formas de asignar un valor a una variabletras su creación:

Directamente: Utilizando la palabra reservada SET .Así, podría asignarse el valor 0 a la variable trasdeclararla:

...

DECLARE actores INT;

SET actores = 0;

...

Tomando su valor de una consulta: Utilizando lapalabra INTO en una consulta de selección. Porejemplo, la siguiente consulta recupera el número deregistros en la tabla actor y guarda el valor en lavariable actores:

...

DECLARE actores INT;

SELECT

Page 263: Desarrollo Web Con PHP y MySQL

SELECT

COUNT(*)

INTO

actores

FROM

actor;

...

En lo que resta de capítulo podrá encontrar variosejemplos del uso de variables en procedimientosalmacenados.

El cuerpo de los procedimientos almacenados quehemos visto hasta ahora está compuesto de una solasentencia SQL. Sin embargo, es posible incluir tantasinstrucciones como sea necesario.

Delimitadores

Ya sabe que cuando se escribe una sentencia SQL esnecesario utilizar punto y coma (;) para indicar dóndeacaba. La sentencia de creación de un procedimientoalmacenado también es SQL y, como tal, necesita elempleo de dicho delimitador. Puede comprobar que los dosprocedimientos almacenados creados hasta ahoracumplen dicha norma.

Por otra parte, la misma norma ha de seguirse en elcuerpo del procedimiento almacenado si éste estácompuesto por más de una sentencia SQL, caso que hastaahora no se ha dado. Aparece aquí un problema: ¿cómodiferenciar entre el punto y coma que finaliza unasentencia perteneciente al cuerpo del procedimientoalmacenado y el que marca el final del mismo?

Por ejemplo, fíjese en esta versión del procedimientoalmacenado visto anteriormente, cuya misión era devolverel número de registros en la tabla actor:

USE videoteca;

CREATE PROCEDURE pa_actores_cantidad2()

BEGIN

DECLARE actores INT DEFAULT 0;

SELECT

COUNT(*)

INTO

actores

FROM

actor;

SELECT actores;

END;

En lugar de ejecutar directamente la consulta, se utilizauna variable en la que se almacena el resultado de laconsulta. A continuación, se devuelve dicho valor. Es laposibilidad de realizar las mismas tareas de diferentes

Page 264: Desarrollo Web Con PHP y MySQL

formas lo que hace tan interesante utilizar este tipo detecnologías.

Si intenta crear el procedimiento almacenado anteriorMySQL le mostrará varios mensajes de error, ya que no escapaz de diferenciar entre el punto y coma que terminauna sentencia SQL interior y el que termina elprocedimiento almacenado.

La solución a este conflicto es relativamente simple:definir un delimitador diferente para los procedimientosalmacenados. Para ello se utiliza la palabra claveDELIMITER, seguida de la secuencia de caracteresmarcará el final del procedimiento almacenado. Aunqueexiste la posibilidad de utilizar prácticamente cualquierdelimitador en la documentación de MySQL se utilizan dosbarras inclinadas (//).

El siguiente es el código del procedimiento almacenadoanterior, corregido para que sea correcto:

USE videoteca;

DELIMITER //

CREATE PROCEDURE pa_actores_cantidad2()

BEGIN

DECLARE actores INT;

SELECT

COUNT(*)

FROM

actor

INTO

actores;

SELECT actores;

END

//

DELIMITER ;

Antes de comenzar la creación del procedimientoalmacenado se declara el nuevo delimitador. Acontinuación, se crea el procedimiento almacenado y, trasla instrucción END, se utiliza el delimitador declaradoanteriormente. Para terminar, se deja todo como estaba,estableciendo como delimitador el punto y coma.

La figura 11.6 muestra la respuesta del cliente de MySQLal ejecutar las instrucciones de creación del procedimientoalmacenado y una posterior llamada al mismo.

Page 265: Desarrollo Web Con PHP y MySQL

Figura 11.6. Uso de delimitadores

Fíjese en la diferente respuesta obtenida al utilizar losprocedimientos almacenados que devuelven el número deregistros en la tabla actor. El primero de ellos, en la figura11.5, encabeza el resultado con COUNT(*). Efectivamente,el número mostrado bajo dicho texto es el resultado de esainstrucción.

Sin embargo, en la figura 11.6, el encabezado esactores, puesto que lo que se está seleccionando es elvalor de la variable así llamada.

Parámetros

Como pudo verse en la descripción de la sintaxis de losprocedimientos almacenados, existe la posibilidad dedeclarar una serie de parámetros asociados. A su vez, esnecesario describir la sintaxis de estos parámetros:

[ IN | OUT ] nombre_parámetro tipo

El significado de las palabras reservadas IN y OUT es elsiguiente:

IN: El parámetro es de entrada, es decir, se estápasando un valor desde la instrucción de llamada. Esevalor sólo se utilizará para proporcionar información alprocedimiento almacenado.OUT : Se trata de un parámetro de salida, es decir, paracomunicarse con el exterior, para informar de un valorobtenido al ejecutar el procedimiento almacenado.

Nota: Como ya sabe, los corchetes indican una opción, por lo que no esobligatorio incluir los valores IN o OUT. De forma predeterminada, si no se indicanada, el parámetro será de t ipo IN.

Como el movimiento se demuestra andando, nada mejorque un ejemplo sobre la utilización de cada tipo deparámetro para comprender su funcionamiento. En primerlugar, los parámetros de entrada, es decir, el tipo de

Page 266: Desarrollo Web Con PHP y MySQL

parámetro predeterminado. El siguiente código sirve paracrear un procedimiento almacenado que muestra la lista deactores cuyo nombre comienza con una determinada letra:

USE videoteca;

CREATE PROCEDURE pa_actores_buscar(letra CHAR(2))

SELECT

*

FROM

actor

WHERE

nombre LIKE letra;

Si quisiese localizar todos los actores cuyo nombrecomienza con la letra h debería ejecutar esteprocedimiento almacenado así:

CALL pa_actores_buscar('h%');

La figura 11.7 muestra el resultado de ejecutar estaconsulta.

Figura 11.7. Búsqueda de actores

Suponga que, además de la lista de actores, necesitaguardar en una variable de salida el número de actoreslocalizados. Es decir, ha de utilizarse una variable de tipoOUT :

USE videoteca;

DELIMITER //

CREATE PROCEDURE pa_actores_buscar2(

IN letra CHAR(2),

OUT actores INT

)

BEGIN

SELECT

*

FROM

actor

WHERE

nombre LIKE letra;

SELECT

COUNT(*)

INTO

Page 267: Desarrollo Web Con PHP y MySQL

actores

FROM

actor

WHERE

nombre LIKE letra;

END

//

DELIMITER ;

La llamada a este procedimiento almacenado es comosigue:

USE videoteca;

CALL pa_actores_buscar2('h%', @cantidad);

También se buscan aquellos actores cuyo nombrecomience con la letra h, como se indica en el primerparámetro. Sin embargo, fíjese en que el segundocomienza con el carácter @ (arroba), conocido por supresencia en las direcciones de correo electrónico.

Utilice este símbolo para crear variables de sesión, cuyaexistencia se limita al tiempo que permanezca conectadocon MySQL. Así, tras la llamada al procedimientoalmacenado de búsqueda es posible obtener el número deresultados obtenidos de la siguiente forma:

SELECT @cantidad;

En la figura 11.8 puede ver la respuesta de MySQL tantoa la llamada al procedimiento almacenado como al accesoal valor de @cantidad.

Figura 11.8. Valor de la variable de salida

Nota: Existe un tercer t ipo de parámetro, INOUT, que queda fuera de losobjet ivos de este capítulo. Para más información consulte la documentación deMySQL.

MySQL también dispone de lo que podríamos llamar unpariente muy cercano de los procedimientos almacenados(prácticamente un hermano): las funciones almacenadas.

Funciones almacenadas

La sintaxis de las funciones almacenadas es

Page 268: Desarrollo Web Con PHP y MySQL

prácticamente la misma que la de los procedimientosalmacenados:

CREATE FUNCTION nombre_fa ([parámetro, [...])

RETURNS tipo

instrucciones

A diferencia de los procedimientos, las funciones sólopueden utilizar un tipo de parámetros, los de entrada (IN).Al encabezado de la función se añade la palabra claveRETURNS seguida del tipo de datos del valor devuelto.

Las funciones almacenadas proporcionan una formadiferente de realizar una misma tarea. Considere estaversión modificada del procedimiento almacenado quemostraba el número de registros presentes en la tabla deactores:

USE videoteca;

DELIMITER //

CREATE FUNCTION fa_actores_cantidad()

RETURNS INT

BEGIN

DECLARE actores INT;

SELECT

COUNT(*)

INTO

actores

FROM

actor;

RETURN actores;

END

//

DELIMITER ;

Es posible utilizar las funciones dentro de consultasSQL, como puede ver en la siguiente:

USE videoteca;

SELECT fa_actores_cantidad();

El resultado de ejecutar la anterior consulta puede verseen la figura 11.9.

Figura 11.9. Función almacenada

Page 269: Desarrollo Web Con PHP y MySQL

Nota: Fí jese en que, a diferencia de los procedimientos almacenados, el prefijoseleccionado para los nombres de las funciones almacenadas es fa. De nuevo,una elección personal.

A pesar de las diferencias existentes entre losprocedimientos y las funciones almacenadas, en lossiguientes apartados nos referiremos a ambos comoprocedimientos almacenados. Así, cuando la definición dela sintaxis de una determinada operación incluya lapalabra reservada PROCEDURE, recuerde que debecambiarla por FUNCTION si va a trabajar con una funciónen lugar de con un procedimiento.

Eliminación

Es posible que, tras crear un procedimiento almacenado,se localice algún error en el código del mismo o se quieramodificar su funcionamiento. En esas ocasiones puedeeliminar el procedimiento almacenado utilizando ordenDROP. Para evitar un error en caso de que elprocedimiento almacenado no exista puede añadir laspalabras reservadas IF EXISTS. A continuación, vuelva acrear el procedimiento almacenado añadiendo lasmodificaciones que considere necesarias.

Por ejemplo, suponga que quiere cambiar elprocedimiento almacenado que devuelve la lista deactores, de manera que ahora el resultado se ordenealfabéticamente, primero por apellidos y luego por nombre.Deberá ejecutar las siguientes instrucciones:

USE videoteca;

DROP PROCEDURE IF EXISTS pa_actores_lista;

CREATE PROCEDURE pa_actores_lista()

SELECT

*

FROM

actor

ORDER BY

apellidos,

nombre;

Utilización desde PHP

La forma en la que puede utilizar procedimientosalmacenados en sus páginas PHP es prácticamenteidéntica a la que ya conoce para la ejecución de consultas.Vamos a aprovechar el procedimiento almacenado con elque terminó el apartado anterior para mostrar la lista deintérpretes de la base de datos. Éste es el códigonecesario:

<?php

Page 270: Desarrollo Web Con PHP y MySQL

$videoteca = new mysqli(

'localhost',

'root',

'',

'videoteca'

);

if ($videoteca->errno != 0) {

echo('Error en la conexión.');

exit();

}

$resultado = $videoteca->query(

'CALL pa_actores_lista()'

);

if ($resultado == FALSE){

echo('Error en la consulta.');

}

while ($fila = $resultado->fetch_row()){

printf(

"(%u) %s %s: %s<br/>",

$fila[0], $fila[1], $fila[2], $fila[3]

);

}

$resultado->close();

$videoteca->close();

?>

Como puede comprobar, sólo debe pasar la instrucciónCALL pa_actores_lista() al método query() y trabajar conel resultado como si de una consulta normal y corriente setratase. La figura 11.10 muestra el resultado del programaanterior.

Figura 11.10. Procedimientos almacenados y PHP

A lo largo de este capítulo hemos visto los conceptosbásicos necesarios para trabajar con procedimientosalmacenados. Gracias a ellos es posible agrupar variassentencias SQL bajo un mismo nombre, simplificando laejecución de tareas frecuentes como el acceso o lamodificación del contenido de las tablas de una base dedatos.

Page 271: Desarrollo Web Con PHP y MySQL

Ahora sabe cómo crear, modificar y eliminarprocedimientos almacenados. Obviamente, también cómoutilizarlos. Incluso ha visto, sin entrar en detalles, queestos procedimientos almacenados pueden utilizarsedesde lenguajes de programación como PHP.

Sin embargo, este capítulo es sólo el comienzo. Si deseaampliar sus conocimientos sobre procedimientosalmacenados, le recomendamos que visite la página de ladocumentación de MySQL dedicada a los mismos:

http://dev.mysql.com/doc/mysql/en/create-procedure.html

Quizá encuentre interesante el siguiente artículo,también publicado en la Web de MySQL:

http://dev.mysql.com/tech-resources/articles/mysql-storedprocedures.html

Page 272: Desarrollo Web Con PHP y MySQL

12

Desencadenadores

Este capítulo está dedicado a otra de las importantescaracterísticas de MySQL: los desencadenadores. Tambiénconocidos por su nombre en inglés (triggers), losdesencadenadores permiten realizar tareas de formaautomática cuando una determinada circunstancia tienelugar.

Se pueden crear desencadenadores que se activenantes o después de una inserción, una actualización o unborrado. Así, con los desencadenadores se puede verificarque los valores que se intenta insertar en una tablacumplen unas determinadas condiciones, deteniendo laoperación en caso de que se detecte alguna incongruencia.

También es posible asociar un desencadenador a unaoperación de actualización, de manera que unamodificación de los datos de una determinada tabla activede forma automática una actualización en otra tabla,manteniendo sincronizados los datos que se requieran.

Si lo desea, puede utilizar desencadenadores pararealizar borrados en cascada: el borrado de undeterminado registro en una tabla tiene comoconsecuencia el borrado de otros registros en otras tablas.

Como se reconoce en la documentación de MySQL, lascaracterísticas ofrecidas por los desencadenadores sonlimitadas, algo que no disminuye la utilidad de los mismos.El simple hecho de que sea posible utilizarlos deja preverque, poco a poco, las capacidades de losdesencadenadores irán aumentando.

Y sólo se han enumerado algunas de las posibilidadesque ofrece esta interesante característica de MySQL.

Introducción

Al igual que en el capítulo anterior, dedicado a losprocedimientos almacenados, este capítulo trata una delas más importantes características de MySQL. Por lotanto, es posible que muchos lectores tengan la tentaciónde leer estas páginas sin pasar por los capítulosanteriores.

Para facilitarles las cosas, este capítulo pretende ser lomás independiente del resto del libro que sea posible. Denuevo, supondremos que el lector tiene ciertas nocionesbásicas tanto sobre el funcionamiento del servidor debases de datos MySQL como de las herramientasnecesarias para trabajar con él. Además, deberá conocer ellenguaje SQL. Si no cumple alguno de estos requisitos lomás razonable es que lea este libro como debe, desde elprincipio.

Page 273: Desarrollo Web Con PHP y MySQL

Base de datos reducida

Durante este capítulo trabajaremos con una versiónreducida y ligeramente modificada de la base de datoscreada a lo largo de los capítulos anteriores de este libro.La sección homónima del capítulo anterior muestra másdetalles sobre la misma, le recomendamos que acuda aella si quiere saber más al respecto.

En lo que respecta a este capítulo, dicha base de datosestá compuesta por dos tablas. La primera de ellas,llamada actor, contiene un identificador numérico únicopara cada actor, su nombre y sus apellidos.

Aquí comienza un pequeño cambio. Anteriormente, estatabla también contenía un campo llamado imdb: elidentificador que IMDb (http://imdb.com/) asigna a cadaactor, para proporcionar una forma de acceder a lainformación de dicha Web desde los programas quedesarrolle.

Imagine que un nuevo diseñador de bases de datos, conmás experiencia, se ha hecho cargo de videoteca. Se tratade una persona con las ideas muy claras y ha encontradolo que cree que es una incongruencia en el diseño de latabla actor. A su modo de ver, esta tabla sólo debecontener datos sobre el actor y el campo imdb no estárelacionado con él, sino con una fuente de informaciónexterna.

Además, existe un nuevo requisito solicitado por laempresa que está pagando el desarrollo de la base dedatos: se debe crear un nuevo campo, compuesto por elnombre y los apellidos del actor, en minúsculas yseparados por un guión bajo (_). Por lo visto, quieren queese nombre se utilice en las direcciones Web de su propiapágina dedicada al cine: una por cada actor. Así, losdetalles de Harrison Ford estarían en la dirección:

http://www.example.com/harrison_ford/

Aviso: En esa dirección no va a encontrar nada relacionado con el cine, se t ratade un simple ejemplo. Sólo por si acaso.

El diseñador ha considerado que el nuevo campo y elcampo imdb tienen aspectos en común, así que hadecidido crear una nueva tabla en la que guardar ambos.Esta tabla estará relacionada con la tabla actor gracias alidentificador numérico. El nombre de la tabla seráactor_ext. Por lo visto ext viene de externo y hacereferencia a que los datos que la tabla contiene sonexternos al actor. La figura 12.1 muestra el aspecto de lasdos tablas que contendrán los datos de cada actor.

Page 274: Desarrollo Web Con PHP y MySQL

Figura 12.1. Diseño de la base de datos

Creación

A continuación veremos qué instrucciones sonnecesarias para crear tanto la base de datos reducidacomo las tablas que contiene. Además, insertaremosalgunos registros de ejemplo para que la base de datosdisponga de contenido con el que trabajar.

En primer lugar, es necesario crear la base de datos:

DROP DATABASE IF EXISTS videoteca;

CREATE DATABASE videoteca;

Advertencia: Sea cauto, si ha seguido los ejemplos de todo el libro ya tendráuna base de datos con ese nombre. Para conservarla sólo t iene que cambiar elnombre de la base de datos videoteca en las líneas anteriores por otro que seade su agrado y acordarse de seguir ut ilizándolo durante el resto del capítulo.

A continuación, cree las tablas de la base de datosutilizando las siguientes instrucciones:

USE videoteca;

CREATE TABLE actor (

id INT NOT NULL

AUTO_INCREMENT,

nombre VARCHAR(64) NOT NULL,

apellidos VARCHAR(64) NOT NULL,

PRIMARY KEY(id)

) ENGINE = InnoDB;

CREATE TABLE actor_ext (

idactor INT NOT NULL,

imdb VARCHAR(32) NOT NULL,

carpeta VARCHAR(255) NOT NULL,

PRIMARY KEY(idactor),

INDEX ae_FK(idactor),

FOREIGN KEY(idactor)

REFERENCES actor(id)

) ENGINE = InnoDB;

Inserción

Por último, inserte algunos valores en las tablas. En estecaso, como hay dos, será necesario realizar una inserciónpor cada tabla:

USE videoteca;

INSERT INTO actor(nombre, apellidos)

VALUES('Harrison', 'Ford');

INSERT INTO actor(nombre, apellidos)

VALUES('Russell', 'Crowe');

INSERT INTO actor_ext(idactor, imdb, carpeta)

Page 275: Desarrollo Web Con PHP y MySQL

INSERT INTO actor_ext(idactor, imdb, carpeta)

VALUES(1, 'nm0000148', 'harrison_ford');

INSERT INTO actor_ext(idactor, imdb, carpeta)

VALUES(2, 'nm0000128', 'russell_crowe');

Lógicamente, los valores necesarios para realizar lasinserciones en la tabla actor_ext han sido tomados de latabla actor. El valor de idactor es el del campo id de latabla actor tras guardar el registro. Al tratarse de un campode incremento automático no es posible conocer su antesde realizar la inserción.

Sintaxis

Siguiendo la costumbre, antes de los ejemplos veremosla sintaxis de las instrucciones relacionadas con losdesencadenadores.

Creación

Para crear desencadenadores es necesario seguir lasiguiente sintaxis:

CREATE TRIGGER nombre momento evento

ON tabla FOR EACH ROW instrucciones;

Las palabras que están en minúsculas son las quenecesitan explicación:

nombre: Es el nombre que recibe el desencadenador,aquel por el que nos referiremos a él cuando queramosutilizarlo.momento: Puede tomar los valores BEFORE (antes) oAFTER (después). Se utiliza para determinar si lasinstrucciones asociadas al desencadenador seejecutarán antes o después de la operación que loactivó.evento: Indique aquí el tipo de instrucción que activaráel desencadenador. Se puede tratar de INSERT ,UPDATE o DELETE.tabla: Nombre de la tabla con la que estará asociado eldesencadenador.instrucciones: Utilice BEGIN y END, como en losprocedimientos almacenados, si desea que eldesencadenador tenga asociada más de una orden.

Eliminación

Para eliminar un desencadenador debe seguir lasiguiente sintaxis:

DROP TRIGGER nombre;

Como es lógico, nombre se refiere al nombre deldesencadenador que desea eliminar.

Ejemplos

Page 276: Desarrollo Web Con PHP y MySQL

Por fin, tras no pocas páginas introductorias, nos vamosa poner manos a la obra. En los siguientes apartadoscomprobaremos lo útiles que pueden llegar a ser losdesencadenadores, tanto en las tareas de inserción yactualización como en las de borrado.

Inserción

¿Recuerda que, anteriormente, insertamos algunosregistros en la tabla actor? Después, para realizar lainserción de los registros correspondientes en la tablaactor_ext, fue necesario comprobar qué identificador seasignó al registro de cada actor para así mantener laintegridad referencial.

Ahora crearemos un desencadenador que,automáticamente, tras la inserción de un nuevo actor ensu tabla, creará el registro correspondiente en la tablaactor_ext, insertando el valor adecuado en el campocarpeta. En primer lugar hemos de seleccionar el nombredel desencadenador.

Pregúntese a qué tabla debe estar asociado eldesencadenador. Las instrucciones asociadas seejecutarán cuando se inserte un nuevo registro en la tablaactor. Incluya el nombre de esa tabla como parte delnombre del desencadenador. Ahora, ¿qué operación activael desencadenador? Una inserción. Incluya también elnombre de esa operación como parte del nombre deldesencadenador. Por último, para diferenciar undesencadenador de cualquier otro objeto de la base dedatos añadiremos el prefijo dc a su nombre.

Por lo tanto, podríamos llamar dc_actor_insertar a estedesencadenador. Obviamente, se trata de una de lasinfinitas posibilidades existentes; seleccione la que másapropiada considere. La única ventaja de este sistema esque permite diferenciar de un vistazo entre undesencadenador y otros objetos de la base de datos, asícomo saber qué tarea realiza.

Tras seleccionar el nombre del desencadenador y sabera qué tabla y operación está asociado debemos determinarsi las instrucciones asociadas al mismo se ejecutaránantes o después del evento que activó el desencadenador.En el caso que nos ocupa, es necesario conocer el valorque toma el identificador del actor recién insertado; por lotanto, las instrucciones deberán ejecutarse después,cuando dicho identificador ya exista.

El siguiente sería el encabezado del desencadenadorque estamos creando, a falta de las instruccionesasociadas:

...

CREATE TRIGGER dc_actor_insertar

AFTER INSERT ON actor

...

Sólo resta escribir las instrucciones asociadas al

Page 277: Desarrollo Web Con PHP y MySQL

desencadenador. En primer lugar, es necesario obtener elidentificador del actor recién insertado. Puede acceder atodos los valores de la operación que provocó la activacióndel desencadenador gracias al alias NEW. Por lo tanto, esposible acceder a dicho valor escribiendo NEW.id.

En segundo lugar, hay que concatenar el nombre y losapellidos del actor. De nuevo, es posible utilizar el aliasNEW para tal fin.

El cuerpo del desencadenador sería el siguiente:

...

DECLARE nuevo_carpeta VARCHAR(255);

SET nuevo_carpeta = CONCAT(

LOWER(NEW.nombre),

'_',

LOWER(NEW.apellidos)

);

INSERT INTO actor_ext(idactor, imdb, carpeta)

VALUES(NEW.id, '', nuevo_carpeta);

...

La declaración de la variable nuevo_carpeta es laprimera acción que lleva a cabo el desencadenador. En ellase almacenará el nombre de la carpeta asociada al actor,fruto de la concatenación del nombre y los apellidos, enminúsculas, con un guión bajo como separador.

La inserción se realiza utilizando dicha variable. Fíjeseen que, como no se dispone del identificador imdb, seinserta una cadena vacía en el campo correspondiente.

El código completo de este desencadenador es elsiguiente:

USE videoteca;

DELIMITER //

CREATE TRIGGER dc_actor_insertar

AFTER INSERT ON actor

FOR EACH ROW BEGIN

DECLARE nuevo_carpeta VARCHAR(255);

SET nuevo_carpeta = CONCAT(

LOWER(NEW.nombre),

'_',

LOWER(NEW.apellidos)

);

INSERT INTO actor_ext(idactor, imdb, carpeta)

VALUES(NEW.id, '', nuevo_carpeta);

END

Page 278: Desarrollo Web Con PHP y MySQL

//

DELIMITER ;

Nota: Más sobre variables y delimitadores en el capítulo 11, dedicado aprocedimientos almacenados.

Inserte ahora un nuevo actor en la tabla actor:

USE videoteca;

INSERT INTO actor(nombre, apellidos)

VALUES('Tim','Robins');

La figura 12.2 muestra el resultado de realizar lainserción de un nuevo actor en la tabla actor y unaposterior consulta a la tabla actor_ext.

Figura 12.2. Desencadenador en acción

Nota: Como ejercicio para el lector se deja la creación de un procedimientoalmacenado que reciba como parámetros el nombre y los apellidos del actor, asícomo su ident ificador imdb. Este procedimiento almacenado realizará la insercióndel nombre y el apellido en la tabla actor. Como consecuencia, el desencadenadorasociado creará el registro correspondiente en la tabla actor_ext . Sólo quedaríaactualizar esta últ ima tabla, insertando el ident ificador imdb donde corresponda.

Actualización

Como puede que ya haya notado, existía un error en elnombre del actor que se insertó en la sección anterior: suapellido se escribe Robbins y no Robins. Es un errorcometido a propósito para aprovechar las posibilidades delos desencadenadores en operaciones de actualización.

Suponga que se ha dado cuenta del error y lo intentasubsanar. Para ello, tendría que utilizar las siguientesinstrucciones (no lo haga todavía):

USE videoteca;

UPDATE

actor

SET

Page 279: Desarrollo Web Con PHP y MySQL

SET

apellidos = 'Robbins'

WHERE

id = 3;

Pero claro, esto sólo subsanaría el error en la tablaactor, no en actor_ext, así que sería necesario realizarotra actualización (tampoco la haga ahora):

USE videoteca;

UPDATE

actor_ext

SET

carpeta = 'tim_robbins'

WHERE

idactor = 3;

¿No sería mejor que esta segunda actualización serealizase de forma automática? A fin de cuentas, ya sabelas operaciones que debe realizar porque las utiliza en eldesencadenador de inserción.

El siguiente es el código del desencadenador asociadocon las actualizaciones de la tabla actor. Se han seguidolos mismos razonamientos que con el desencadenador deinserción para seleccionar su nombre:

USE videoteca;

DELIMITER //

CREATE TRIGGER dc_actor_actualizar

AFTER UPDATE ON actor

FOR EACH ROW BEGIN

DECLARE nuevo_carpeta VARCHAR(255);

SET nuevo_carpeta = CONCAT(

LOWER(NEW.nombre),

'_',

LOWER(NEW.apellidos)

);

UPDATE

actor_ext

SET

carpeta = nuevo_carpeta

WHERE

idactor = NEW.id;

END

//

DELIMITER ;

Ahora sí, realice la operación de modificación en la tablaactor. Podrá comprobar que, de forma automática, el valor

Page 280: Desarrollo Web Con PHP y MySQL

del campo carpeta de la tabla actor_ext ha cambiado y suvalor también es el correcto.

Borrado

Hasta ahora, todos los desencadenadores que hemosvisto se ejecutaban tras la acción que los activaba. Elejemplo que veremos en este apartado ejecuta lasinstrucciones asociadas antes, no después.

Supongamos que queremos eliminar a uno de losactores de la base de datos, por ejemplo, el que se insertóen el apartado anterior. Para eliminarlo es necesario borrartanto el registro asociado en la tabla actor_ext como el dela tabla actor. Pero, como ya sabe utilizardesencadenadores, puede que prefiera automatizar eltrabajo. Vamos a crear un desencadenador que se active alintentar un borrado en la tabla de actores y, antes derealizarlo, elimine el registro correspondiente en la tablaactor_ext.

¿Por qué antes y no después? Porque la tabla actor_exttiene un campo, idactor, que está relacionado con elcampo id de la tabla actor. No es posible eliminar elregistro de la tabla actor sin antes eliminar el asociado dela tabla actor_ext. Inténtelo si quiere:

USE videoteca;

DELETE FROM actor WHERE id = 3;

Obtendrá un error como el que se puede ver en la figura12.3.

Figura 12.3. Error al borrar

El siguiente es el código de un desencadenador que seactiva cuando se intenta eliminar un registro de la tablaactor:

USE videoteca;

DELIMITER //

CREATE TRIGGER dc_actor_eliminar

BEFORE DELETE ON actor

FOR EACH ROW BEGIN

DELETE FROM

actor_ext

WHERE

idactor = OLD.id;

END

Page 281: Desarrollo Web Con PHP y MySQL

//

DELIMITER ;

Puede acceder a los campos de la tabla a la que estáasociado el desencadenador mediante el alias OLD. Así, elidentificador del registro que se está intentado eliminar esOLD.id.

Tras crear el desencadenador podrá comprobar que laoperación de borrado ya no provoca error alguno.

En este capítulo ha aprendido a utilizardesencadenadores, una de las interesantes característicasde MySQL que le permitirá automatizar tareas tediosas,como inserciones dependientes de claves de incrementoautomático, actualizaciones y borrados.

Sin embargo, tenga cuidado. Utilizar desencadenadoresen exceso puede complicar las operaciones demantenimiento de la base de datos si su funcionamiento oexistencia no está completamente documentado.

Contrariamente a lo que se piensa, losdesencadenadores no ralentizan el funcionamiento globalde la base de datos. Lógicamente, añaden ciclos deproceso cuando están en funcionamiento pero, si lasoperaciones que realiza no los activan, su base de datosserá tan rápida como si no estuviesen presentes. Enresumen: sus operaciones de selección tendrán el mismorendimiento con y sin desencadenadores.

Page 282: Desarrollo Web Con PHP y MySQL

13

Vistas

Como su propio nombre deja al descubierto, las vistaspermiten modificar la forma en la que los datos sonpresentados. Se trata de una característica de MySQL que,dada su importancia, se presenta en su propio capítulo.

En los dos capítulos anteriores se presentaron losconceptos básicos necesarios para poder trabajar conprocedimientos almacenados y desencadenadores. Lasvistas le permitirán añadir una nueva capa a esas dos,aumentando el valor de su base de datos.

Dejando tecnicismos a un lado, se puede decir que lasvistas proporcionan control sobre los datos que desearecuperar y sobre la forma en la que los mismos sepresentan. Puede pensar en las vistas como en tablasficticias que toman sus datos de las tablas existentes.

En este capítulo aprenderemos la sintaxis necesariapara crear, modificar y eliminar vistas. Utilizando la basede datos de ejemplo que vimos en el capítulo anterior,dedicado a los desencadenadores, crearemos una vistaque permitirá simular que la tabla que contiene los datosde los actores no fue dividida en ningún momento. A todoslos efectos, el usuario no apreciará que haya habidocambio alguno en el diseño de la base de datos.

Cuando este capítulo termine tendrá en su poder elconocimiento necesario para utilizar tres de las técnicasmás interesantes que MySQL pone en su poder. Estará ensu mano sacar el máximo partido de ellas en su trabajo.

Introducción

Para trabajar en este capítulo aprovecharemos parte deltrabajo realizado en el anterior. Todo lo necesario paradisponer de una base de datos con la que poder hacerpruebas está en la sección 1 del capítulo 12.Refresquemos la memoria de aquellos que ya hayanpasado por él con la figura 13.1. En ella puede ver las dosúnicas tablas que componen la base de datos.

Figura 13.1. Base de datos de trabajo

Así pues, siga todos los pasos de dicho apartado si aúnno lo ha hecho. Cuando termine, vuelva aquí y continúeleyendo.

Sintaxis

Page 283: Desarrollo Web Con PHP y MySQL

Antes de comenzar a trabajar con vistas veremos lasintaxis de las diferentes operaciones que se puedenrealizar con ellas: creación, modificación y borrado.

Creación

Para crear vistas en sus bases de datos debe seguir lasiguiente sintaxis:

CREATE [OR REPLACE] VIEW nombre AS

consulta;

Entre corchetes, OR REPLACE. Si, al crear la vista,utiliza esas palabras reservadas y ya existe una con elmismo nombre, ésta será reemplazada con la nueva.Indique el nombre por el que desea referirse a la vista ennombre. El resto de la vista estará compuesto por unaconsulta de selección. En la sección 3 de este mismocapítulo veremos algunos ejemplos.

Modificación

Si desea realizar algún cambio en una vista ya existentetiene dos opciones: utilizar CREATE OR REPLACE VIEW(como acabamos de ver) o ALTER VIEW. La sintaxis deesta última es:

ALTER VIEW nombre AS

consulta;

Eliminación

Cuando no necesite seguir utilizando una determinadavista puede eliminarla utilizando DROP VIEW:

DROP VIEW [IF EXISTS] nombre;

Para evitar que el intento de borrado provoque un error sino existiese ninguna vista con ese nombre, incluya IFEXISTS. De esa forma, la instrucción de borrado sólo seejecutará si la vista existe.

Ejemplos

La base de datos con la que trabajaremos durante estecapítulo está compuesta por dos tablas. Como ya sabrá,son el resultado de dividir la tabla actor original, dejandoen una de ellas los datos pertenecientes al actor ymoviendo a la otra los datos externos al mismo: elidentificador de IMDb y el nombre de la carpeta de la Weben la que estará su página. Este último campo es de nuevaaparición y fue creado en el capítulo anterior.

Creación

Es posible que alguno de los usuarios de la base dedatos necesite obtener la misma información que antes dela división de la tabla actor. Como ya sabe, eso puedelograrse con la siguiente consulta:

Page 284: Desarrollo Web Con PHP y MySQL

USE videoteca;

SELECT

a.id,

a.nombre,

a.apellidos,

ae.imdb

FROM

actor a

JOIN actor_ext ae ON a.id = ae.idactor;

El resultado de ejecutar la consulta anterior puede verseen la figura 13.2.

Figura 13.2. Datos de actores

¿No le parece interesante poder ocultar a algunosusuarios los detalles de la estructura de la base de datos?Por ejemplo, a aquellos con menos conocimientos de SQL.Para estos usuarios podría crear una vista en la que losdatos de las tablas actor y actor_ext se combinasen,comportándose como una sola tabla.

Al igual que con los procedimientos almacenados y losdesencadenadores, utilizaremos un prefijo que permitadiferenciar las vistas del resto de objetos de la base dedatos. En este caso, dicho prefijo será v. El códigonecesario para crear dicha vista es el siguiente:

USE videoteca;

CREATE VIEW v_actor AS

SELECT

a.id,

a.nombre,

a.apellidos,

ae.imdb

FROM

actor a

JOIN actor_ext ae ON a.id = ae.idactor;

Las vistas se comportan a todos los efectos como sifuesen tablas. Por lo tanto, es posible realizar consultas deselección sobre ellas:

USE videoteca;

Page 285: Desarrollo Web Con PHP y MySQL

SELECT * FROM v_actor;

En la figura 13.3 puede ver el resultado de crear la vista yrealizar una consulta sobre ella.

Figura 13.3. Creación y uso de una vista

Nota: No es posible asignar a una vista el nombre de un objeto ya existente en labase de datos. Pruebe a ut ilizar el nombre actor en la vista que acaba de crear.MySQL le avisará de que ya existe una tabla con ese nombre, como puede ver enla figura 13.4.

Figura 13.4. Conflicto en el nombre

Modificación

Hasta tal punto las vistas se comportan como si detablas se tratase que es posible incluir modificadores,como los de ordenación, en las consultas que sobre ella serealicen. Por ejemplo:

USE videoteca;

SELECT

*

FROM

v_actor

ORDER BY

apellidos,

nombre;

Fíjese en el resultado de ejecutar esta consulta, que semuestra en la figura 13.5, y compárelo con el obtenido enla figura 13.2. Podrá comprobar que el orden en el que sedevuelven los registros ha cambiado.

Page 286: Desarrollo Web Con PHP y MySQL

Figura 13.5. Orden en las vistas

Pero también es posible modificar el orden en el que losregistros son devueltos, directamente, por la vista. Paraello, sólo hay que modificar la consulta. Como vimos en elapartado dedicado a la sintaxis de las operacionesrelacionadas con la gestión de las vistas, disponemos dedos opciones: CREATE OR REPLACE VIEW y ALTERVIEW.

El código necesario para modificar la vista utilizando laprimera de las opciones es el siguiente:

USE videoteca;

CREATE OR REPLACE VIEW v_actor AS

SELECT

a.id,

a.nombre,

a.apellidos,

ae.imdb

FROM

actor a

JOIN actor_ext ae ON a.id = ae.idactor

ORDER BY

apellidos,

nombre;

Aunque también puede obtener el mismo resultado conlas siguientes instrucciones:

USE videoteca;

ALTER VIEW v_actor AS

SELECT

a.id,

a.nombre,

a.apellidos,

ae.imdb

FROM

actor a

JOIN actor_ext ae ON a.id = ae.idactor

ORDER BY

apellidos,

nombre;

Page 287: Desarrollo Web Con PHP y MySQL

En la figura 13.6 puede comprobar que ahora la vistadevuelve los datos de los actores ordenados.

Figura 13.6. La vista ordena los datos

Eliminación

Cuando decida que no necesita una determinada vistapuede eliminarla utilizando la instrucción DROP VIEW. Porejemplo, las siguientes instrucciones eliminan la vistav_actor de la base de datos videoteca:

USE videoteca;

DROP VIEW v_actor;

La eliminación de una vista no supone la eliminación delas tablas de las que obtenía los datos.

Utilización desde PHP

La forma en la que puede utilizar vistas en sus páginasPHP es prácticamente idéntica a la que ya conoce para laejecución de consultas. Éste es el código necesario parautilizar la vista que devuelve la lista de intérpretesordenados por nombre que creamos en la sección anterior:

<?php

$videoteca = new mysqli(

'localhost',

'root',

'',

'videoteca'

);

if ($videoteca->errno != 0) {

echo('Error en la conexión.');

exit();

}

$resultado = $videoteca->query(

'CALL pa_actores_lista()'

);

if ($resultado == FALSE){

echo('Error en la consulta.');

}

Page 288: Desarrollo Web Con PHP y MySQL

while ($fila = $resultado->fetch_row()){

printf(

"(%u) %s %s: %s<br/>",

$fila[0], $fila[1], $fila[2], $fila[3]

);

}

$resultado->close();

$videoteca->close();

?>

Como puede comprobar, sólo debe pasar la instrucciónCALL pa_actores_lista() al método query() y trabajar conel resultado como si de una consulta normal y corriente setratase. La figura 13.7 muestra el resultado del programaanterior.

Figura 13.7. Vistas y PHP

Durante este capítulo ha aprendido a gestionar una delas características más interesantes de MySQL, las vistas.Gracias a ellas puede ocultar la verdadera estructura de labase de datos a algunos de los usuarios de la misma. Estopuede suponer una gran ventaja en aquellas ocasiones enlas que sea necesario modificar la distribución de loscampos dentro de las diferentes tablas. Si el usuario utilizalas vistas que se le proporcionan sólo será necesariocambiar la forma en la que la vista trabaja para seguirproporcionando al usuario lo que espera.

Sin embargo, el uso de vistas también presentainconvenientes. Entre ellos, la sobrecarga de trabajo que lagestión de las vistas puede suponer a los administradoresde la base de datos. Si, además, la base de datos tambiéntiene procedimientos almacenados y desencadenadores,debe tener especial cuidado en mantener completamentedocumentados todos los aspectos de la base de datos. Así,administradores y usuarios sabrán qué resultados puedenesperar de sus operaciones.

Page 289: Desarrollo Web Con PHP y MySQL

14

XML

De un tiempo a esta parte las siglas XML se han hechoomnipresentes en el ámbito de la informática. Como antescon muchos otros estándares, su adopción se anunciacomo la solución de los problemas a los que se enfrentan adiario los profesionales del mundo de la informática. Estássiglas, que tanto han dado que hablar, proceden del ingléseXtensible Markup Language (lenguaje extensible demarcas).

La pareja formada por las aplicaciones Web(desarrolladas con MySQL y PHP) y XML resultaespecialmente interesante. Por una parte, hace más fácilla posibilidad de que en la base de datos sólo haya datospuros, sin formato, cuya apariencia pueda ser modificadaposteriormente. Por otra, permite almacenar en brutograndes cantidades de datos en un único campo y, luego,extraer o modificar únicamente un fragmento.

MySQL nos ofrece dos formas de combinar datos y XML.En primer lugar, utilizando herramientas como mysql omysqldump. En segundo lugar, mediante dos funcionesque permiten manipular cadenas de texto con formato XMLque se encuentren almacenadas en algún campo. Aunquedista mucho de ser el soporte completo que a todos nosgustaría tener, sí que se trata de un punto de partida. Porsu parte, PHP dispone de multitud de herramientas paratratar con XML.

En este capítulo encontrará una introducción al formatoXML. Veremos cómo obtener valores en formato XMLdesde la línea de órdenes, aprenderemos trabajardirectamente con XML, desde consultas SQL y, por último,utilizaremos PHP junto con XML.

¿Qué es XML?

Al hablar de XML y MySQL nos debatimos entre lasencillez de unas siglas y la panacea universal.

Ni una cosa ni otra: no son sólo unas siglas, y lo que esseguro es que, por sí sola, la utilización de XML conMySQL y PHP no resolverá todos nuestros problemas.Aunque también es seguro que hará más sencilloencontrar soluciones a los mismos.

Pero, ¿qué aspecto tiene un documento XML? Enrealidad, no se trata de nada extraño, son sencilloscaracteres de texto puestos uno tras otro. El siguientecontiene detalles sobre el reparto de Blade Runner:

<?xml version="1.0"?>

<reparto>

<papel protagonista="si">

<personaje>Rick Deckard</personaje>

Page 290: Desarrollo Web Con PHP y MySQL

<actor>Harrison Ford</actor>

</papel>

<papel protagonista="no">

<personaje>Roy Batty</personaje>

<actor>Rutger Hauer</actor>

</papel>

<papel protagonista="no">

<personaje>Rachael</personaje>

<actor>Sean Young</actor>

</papel>

</reparto>

Si conoce HTML seguro que encuentra similitudes. Lafigura 14.1 muestra cómo se ve el anterior documento XMLen un cliente Web. Es interesante comprobar que, desde elprincipio, aplicaciones que pensábamos que tenían unaúnica misión (visitar páginas Web, en este caso) estánlistas para desempeñar muchas otras funciones. Aunque,si lo piensa un poco, tampoco es tan sorprendente: XMLestá pensado con Internet como uno de sus objetivos.

Figura 14.1. XML en un cliente Web

Lo que sí queda claro es que, aunque los que mejor van aentender XML son las máquinas y los procesos, dada sunaturaleza estructurada, nosotros también somos capacesde sacar conclusiones a partir de un documento XML, deun vistazo.

Todo lenguaje tiene unas reglas más o menos estrictasque deben ser cumplidas para que pueda ser entendido. Enel caso de XML, esto es aún más cierto. XML es unlenguaje en el que prima la sencillez y la portabilidad.Mientras más estricto sea, más fácil será crear programascapaces de leerlo de forma eficaz.

Parafraseando a Jack el destripador, vayamos porpartes.

Partes de un documento XML

Antes de describir con más detalle cada parte de undocumento XML recordemos que es un lenguaje de

Page 291: Desarrollo Web Con PHP y MySQL

marcas, pensado para la descripción de datos. En él, lasmarcas están delimitadas por los símbolos "menor que" (<)y "mayor que" (>). Todo lo que se encuentre entre esos dossímbolos es una marca o etiqueta. Por ejemplo,<personaje> y <actor> son etiquetas.

Dicho lo cual, un documento XML puede presentar trespartes diferentes: el prólogo, el cuerpo y el epílogo.

Prólogo

Todo documento XML debe comenzar con un prólogoque se encargue de presentar el tipo del documento, laversión de la norma a la que se adhiere y muchas otrascaracterísticas. En el ejemplo que nos ocupa el prólogo esel siguiente:

<?xml version="1.0"?>

La etiqueta de esta línea está compuesta de formadiferente al resto de las que aparecen en el documento: enlugar de estar entre los símbolos "menor que" (<) y "mayorque" (>), a éstos se añade un símbolo de cierre deinterrogación, lo que resulta en (<?) y (?>). Eso quiere decirque se trata de una instrucción que contiene informaciónsobre el documento, lo que se conoce como instrucción deproceso.

A continuación del prólogo nos encontramos con elcontenido del documento.

Cuerpo

Los datos que un documento XML nos ofrece están en loque se conoce como cuerpo. En el caso de nuestroejemplo, se trataría de todo lo que está entre <reparto> y</reparto>, incluidas estas dos etiquetas. Este elementose conoce como la raíz del documento.

Epílogo

Situado a continuación del cuerpo del documento, puedeestar compuesto de instrucciones de proceso como las delprólogo, a excepción de declaraciones XML o de tipo dedocumento.

Etiquetas

Para diferenciar entre los distintos elementos quecomponen un documento XML hemos de utilizar etiquetas.Las etiquetas están compuestas por un nombre y unosatributos, debe existir una de apertura y otra de cierre ydeben estar correctamente situadas.

Nombres

Es más que recomendable ceñirse a un determinadopatrón al dar nombre a las etiquetas: todo minúsculas,todo mayúsculas, o una combinación de ambas, perosiempre con el mismo patrón. Seguir esta recomendaciónle evitará muchos quebraderos de cabeza en el futuro.

Page 292: Desarrollo Web Con PHP y MySQL

Cada etiqueta de apertura debe tener una decorrespondiente de cierre. Por ejemplo:

<actor>Harrison Ford</actor>

Las etiquetas de cierre son como las de apertura, perocon una barra inclinada antes del nombre de la misma.Obviamente, los nombres de las etiquetas de apertura ycierre deben coincidir.

Atributos

Las etiquetas pueden aprovecharse para incluir otrosdatos, utilizando atributos. Si conoce HTML ya habrátenido su primer contacto con los atributos. Por ejemplo, laetiqueta HTML para crear un enlace a otra página podríaser la siguiente:

...

<A HREF=http://enreas.com/mysql>

Guía de MySQL

</A>

...

En este caso, la etiqueta A se refiere a un enlace yHREF es un atributo. Los atributos serían las propiedadesque tiene ese elemento: ese enlace lleva a unadeterminada dirección que se indica en el atributo A.

El caso de XML no es diferente: la etiqueta denota elnombre del elemento, y el atributo, sus propiedades. Losatributos sólo pueden indicarse en las etiquetas deapertura, no en las de cierre.

Un atributo está formado por el nombre del mismo y elvalor que toma, separados ambos por un signo de igualdad(=). El valor del atributo debe estar obligatoriamente entrecomillas. Estas comillas pueden ser simples o dobles, perosi la apertura de comillas es simple, el cierre también debeserlo, e igual si son dobles.

Uniendo etiquetas, atributos y valores, ¿qué tenemos?

Nodos

Un nodo está compuesto por una etiqueta, sus atributosy su contenido. El contenido es todo lo que está entre laetiqueta de apertura y la de cierre, lo que puede incluir aotros nodos.

Si en el contenido de un nodo hay otros nodos, nosreferiremos a ellos como nodos descendientes. En elprimer nivel de descendencia están los nodos hijos. Siestos nodos tienen a su vez otros nodos en su interior,serán hijos del inmediatamente anterior, y nietos del otro.

Esta estructura de padres e hijos también es conocidacomo estructura arbórea o jerarquía. La jerarquía ennuestro ejemplo está muy clara: el primer nodo del árbol es<reparto>. Este nodo tiene como descendientes nodos<papel> que, a su vez, tienen como descendientes a losnodos <personaje> y <actor>.

Page 293: Desarrollo Web Con PHP y MySQL

Con esta breve introducción ya estamos listos paratrabajar con XML.

XML desde la línea de órdenes

La forma más sencilla de que el resultado de nuestrasconsultas SQL esté en formato XML es utilizar lasherramientas para la línea de órdenes como, por ejemplo,mysql, de la que tanto partido hemos sacado durante estelibro. Sólo tenemos que añadir un parámetro más, xml. Así,por ejemplo, para iniciar una sesión con el usuario rootutilizaríamos la siguiente orden:

mysql -u root -p --xml

Cuando introduzca la contraseña le parecerá que nadaha cambiado, pero basta con que realice una consulta paradarse cuenta de que no es así. Por ejemplo, vamos aseleccionar todos los soportes guardados en la base dedatos:

USE videoteca;

SELECT * FROM soporte;

La figura 14.2 muestra el resultado de ejecutar estaconsulta tras utilizar ese parámetro.

Figura 14.2. Resultado de una consulta en XML

En el documento XML obtenido podemos examinar losdiferentes elementos que describimos al principio delcapítulo: hay un prólogo y un cuerpo, pero no hay epílogo.Dentro del cuerpo podemos ver el nodo raíz, resultset(conjunto de resultados, en inglés.). El valor de uno de susatributos, statement, es la consulta que dio comoresultado el documento XML que estamos examinando.

Los descendientes de resulset son nodos row, uno porfila obtenida como resultado de la consulta. A su vez, losdescendientes de este nodo son nodos field, uno por cadacampo solicitado en la consulta. En este caso son todoslos campos de cada fila de la tabla soporte. El atributoname contiene el nombre del atributo. El valor de cadacampo se encuentra entre las etiquetas de apertura y

Page 294: Desarrollo Web Con PHP y MySQL

cierre de los nodos field.

El documento XML obtenido responde fielmente a lascaracterísticas de la consulta SQL realizada. Por ejemplo,supongamos que no nos interesan ni los identificadores nilas siglas. La figura 14.3 muestra el resultado de ejecutaresta consulta:

USE videoteca;

SELECT nombre FROM soporte;

Figura 14.3. Consulta SQL con un único campo

Como puede comprobar, ahora cada elemento row sólotiene un descendiente, un elemento field correspondientecon el campo nombre.

El documento XML también puede modificarse desde laconsulta SQL para que el valor del atributo name sea elque queramos. Por ejemplo, gracias a esta consulta suvalor será soporte en lugar de nombre:

USE videoteca;

SELECT nombre AS soporte FROM soporte;

Puede ver el resultado en la figura 14.4.

Figura 14.4. Cambio en el nombre del campo

Obtener el resultado en formato XML es muyinteresante, pero quizá lo fuese más si pudiésemosguardarlo en un archivo para poder utilizarlo desde otrasaplicaciones. Sí, puede copiar el resultado obtenido ypegarlo en un editor de textos, pero también puedeejecutar esta orden:

mysql -u root -p --xml

-e "SELECT * FROM soporte" videoteca

> soportes.xml

Page 295: Desarrollo Web Con PHP y MySQL

Tras el parámetro xml aparece el parámetro e, quenecesita el texto de la consulta a realizar (la de selecciónde soportes, en este caso). A continuación, indicamos elnombre de la base de datos con la que queremos trabajary, por último, redirigimos el resultado a un archivo. En lafigura 14.5 puede ver el archivo resultante, abierto conInternet Explorer.

Figura 14.5. Resultado XML en Internet Explorer

Ya sabemos cómo obtener el resultado de nuestrasconsultas en formato XML. A continuación veremos que esposible guardar documentos XML en los campos de unatabla, así como extraer valores de ellos y modificarlos.

Funciones XML

MySQL proporciona dos funciones para trabajar condocumentos XML: ExtractValue y UpdateXML. Enrealidad, siendo precisos, estas dos funciones trabajan confragmentos de cadenas en formato XML, ya que noincluiremos el prólogo.

Pero, ¿de qué puede servir guardar fragmentos dedocumentos XML en los campos de una tabla? Volvamos ala base de datos de ejemplo que hemos utilizado en estaguía y supongamos que queremos almacenar nuevosdatos en ella. En este caso, el reparto de cada película.¿Dónde encajaría dentro del modelo que puede ver en lafigura 14.6?

Page 296: Desarrollo Web Con PHP y MySQL

Figura 14.6. La base de datos de la videoteca

Podríamos añadir una pareja de campos nuevos:reparto_personaje y reparto_actor. No parecedemasiado lógico, ¿verdad? Sólo podríamos almacenaruno de los personajes del reparto. Si añadiésemos másparejas reparto_personaje y reparto_actor, con unnúmero al final para diferenciarlas, podríamos tener tantascomo quisiésemos. Pero eso no soluciona otro problema:estamos añadiendo datos duplicados. A fin de cuentas,tenemos una tabla para los actores.

Está claro que se trata de información relacionada concada película, pero también con cada actor. Deberíamoscrear una tabla de personajes relacionada con la tabla deactores y con la de películas. Estas relaciones deberían sermuchos a muchos: un mismo personaje puede aparecer envarias películas (como Peter Parker en la serie de películasde Spiderman) y, además, un mismo actor puedeinterpretar varios personajes en la misma película (en estecaso, Tobey Maguire se encarga tanto de Peter Parkercomo de Spiderman).

¿Merece la pena que añadamos la tabla de personajes ylas dos tablas auxiliares necesarias para mantener laintegridad referencial de las relaciones correspondientes?En la figura 14.7 puede ver el reparto de la primera parte deSpiderman. Fíjese en que se trata sólo de parte de ella, sihace clic en el enlace more (el puntero del ratón seencuentra sobre él) podrá ver el reparto completo de estapelícula.

Page 297: Desarrollo Web Con PHP y MySQL

Figura 14.7. Reparto de Spiderman

Supongamos que no nos interesa para nada mantener latabla de personajes, sólo queremos disponer del repartocomo simple referencia. Tampoco queremos que el repartomantenga relación con la tabla de actores. En definitiva,sólo necesitamos guardar una lista.

Las funciones ExtractValue y UpdateXML nospermitirán hacer esto, precisamente. Aunque se trata sólode una de las múltiples aplicaciones que se le pueden dar.Pero antes de ver estas dos funciones hablemos unpoquito de XPath.

XPath

La clave de utilizar XML es doble: guardar y extraer.Primero, hay que saber cómo almacenar los datos, y debehacerse de forma homogénea. Segundo, hay que saberextraer información a partir de los datos. XPath no es másque un conjunto de reglas sintácticas que definen unsistema de consulta para documentos XML.

Igual que ocurre dentro de un sistema de archivos, unaconsulta XPath puede ser absoluta o relativa. Se dice quees absoluta si parte del nodo raíz, es decir, el primercarácter de la consulta es /.

Recordemos el documento XML con el que comenzó elcapítulo:

Page 298: Desarrollo Web Con PHP y MySQL

<?xml version="1.0"?>

<reparto>

<papel protagonista="si">

<personaje>Rick Deckard</personaje>

<actor>Harrison Ford</actor>

</papel>

<papel protagonista="no">

<personaje>Roy Batty</personaje>

<actor>Rutger Hauer</actor>

</papel>

<papel protagonista="no">

<personaje>Rachael</personaje>

<actor>Sean Young</actor>

</papel>

</reparto>

Gracias a XPath podemos llegar a los nombres de cadapersonaje utilizando:

Una ruta absoluta: /reparto/papel/personaje.

Una ruta relativa: papel/personaje, a partir de /reparto.

XPath también permite acceder al valor de los atributos.Por ejemplo, para obtener los valores del atributoprotagonista tendríamos que utilizar la ruta:/reparto/papel/personaje@protagonista.

Datos de ejemplo

Para probar el funcionamiento de las dos funciones quepermiten trabajar con datos en formato XML vamos amodificar la tabla de películas. Crearemos un nuevo campoque contendrá fragmentos de XML con el reparto. Ejecutela siguiente consulta para añadir este nuevo campo:

USE videoteca;

ALTER TABLE

pelicula

ADD

reparto TEXT NOT NULL;

Ahora vamos a insertar en ese nuevo campo elfragmento XML con el reparto de Blade Runner. Si elidentificador de esta película es el 1, la consulta deactualización sería:

USE videoteca;

UPDATE

pelicula

SET

reparto =

'<reparto>

<papel protagonista="si">

<personaje>Rick Deckard</personaje>

<actor>Harrisond Ford</actor>

</papel>

Page 299: Desarrollo Web Con PHP y MySQL

</papel>

<papel protagonista="no">

<personaje>Roy Batty</personaje>

<actor>Rutger Hauer</actor>

</papel>

<papel protagonista="no">

<personaje>Rachael</personaje>

<actor>Sean Young</actor>

</papel>

</reparto>'

WHERE

id = 1;

La figura 14.8 muestra el resultado de realizar unaconsulta de selección sobre la tabla de películas para verlos campos de Blade Runner.

Figura 14.8. Datos de la película Blade Runner

Y ahora, ¿qué hacemos con todo esto?

ExtractValue

La función ExtractValue permite recuperar valores de unfragmento de un documento XML. Recibe dos parámetros:el fragmento en cuestión y una expresión XPath quedetermina qué valores debe devolver.

El siguiente es un sencillo ejemplo del funcionamientode esta función:

SELECT ExtractValue(

'<papel>

<personaje>Roy Batty</personaje>

<actor>Rutger Hauer</actor>

</papel>',

'/papel/personaje'

) AS personaje;

Como acaba de ver, no es necesario que el fragmento setome de una tabla. El resultado de ejecutar esta consultaaparece en la figura 14.9.

Page 300: Desarrollo Web Con PHP y MySQL

Figura 14.9. Ejemplo de ut ilización de ExtractValue

Truco: Las cosas serían mucho más feas sin esa últ ima cláusula AS personaje.Haga la prueba.

El valor del segundo parámetro es /papel/personaje. Siinterpreta ese valor como una ruta sólo tiene que seguirlos nodos para obtener el resultado mostrado en la figura14.9. Primero el nodo raíz, papel y luego el nodopersonaje. Obtendríamos un resultado distinto siutilizásemos como segundo parámetro la expresión XPath/papel/actor.

Pero, ¿cuál será el resultado de utilizar esta función conun valor almacenado en un campo de una tabla? ¿Quéocurrirá si más de un registro coincide con la expresiónXPath? Ejecute la siguiente consulta para averiguarlo:

USE videoteca;

SELECT

ExtractValue(

reparto,

'/reparto/papel/personaje'

) AS personajes

FROM

pelicula

WHERE

id = 1;

Como muestra la figura 14.10, el resultado es la lista depersonajes contenidos en el fragmento XML del campo.

Figura 14.10. Lista de personajes

Igual de sencillo es obtener la lista de intérpretes.También podemos acceder a los atributos utilizando laexpresión XPath /reparto/papel/@protagonista. La figura

Page 301: Desarrollo Web Con PHP y MySQL

14.11 muestra el resultado utilizarla en una consulta.

Figura 14.11. Atributos de cada papel

Sin embargo, de poco nos sirven los resultados queacabamos de obtener. En este último ejemplo sí es fácildiferenciar entre cada uno de los elementos devueltospero, en el caso de los nombres de los personajes (RickDeckard Roy Batty Rachael) resulta un poco máscomplicado. Podemos solucionarlo si combinamos variasde las técnicas aprendidas a lo largo de este libro.

Vamos a utilizar el siguiente código para crear unprocedimiento almacenado que recupere, uno por uno, losnombres de los personajes y los devuelva separados porcomas. De esa forma, si llama al procedimientoalmacenado desde un lenguaje de programación, podráacceder fácilmente a cada uno de ellos.

Nota: Encontrará más información sobre los procedimientos almacenados en elcapítulo 11.

El código del procedimiento almacenado es el siguiente:

DELIMITER //

DROP PROCEDURE IF EXISTS

pa_personajes_obtener;

CREATE PROCEDURE pa_personajes_obtener (

idpelicula INT

)

BEGIN

DECLARE i INT DEFAULT 1;

DECLARE j INT DEFAULT 0;

DECLARE personajes TEXT DEFAULT '';

DECLARE personaje TEXT DEFAULT '';

SELECT

ExtractValue(

reparto, 'count(/reparto/papel)')

INTO

j

FROM

Page 302: Desarrollo Web Con PHP y MySQL

FROM

pelicula

WHERE

id = idpelicula;

WHILE i <= j DO

SELECT

ExtractValue(

reparto,

'/reparto/papel[$i]/personaje')

INTO

personaje

FROM

pelicula

WHERE

id = idpelicula;

SELECT

IF(

i <> j,

CONCAT(personaje, ', '),

personaje)

INTO personaje;

SET personajes = CONCAT(

personajes, personaje);

SET i = i + 1;

END WHILE;

SELECT personajes;

END //

DELIMITER ;

Para obtener la lista de personajes de la película conidentificador 1 (Blade Runner) tendría que ejecutar lasiguiente consulta:

USE videoteca;

CALL pa_personajes_obtener(1);

El resultado, en la figura 14.12.

Figura 14.12. Personajes, separados por comas

Page 303: Desarrollo Web Con PHP y MySQL

En este procedimiento almacenado se utilizan variastécnicas avanzadas. Para empezar, contamos el númerode papeles de que disponemos en el fragmento XML. Elresultado de esa consulta se guarda en la variable j.

A continuación, obtenemos uno por uno los nombres delos personajes y los guardamos en otra variable,separados por comas. El último nombre no incluye unacoma al final.

Para poder acceder a ellos de uno en uno utilizamos laexpresión XPath /reparto/papel[$i]/personaje, donde $itoma los valores desde 1 hasta el número de papelesexistentes: /reparto/papel[1] representa al primer nodopapel, /reparto/papel[2] al segundo y así sucesivamente.

Terminamos devolviendo el valor guardado en lavariable personajes.

Nota: En el procedimiento almacenado anterior ut ilizamos la instrucción decontrol de flujo WHILE y la función IF, técnicas avanzadas que no han tenido suhueco en este libro. Si desea más información sobre ellas consulte ladocumentación de MySQL.

UpdateXML

La función UpdateXML es la contrapartida necesaria deExtractValue. Recordemos que ésta última permiteextraer datos de fragmentos de documentos XMLalmacenados en campos de una tabla. No tendría muchosentido que para modificar los valores de esos campostuviésemos que guardar una nueva versión de dichosfragmentos.

UpdateXML recibe tres parámetros: el fragmento XMLcon el que trabajar, la expresión XPath que determina quévalores se quieren modificar y, por último, el nuevo valorque queremos guardar.

Volvamos a utilizar los datos de ejemplo. Para empezar,eche un vistazo a la lista de actores presentes en el camporeparto. Pudimos verla en la figura 14.8. Si se fija, hemosmetido la pata: el actor principal de Blade Runner no esHarrisond Ford sino Harrison Ford.

Ejecute la siguiente consulta para corregirlo:

USE videoteca;

UPDATE

pelicula

SET

reparto = UpdateXML(

reparto,

'/reparto/papel[1]/actor',

'<actor>Harrison Ford</actor>'

)

WHERE

Page 304: Desarrollo Web Con PHP y MySQL

id = 1;

Tras papel, entre corchetes, la posición en la que seencuentra el elemento papel que queremos modificar. Eneste caso se trata del primero de ellos, el correspondienteal papel de Rick Deckard.

¿Ha tenido éxito el cambio? Compruébelo con lasiguiente consulta:

USE videoteca;

SELECT

ExtractValue(

reparto,

'/reparto/papel[1]/actor'

) AS actor

FROM

pelicula

WHERE

id = 1;

La figura 14.13 muestra el resultado de ejecutar tanto lamodificación como la consulta de datos.

Figura 14.13. Modificación con UpdateXML

SimpleXML

Su nombre no podía ser más claro: SimpleXML es laforma más sencilla de manipular documentos XML desdePHP, con diferencia. Existen otras alternativas, cada unacon sus ventajas y sus inconvenientes si las comparamosentre sí. Por ejemplo, DOM (o DOM XML si utiliza PHP 4) ola pareja XMLReader y XMLWriter.

Apertura

Según vimos en los apartados anteriores, la siguienteorden devuelve la lista de géneros contenidos en la tablacorrespondiente de la base de datos.

Page 305: Desarrollo Web Con PHP y MySQL

mysql -u root -p --xml

-e "SELECT * FROM soporte" videoteca

> soportes.xml

La anterior figura 14.5 mostraba el resultado de ejecutardicha orden. Se trata del siguiente documento XML:

<?xml version="1.0"?>

<resultset

statement="SELECT * FROM soporte"

xmlns:xsi=

"http://www.w3.org/2001/XMLSchema-instance"

>

<row>

<field name="id">1</field>

<field name="nombre">DVD</field>

<field name="descripcion">

Digital Versatile Disc

</field>

</row>

<row>

<field name="id">2</field>

<field name="nombre">VHS</field>

<field name="descripcion">

Video Home System

</field>

</row>

</resultset>

Cargar un documento XML desde un archivo de textoutilizando SimpleXML es, pues eso, simple:

<?php

$xml = new SimpleXMLElement(

'C:\soportes.xml', NULL, TRUE

);

echo $xml->asXML();

?>

La figura 14.14 muestra el resultado de este breveprograma.

Figura 14.14. Carga de un documento XML

Truco: Efect ivamente, no parece un documento XML en absoluto, pero eso esporque el cliente Web está interpretando el código XML y sólo muestra la parte

Page 306: Desarrollo Web Con PHP y MySQL

interesante para nosotros, meros seres humanos. Si quiere ver el código XMLcompleto haga clic con el botón derecho del ratón sobre la página y seleccione laopción Ver código fuente del menú desplegable que aparecerá.

Para cargar el documento XML utilizamos el constructorde la clase SimpleXMLElement. El primer parámetro es elcontenido XML que deseamos cargar. Puede ser tanto unacadena de texto con contenido XML como un URL (queapunte a una dirección Web o a contenido dentro delsistema de archivos), dependiendo del valor del tercerparámetro. Si su valor es TRUE, el primer parámetro seinterpretará como URL, si es FALSE como texto XML.

Nota: El segundo parámetro se puede ut ilizar para pasar opciones al intérpreteXML, libxml, que quedan fuera del alcance de esta guía.

El método asXML de la clase SimpleXMLElement seutiliza para obtener el contenido XML cargado desde elrecurso externo o desde la cadena de texto pasada comoprimer parámetro.

Aunque poder mostrar el contenido de un documentoXML está muy bien, lo que resulta realmente interesantees poder acceder a sus elementos.

Recorrido de nodos

El nodo raíz del documento XML que estamos utilizandoen este apartado es resultset. Sus descendientes son losnodos row que, a su vez, contienen nodos field. Resultasencillo recorrer cada nodo row del documento:

<?php

$xml = new SimpleXMLElement(

'C:\soportes.xml', NULL, TRUE

);

$rows = $xml->xpath('/resultset/row');

foreach($rows as $row){

echo $row->asXML() . '<br/>';

}

?>

La apertura del documento es exactamente igual queantes. Ahora, en lugar de mostrar el contenido deldocumento utilizamos el método xpath para acceder a losnodos que nos interesan. En este caso se trata de losnodos row que contiene el nodo resultset. Por lo tanto, elparámetro de que debemos pasar a xpath es/resultset/row. Como resultado se devolverán todos losnodos del documento que cumplan ese criterio.

Para acceder a cada nodo sólo tenemos que iterar por$rows y mostrar su contenido utilizando asXML. La figura

Page 307: Desarrollo Web Con PHP y MySQL

14.15 muestra lo que se vería al ejecutar el anteriorprograma.

Figura 14.15. Acceso a nodos

Acceso a atributos

Para acceder a los atributos de un nodo debemos utilizarel método attributes del nodo que nos interese. Así,podría utilizar un bucle foreach para obtener todos losnodos row, otro bucle para obtener todos los nodos field y,una vez allí, obtener todos los atributos con otro bucleforeach.

Dependiendo del valor del atributo name de cada nodofield contenido en su interior mostraremos la informaciónde una forma o de otra. Por ejemplo, el identificador iráentre paréntesis, al principio, el nombre en negrita y, acontinuación, tras dos puntos, la descripción, terminada enpunto. El código resultante sería el siguiente:

<?php

$xml = new SimpleXMLElement(

'C:\soportes.xml', NULL, TRUE

);

$rows = $xml->xpath('/resultset/row');

foreach($rows as $row){

$fields = $row->xpath('field');

foreach($fields as $field){

$attributes = $field->attributes();

foreach($attributes as $attribute){

switch($attribute){

case 'id':

echo('(' .

$field->asXML() . ') ');

break;

case 'nombre':

echo('<b>' .

$field->asXML() . '</b>: ');

break;

Page 308: Desarrollo Web Con PHP y MySQL

break;

case 'descripcion':

echo($field->asXML() . '.<br/>');

break;

}

}

}

}

?>

El resultado, en la figura 14.16.

Figura 14.16. Acceso a los atributos

Nota: SimpleXML también permite modificar el contenido de los documentosXML, incluso construirlos desde cero. Consulte la documentación de SimpleXML sidesea más información al respecto.

Tras lo visto en este capítulo ya sabe cómo obtener enresultado de sus consultas SQL en formato XML, algo quepuede serle útil si quiere utilizar esos datos en otrosprogramas. Además, hemos aprendido cómo funcionantanto ExtractValue como UpdateXML, que permitenextraer y modificar valores de campos que contenganfragmentos de documentos en formato XML. Paraterminar, hemos aprendido a tratar esos datos XML desdePHP.

Aunque las capacidades de MySQL en lo que a esteformato se refiere son bastante rudimentarias, se tratasólo de la punta del iceberg. La mayoría de los lenguajesde programación modernos permiten trabajar directamentecon XML. Es más, le garantizo que MySQL seguiráincorporando nuevas características para facilitar el trabajocon XML, así que todo el tiempo que invierta en aprendersobre él será una buena inversión.

No podemos decir lo mismo de PHP. Este lenguaje deprogramación ofrece diferentes interfaces de acceso a XMLademás de SimpleXML como, por ejemplo, DOM o la parejaXMLReader y XMLWriter. Cada una de ellas tiene susvirtudes y sus defectos. La elección dependerá de lasnecesidades de sus programas.

Page 309: Desarrollo Web Con PHP y MySQL

Epílogo

Durante este libro hemos recorrido una gran cantidad detecnologías de diferente naturaleza: servidores Web,servidores de bases de datos, diferentes lenguajes deprogramación. Y de todas estas herramientas diferenteshemos sido capaces de lograr lo impensable, gracias a queson capaces de colaborar entre ellas.

El espacio del que disponemos en una guía de estascaracterísticas es limitado y sin embargo, hemos trabadocontacto con una gran cantidad de productos diferentes.

Espero que, al menos, todo esto haya servido para quepierda el miedo y sepa que tiene frente a sí una grancantidad de posibilidades si dispone de las herramientasadecuadas.

Recuerde: aún queda mucho que aprender.

Page 310: Desarrollo Web Con PHP y MySQL

Table of ContentsDedicatoriaAgradecimientosIntroducciónCómo usar este libroPrólogo1. MySQL y PHP

1.1. La primera aplicación1.2. XAMPP

1.2.1. Puesta en marcha deXAMPP

1.3. Trabajando con MySQL1.3.1. Creación de la base dedatos1.3.2. Creación de la tabla1.3.3. Inserciones

1.4. Trabajando con PHP2. PHP

2.1. Introducción2.2. Editores2.3. Estructura de un archivo PHP

2.3.1. Escapar de HTML2.3.2. Funciones de salida2.3.3. Comentarios

2.4. Variables2.4.1. Tipos de datos

2.5. Operadores2.5.1. Operador básico deasignación2.5.2. Operadores aritméticos2.5.3. Operadores decomparación2.5.4. Operadores lógicos2.5.5. Operadores de incremento2.5.6. Concatenación de cadenas2.5.7. Precedencia de operadores2.5.8. Cambios de tipo

2.6. Instrucciones de control2.6.1. Instrucciones condicionales2.6.2. Instrucciones iterativas2.6.3. Salida de bucles

3. MySQL3.1. Bases de datos3.2. ¿Qué es una tabla?3.3. Base de datos de ejemplo

3.3.1. Herramientas de consulta3.3.2. Creación de la base dedatos

3.4. Operaciones sobre tablas3.4.1. Creación3.4.2. Modificación3.4.3. Borrado

3.5. Tipos de tabla3.5.1. MyISAM3.5.2. InnoDB

3.6. Tipos de datos3.6.1. Tipos de texto

Page 311: Desarrollo Web Con PHP y MySQL

3.6.2. Tipos numéricos3.6.3. Fechas y horas

4. PHP orientado a objetos4.1. Funciones

4.1.1. Parámetros4.1.2. Devolución de valores4.1.3. Trabajando con funciones

4.2. Inclusión de archivos4.3. Orientación a objetos

4.3.1. Clases4.3.2. Más allá de las clases

5. Diseño de bases de datos5.1. El ejemplo

5.1.1. Limitaciones5.1.2. Objetivos

5.2. MySQL Workbench5.2.1. Instalación

5.3. Conceptos varios5.3.1. El valor NULL5.3.2. Claves primarias5.3.3. Índices5.3.4. Columnas de incrementoautomático5.3.5. El modelo relacional

5.4. Divide y vencerás5.4.1. Creación de tablas conMySQL Workbench5.4.2. División de tablas5.4.3. Relacionar tablas5.4.4. Relaciones muchos amuchos5.4.5. El ejemplo finalizado

6. SQL6.1. La base de datos de ejemplo

6.1.1. Creación de la base dedatos6.1.2. Inserción de datos

6.2. Operadores6.2.1. Operadores aritméticos6.2.2. Operadores decomparación6.2.3. Operadores lógicos6.2.4. Cambiando la precedencia

6.3. Manipulación de bases de datos6.3.1. Creación6.3.2. Borrado

6.4. Consultas de selección6.4.1. Listados de una tabla6.4.2. Listados de varias tablas

6.5. Actualizaciones6.6. Inserciones6.7. Borrados

7. PHP y MySQL7.1. Acceso mejorado a MySQL7.2. El ciclo de la vida

7.2.1. Conexión7.2.2. Operación7.2.3. Desconexión

7.3. Conjuntos de registros

Page 312: Desarrollo Web Con PHP y MySQL

7.4. Otras consultas7.5. Consultas escapadas7.6. Configuración

7.6.1. Valores de configuración7.6.2. Modificación de laconfiguración7.6.3. Ventajas7.6.4. Inconvenientes7.6.5. Opciones de PHP enApache

8. Formularios8.1. Cómo funcionan los formularios8.2. Formularios HTML

8.2.1. Creación de formularios8.2.2. Elementos de un formulario

8.3. Envío de información8.4. Recuperación de información8.5. Inserción de registros8.6. Control en el lado del cliente

9. Gestión de errores9.1. PHP y los errores

9.1.1. Configuración9.1.2. Funciones9.1.3. Excepciones

9.2. MySQL y los errores9.2.1. Archivos de registro9.2.2. Archivos de registro entablas9.2.3. Idioma de los errores

9.3. MySQLi y los errores10. Plantillas

10.1. ¿Qué es Smarty?10.1.1. Un pequeño ejemplo

10.2. Instalación10.3. Lista de géneros

10.3.1. La plantilla10.3.2. La página PHP10.3.3. Otra plantilla

11. Procedimientos almacenados11.1. Introducción

11.1.1. Base de datos reducida11.1.2. Creación11.1.3. Inserción

11.2. Un sencillo ejemplo11.3. Sintaxis

11.3.1. Creación11.3.2. Variables11.3.3. Delimitadores11.3.4. Parámetros11.3.5. Funciones almacenadas11.3.6. Eliminación

11.4. Utilización desde PHP12. Desencadenadores

12.1. Introducción12.1.1. Base de datos reducida12.1.2. Creación12.1.3. Inserción

12.2. Sintaxis12.2.1. Creación

Page 313: Desarrollo Web Con PHP y MySQL

12.2.2. Eliminación12.3. Ejemplos

12.3.1. Inserción12.3.2. Actualización12.3.3. Borrado

13. Vistas13.1. Introducción13.2. Sintaxis

13.2.1. Creación13.2.2. Modificación13.2.3. Eliminación

13.3. Ejemplos13.3.1. Creación13.3.2. Modificación13.3.3. Eliminación

13.4. Utilización desde PHP14. XML

14.1. ¿Qué es XML?14.1.1. Partes de un documentoXML14.1.2. Etiquetas

14.2. XML desde la línea de órdenes14.3. Funciones XML

14.3.1. XPath14.3.2. Datos de ejemplo14.3.3. ExtractValue14.3.4. UpdateXML

14.4. SimpleXML14.4.1. Apertura14.4.2. Recorrido de nodos14.4.3. Acceso a atributos

Epílogo

Page 314: Desarrollo Web Con PHP y MySQL