$ d i s t a n c e < / t d > \ n " ; echo " |
I
/ > I ;
/ / o cualquier procesamiento que desee realizar
Desarrollo W e b con PHP y MySQL
A1 crear didmicamente 10s nombres de las variables, podemos acceder a cada campo uno por uno. Adem6s del bucle f o r existe el bucle f o r e a ch, disefiado especificamente para su uso con matrices. En un capitulo posterior comentaremos c6mo utilizarlo.
...
Bucles d o while El tip0 final de bucle que mencionaremos se comporta de mod0 ligeramente diferente. La estructura general de una instrucci6n do. . w h i l e es la siguiente:
.
Un bucle d o . .w h i l e se diferencia de un bucle w h i l e en que la condici6n se prueba a1 final. Por lo tanto en un bucle do. . w h i l e , la instrucci6n o el bloque incluido en el bucle se ejecuta siempre una vez a1 menos. Incluso si tomamos un ejemplo en el que la condicidn ser6 f a 1 s e a1 principio y nunca puede ser t r u e , el bucle se ejecutar6 una vez antes de comprobar la condici6n y el final.
.
Snum d0
=
100;
(
echo $num.'
/ > I ;
I
while
(Snum < 1
i;
-
Como salir de- una estructura de control o una secuencia de comandos Si desea detener la ejecuci6n de un fragment0 de c6dig0, existen tres opciones que dependen del efecto que est6 persiguiendo. Si desea detener la ejecucidn de un bucle, puede utilizar la instrucci6n b r e a k como se coment6 anteriormente en la seccion sobre s w i t c h . Si utiliza esta instrucci6n en un bucle, la ejecucidn de la secuencia de comandos continuard en la linea situada tras el bucle. Si desea saltar hasta la siguiente iteraci6n de bucle, puede utilizar la instrucci6n continue. Si desea terminar de ejecutar la secuencia de comandos PHP entera, puede utilizar la instrucci6n e x i t . Esta opci6n resulta util a1 realizar tareas de comprobaci6n de errores. Por ejemplo, podemos modificar nuestro ejemplo anterior de la siguiente forma:
1. Curso acelerado de P H P
I e c h o 'You exit;
did
not
order
anything
on
the
previous
page!
/ > I ;
i
La llamada a exit impide que PHP ejecute el resto de la secuencia de comandos.
Siguiente paso: guardar el pedido del cliente Ahora ya sabe c6mo recibir y manipular pedidos de un cliente. En el siguiente capitulo examinaremos c6mo almacenar el pedido para poder recuperarlo y servirlo.
Ahora que ya sabemos cdmo acceder y manipular datos introducidos en un formulario HTML, podemos pasar a examinar variar formas de almacenar dicha informacidn para su uso posterior. En la mayor parte de 10s casos, incluido el ejemplo examinado en el capitulo anterior, querri almacenar 10s datos y cargarlos en un momento posterior. En nuestro caso, necesitamos escribir pedidos de cliente para almacenarlos y poder servirlos despuds. En este capitulo vamos a expkcar cdmo podemos escribir el pedido del cliente del ejemplo anterior en un archivo y cdmo volverlo a leer. Tambikn veremos por qud esta solucidn no es siempre la mejor. Si tenemos un gran numero de pedidos, deberiamos utilizar un sistema de administracidn de base de datos como MySQL. Entre 10s temas clave que trataremos en este capitulo se incluyen 10s siguientes: Cdmo guardar datos para su uso posterior Cdmo abrir un archivo C6mo crear y escribir en un archivo Cdmo cerrar un archivo Lectura de un archivo Bloqueo de un archivo Eliminacidn de archivos Otras funciones utiles con archivos
2. Almacerrnrrlierrto
!j
r e c ~ ~ y e r n c i oder ~datos
Una opci6n inejor: 10s sistemas de administraci6n de bases de datos Lecturas adicionales
Bdsicamente existen dos formas d e almacenar datos: en archivos planos o e n una base d e datos. Los archivos planos pueden tener multiples formatos pero, e n general, cuando hacemos referencia a un archivo plano, nos estamos refiriendo a un archivo simple d e texto. En este ejemplo, vamos a escribir 10s pedidos d e 10s clientes en un archivo d e texto, uno en cad a 1'inea. Este rn4todo es muy sencillo, per0 resulta a la vez muy restrictivo, como veremos en una secci6n posterior. Si esta tratando con informacion de un volumen significative es probable que prefiera utilizar una base d e datos. Sin embargo, 10s archivos planos se utilizan en determinadas ocasiones y hay situaciones en las que necesitara saber c6mo hacerlo. Las operaciones d e lectura y escritura d e archivos en PHP se realizan priicticamente d e la misma forma que e n C. Si ha programado alguna vez en C o ha desarrollado secuencias d e comandos d e nucleo para sistemas UNIX, la mecinica le resultara bastante familiar.
En este capitulo, utilizaremo? una versi6n modificada del formulario d e pedido visto en el 6ltimo capitulo: Comenzaremos por este formulario y por el c6digo d e PHP que escribimos para procesar 10s datos del pedido. I
Nota Las secuenciasde comandosde HTMLy de PHP que se utilizan en este capitulo se pueden encontrar en la carpeta correspondiente del CD-ROM.
Hemos modificado el formulario para incluir un metodo rapido para obtener la direccion d e envio del cliente. En la figura 2.1 se ilustra s u aspecto. El campo del formulario en el que se recoge la direccion d e envio del cliente se denomina address.Este campo nos da una variable a la que podemos acceder como $address a1 procesar el formulario e n PHP, si hemos activado el parimetro register-globals o como $ -POST [ 'address ' ] o $ GET [ 'address ' ] si el parametro register-globals n o est6 activado (consu~teel capitulo 1 si desea obtener mAs detalles).
Dcsnrrollo Wch con P H P y MySQL
1 Order Form Item
I Quantity
Tires
r
li-
oil Spark Plugs
16
Sllipp~ngAddress 11 Smith Strecl. Nowlieresv~lle
Figura 2.1. Esta version del pedido obtiene la direccion de envio del cliente
Escribiremos cada pedido que entre en el mismo archivo. Seguidamente, construiremos una interfaz Web para permitir que la plantilla d e Bob pueda ver 10s pedidos que entran.
Introducci~nal procesamiento c'e arcliivos La operaci6n d e escribir datos en u n archivo incluye 10s siguientes pasos:
1. Abrir el archivo. Siel a r h i v o no existiese, tendriamos que crearlo. 2. Escribir 10s datos en el archivo.
3. Cerrar el archivo. La operation d e lectura d e 10s d a t o s d e u n archivo t a m b i h incluye d e tres pasos:
1. Abrir el archivo. Si no se puede abrir (por ejemplo, si no existiese), tendriamos que reorganizar el proceso y salir con elegancia. 2. Leer 10s datos del archivo.
3. Cerrar el archivo. Cuando queremos leer 10sdatos d e u n archivo, podemos determinar qu6 cantidad d e elementos del archivo leer cada vez. En una secci6n posterior examinaremos dichas opciones. En primer lugar vamos a comenzar por abrir un archivo.
2. Almacenamiento y recuperacidn de datos
Como abrir un archivo Para abrir un archivo en PHP, se utiliza la funci6n f open ( ) . A1 abrir un archivo, tenemos que especificar para qud tenemos pensado utilizarlo. Es lo que se conoce como 10s modos de archivo.
Modos de archivo El sistema operativo del servidor necesita saber qud queremos hacer con el archivo que vamos a abrir. Necesitamos saber si otra secuencia de comandos puede abrir el archivo que ya tenemos abierto y determinar si el titular de la secuencia de comandos dispone de permiso para utilizarlo de esa forma. Bfisicamente, 10s modos de archivo ofrecen a1 sistema operativo un mecanismo para determinar la forma de procesar las peticiones de acceso procedentes de otras personas o secuencias de comandos, y un mdtodo para comprobar si dispone de acceso y permiso para utilizar el archivo. A1 abrir un archivo dispone de tres opciones: 1. Puede abrir un archivo para leerlo para escribir en dl o para ambas acciones. 2. Si estfi escribiendo en un archivo, puede sobrescribir 10s contenidos existentes o adjuntar nuevos datos a1 final del archivo.
3. Si est6 intentando escribir en un archivo sobre un sistema operativo que diferencie entre archivos binarios y archivos de texto, puede que desee especificar esta circunstancia. La funci6n f open ( ) admite combinar estas tres opciones.
Uso de fopen() para abrir un archivo Supongamos que desea escribir el pedido de un cliente en el archivo de pedidos de Bob. Puede abrir el archivo para escribir el pedido con siguiente secuencia:
A1 llamar a f open, se esperan dos o tres parfimetros. Por regla general se utilizarfin dos, como se muestra en la linea de c6digo. El primer0 deberia ser el archivo que queremos abrir. Puede especificar una ruta hasta este archivo como hemos hecho en el c6digo anterior; nuestro archivo o r d e r s . t x t se encuentra dentro del directorio de pedidos. Hemos utilizado la variable incorporada SHTTP SERVER VARS [ ' DOCUMENT ROOT ' 1 pero, como ocurre con 10s inc6modos nombre; comple
..
Desnrrollo W e b con PHP y MySQL
Este directorio se encuentra fuera del arb01 de directorios, por razones de seguridad. No queremos que este archivo resulte accesible desde la Web salvo a trav6s de una interfaz que proporcionaremos nosotros. Esta ruta se conoce como ruta relativa ya que describe una posici6n en el sistema de archivos en relaci6n a1 directorio del documento. Como ocurre con 10s nombres cortos que asignamos a las variables de formulario, si no activamos el padmetro register global s, necesitamos incluir la siguiente linea a1 principio de la secuencia de comandos:
para copiar 10s contenidos de la variable de estilo largo a la variable de estilo corto. A1 igual que existen varias formas de acceder a 10s datos de formulario, existen varias formas de acceder a las variables de servidor predefinidas. En funci6n de la configuraci6n del servidor puede acceder a la raiz del documento a traves de:
Como en el caso de 10s datos de formulario, el primer estilo, que hemos llamado estilo corto, est6 disponible autom6ticamente si ha activado el partimetro register globals. El segundo estilo (el estilo intermedio) no se puede desactivar, pero s610 ;st6 disponible en PHP 4.1 y versiones posteriores. El estilo largo est6 disponible para todos 10s sistemas, pero se considera obsoleto por lo que es posible que desaparezca en un futuro. T a m b i h se especifica una ruta absoluta a1 archivo. Esta es la ruta desde el directorio raiz ( / en 10s sistemas UNIX y, por regla general, c : \ en Windows). En nuestro servidor UNIX, ~ e r i a Jhome / boo k / o rde r s . El problema de utilizar este m6todo es que si alojamos el sitio en el servidor de un tercero, la ruta absoluta podria variar. A nosotros nos toc6 aprenderlo de la forma dificil ya que tuvimos que modificar las rutas absolutas de una gran cantidad de secuencias de comandos cuando 10s administradores del sistema decidieron cambiar la estructura de directorios sin previo aviso. Si no se especifica la ruta, el archivo se crear6 o se buscar6 en el mismo directorio que la propia secuencia de comandos. Esta ser6 diferente si estd ejecutando PHP a traves de algiin tip0 de contenedor CGI y ello depender6 de la configuraci6n del servidor. En un entorno UNIX, las barras de 10s directorios son las barras est6ndar (/). Si estd utilizando la plataforma Windows, puede usar estas barras o las barras invertidas (\). Si utiliza estas iiltimas, debe marcarlas como caracteres de escape para que fopen puede entenderlas correctamente. Para marcar un car6cter como car6cter especial, basta con agregar otra barra invertida delante, como se muestra a continuaci6n:
2. Almncetrntr~ierrtoy recrrperncidw dp dntos
Las barras invertidas no se suelen utilizar para indicar rutas e n P H P porque el codigo solo funcionaria e n Windows. El uso d e la barra estandar permite mover codig o entre equipos Windows y UNIX sin variaciones. El segundo par6metro d e f o p e n ( ) es el m o d o d e archivo, q u e deberia ser una cadena. ~ s t especifica a qu4 hacer con el archivo. En este caso vamos a pasar ' w ' a f o p e n ( ) , q u e significa abrir el archivo para escritura. En la tabla 2.1 se describen 10s distintos modos d e archivo. Tabla 2.1. Resumen de 10s modos de archivo de fopen 7-
Modo
---
--
-
-
--.
Significado Modo de lectura: abre el archivo para la lectura, empezando por la parte inicial del archivo. Modo de lectura: abre el archivo para lectura y escritura, empezando por la parte inicial del archivo. Modo de escritura: abre el archivo para escritura, empezando por la parte inicial del archivo. Si el archivo ya existiese, elimina sus contenidos. Si no existiese, intenta crearlo. Modo de escritura: abre el archivo para escritura y lectura. Si el archivo ya existiese, elimina sus contenidos. Si no existiese, intenta crearlo. Modo de adjuncion: abre el archivo para adjuntar (escribir) unicamente, empezando por la parte final de 10s contenidos existentes. Si no existiese, intenta crearlo. Modo de adjuncion: abre el archivo para adjuntar (escribir) -y l e a , empezando por la parte final de 10s contenidos existentes. Si no existiese, intenta crearlo. Modo binario: se utiliza en combinacion con uno de 10s otros modos. Puede utilizarlo si su sistema de archivos distingue entre archivos binarios y archivos de texto. Los sistemas Windows hacen esta diferencia al contrario que 10s sistemas UNIX.
El modo d e archivo para nuestro ejemplo d e p e n d e d e como s e utilice el sistema. En nuestro caso, hemos utilizado 'w', q u e solo permite almacenar u n pedido e n el archivo. Cada vez que s e tome u n nuevo pedido, s e sobrescribira el anterior. Esta opci6n no parece m u y adecuada por lo que haremos mejor e n seleccionar el m o d o d e adjuncion. La funcion f o p e n ( ) consta d e u n tercer parametro opcional. Puede utilizarlo si desea buscar el par6metro i n c l u d e p a t h (establecido e n la configuration d e PHP; a este respecto consulte el a p 4 n d i c e i ) d e u n archivo. Si desea activar esta opcicin,
Desarrollo Web con P H P y MySQL
asigne 1 a1 parfimetro. De esta forma no tendr6 que suministrar un nombre o una ruta de directorio: Sfp
=
fopenilorders.txt', 'a', 1);
Si f o p e n ( ) se abre satisfactoriamente, se devolverfi un puntero a1 archivo que deberia guardarse en una variable, en este caso $ f p . Esta variable se utiliza para acceder a1 archivo cuando se desee leer o escribir en el.
Como abrir archivos a trav6s de FTP o HTTP Ademfis de abrir archivos locales para su lectura o escritura, puede abrir archivos a traves de FTP y HTTP utilizando f o p e n ( ) . Si el nombre del archivo utilizado comienza por f t p : / /, se abrirfi una conexi6n FTP en mod0 pasivo a1 servidor especificado y se devolverfi un puntero a1 inicio del archivo. Si el nombre del archivo utilizado comienza por h t t p : //, se abrir6 una conexi6n HTTP al servidor especificado y se devolverri un puntero a la respuesta. A1 utilizar el mod0 HTTP, debe especificar las barras situadas a1 final de 10s nombres de directorios, como se muestra a continuaci6n:
Cuando se especifica la iiltima forma de direcci6n (sin la barra), el servidor Web suele utilizar una redirecci6n HTTP para enviarle a la primera direcci6n (con barra). Pruebe en su navegqdor., En las versiones de PHP anteriores a la 4.0.5, la funci6n f o p e n ( ) no admitia redirecciones HTTP, por lo que debe especificar 10s URL a 10s que hacen referencia 10s directorios con una barra final. A partir de la versi6n 4.3.0 tambien puede abrir archivos sobre SSL siempre y cuando se haya compilado o habilitado la compatibilidad para OpenSSL y utilice la secuencia h t t p s : / / delante del nombre del archivo. Recuerde que 10s nombres de dominio de su URL no discriminan entre mayiisculas y minfisculas per0 que la ruta y el nombre del archivo puede que si lo hagan.
Problemas al abrir el archivo Un error que suele producirse de manera habitual es intentar abrir un archivo para el que no se disponga de permiso de lectura o escritura. PHP generar6 un aviso similar a1 que se ilustra en la figura 2.2. Si recibe este error, debe asegurarse de que el usuario utilizado para ejecutar la secuencia de comandos dispone de permiso para acceder a1 archivo que est6 inten-
tando utilizar. En funcion d e c6mo se configure el servidor, la secuencia d e comandos puede clue se ejecute como el usuario de servidor Web o como el propietario del directorio e n el clue s e incluye la secuencia d e comandos.
Order Results Order processed at 16:36, 20th April Your order is as follorva: 4 spark plugs Told of order is 16.00
I
I
.4ddre~.sto ship lo is 200 Interciiy Hny, Counhytorvn W H I I ~ Ifoper~("../../ordera/o~'de~_~~tx-t",) ~: - Pem~issiondenied in /home/bookipubtic~1111nl/cl1apte1'2~~1roce~~0rd~r.~1h~1 011 line 54
Figura 2.2. PHP le avisa especificarnente cuando no puede abrir
u n archivo
En la mayor parte d e 10s sistemas, la secuencia d e comandos se ejecuta como el usuario d e servidor Web. Si SLI secuencia d e comandos estuviera e n u n sistema UNIX dentro del directorio -/public html/chapter2/, se crearia u n directorio sobre el clue todo el rnundo podria escribir y almacenar el pedido mediante la siguiente secuencia:
Tenga e n cuenta q u e 10s directorios y 10s archivos sobre 10s q u e puede escribir todo el m u n d o son peligrosos. No deberia utilizar directorios susceptibles d e escritura clue resulten accesibles desde la Web. Por esta razcin, nuestro directorio orders se encuentra d o s subdirectorios m i s atras, por encima del directorio public html.El tema d e la seguridad se comentari e n m i s profundidad e n u n capitulo Uno d e 10s elementos clue suele d a r errores a1 abrir u n archivo es el uso d e permisos incorrectos, a u n q u e no es el ilnico problema. Si el archivo n o se puede abrir, necesitari saberlo para n o intentar leer o escribir datos e n 41. Si la llamada a fopen ( ) falla, la funci6n devolveri false.Puede tratar el error d e forma clue resulte m i s significative sustituyendo el mensaje d e PHP por otro.
Desnrrollo Wtb con P H P
!j
M!ySQL
El simbolo @ situado delante d e la llamada a fo p e n { ) indica a P H P clue suprima todos 10s errores producidos por la llamada d e funci6n. Por regla general, conviene saber c u i n d o ocurre alglin error, per0 en este caso vamos a tratar el problema en otro lugar. Esta linea t a m b i h s e puede escribir d e la siguiente forma:
Sin embargo, con esta secuencia resulta menos obvio que se esta utilizando el operador d e supresion d e errores. En un capitulo posterior se tratari el tema de la generacidn de informes de error d e manera m i s detallada. La instruccidn i f comprueba la variable $ f p para determinar si se ha devuelto un punter0 v d i d o d e archivo desde la llamada f o p e n . En caso negativo, imprime u n mensaje d e error y concluye la ejecucidn d e la secuencia d e comandos. Como la pigina termina aqui, se ha utilizado etiqueta HTML d e cierre para que cddigo HTML resulte correcto. En la figura 2.3 se ilustra el resultado d e este enfoque.
I
A r ~ h m Edta6n Ver F m n l a s Henam~enlas b d a
1 Dlrernbn la t np I
b
BR CI/
tT
I
c I
rtl
J '2
II
Order Results Order processed al 16:41,20th April
I1 1 11
You- order is as follows: I spark plugs Total oforder is 16.00 Address to ship to is 200 Jntercity Hwy, C o u n ~ o w n Your order could not be yrocesacd at U~ist h e . Plense t ~ y a g h later.
Figura 2.3. El uso de propios mensajes de error propios en lugar de 10s de PHP puede mejorar la comprension de 10s errores
C6mo escribir en un archivo La operacidn d e escribir en u n archivo e n PHP resulta relativamente sencilla. Puede utilizar la funci6n fwri t e ( ) (escribir archivo) o la funci6n f p u t s ( ) (cadena
2. Almacenamiento y recuperacidn de datos
de archivo); f p u t s ( ) es un alias de f w r i t e la funci6n f w r i t e ( ) : fwrite($fp,
()
. En el siguiente ejemplo llamamos a
Soutputstring);
Esta linea indica a PHP que escriba la cadena almacenada en $ o u t p u t s t r i n g en el archivo a1 que apunta $ f p . Antes d e analizar 10s contenidos d e $ o u t p u t s t r i n g , vamos a comentar la funci6n f w r i t e ( ) .
de fwrite()
Parametros
La funci6n f w r i t e ( ) toma tres parimetros aunque el tercero es opcional. Su sintaxis es la siguiente: int
fwrite
(
int
fp, string
cadena
[,
int
longitud])
El tercer parimetro, longitud, es el niimero miximo de bytes que escribir. Si se incluye este parimetro, f w r i t e ( ) escribiri la cadena en el archivo a1 que apunte el parimetro fp hasta que alcance el final de la cadena o haya escrito la longitud de bytes, dependiendo de qu6 venga primero.
Formatos de archivo A1 crear un archivo de datos como el utilizado en el ejemplo, la decisi6n sobre el formato en el que almacenar 10s datos seri nuestra. (Sin embargo, si tiene previsto utilizar el archivo de datos en otra aplicacGn, puede que necesite seguir las reglas de dicha aplicaci6n.) Vamos a crear una cadena que represente un registro en nuestro archivo de datos. Para ello, podemos utilizar el siguiente c6digo: Soutputstring = $date."\tW .$tireqty." tires .$sparkqty." spark plugs\t\$".$total \ t u . $address."\rr";
\t".$oilqty."
oil\tM
M
En nuestro sencillo ejemplo, estamos almacenando cada registro de pedido en una linea separada del archivo. Hemos optado por escribir un registro por linea porque de esta forma obtenemos un separador de registros sencillo en forma del caricter de nueva linea. Como las nuevas lineas son invisibles, las representamos con la secuencia de control " \ n u . Escribiremos 10s campos de datos en el mismo orden y utilizaremos el caricter de tabulaci6n para separar 10s campos. De nuevo, como el caricter de tabulaci6n es invisible, se representa mediante la secuencia de control " \ t " . Puede seleccionar cualquier delimitador 16gico que resulte sencillo de distinguir. El separador o delimitador no debe ser un caricter que se utilice como entrada ya que deberia procesarse para eliminar o utilizar caracteres de escape en todas las instancias del limitador. En un capitulo posterior se analizari c6mo procesar las entradas del usuario. Por el momento asumiremos que no se van a introducir tabuladores en un formulario de pedido. Aunque resulta dificil, no es imposible que un usuario introduzca un tabulador o un caricter de nueva linea en un campo de entrada HTML de una sola linea.
Desarrollo Web con P H P y MySQL
El uso de un separador especial de campo nos permitira dividir 10s datos en variables distintas de manera mas sencilla a1 leer 10s datos, como veremos en capitulos posteriores. Por el momento, trataremos cada pedido como una unica cadena. Tras procesar varios pedidos, 10s contenidos del archivo se parecertin a1 ejemplo ilustrado en el listado 2.1. Listado 2.1. Ejemplo de lo que podria contener el archivo de pedidos 15:42, 20th April 15:43, 20th April 15:43, 20th April
4 tires 1 ail 6 spark plugs $434.00 22 Short St, Smalltown 1 tires 0 oil 0 spark plugs $100.00 33 Mairl Rd, Newtown 0 tires 1 oil 4 spark plugs $26.00 127 Acacia St, Springfield
Como cerrar un archivo Cuando se termina de utilizar un archivo, es necesario cerrarlo. Deberia hacerlo utilizando la funci6n f clos e ( ) de la siguiente forma:
Esta funci6n devolverti t r u e si el archivo se cerr6 satisfactoriamente o f a 1s e en caso contrario. Como la probabilidad de que surja un problema con esta funcion es muy inferior a la operaci6n de apertura, no procederemos a probarla.
Lectura desde un archivo Llegados a este punto, 10s clientes de Bob pueden remitir sus pedidos a travks de la Web, pero si 10s empleados de Bob quieren examinar 10s pedidos, tendr6n que abrir 10s archivos manualmente. Vamos a crear una interfaz Web para permitir que 10s empleados de Bob puedan leer 10s archivos de manera sencilla. El c6digo correspondiente a esta interfaz se incluye en el listado 2.2. Listado 2.2. vieworders.php. lnterfaz para leer el archivo de pedidos
Bobls Auto Parts - Customer Orders
2. Alrnacennrniento y recuperncidn de datos
Esta secuencia d e comandos sigue el orden expuesto anteriorinente: abre el archivo, lee el archivo y cierra el archivo. En la figura 2.4 se ilustra el resultado de esta secuencia d e comandos utilizando el archivo d e datos del listado 2.1.
I 4rhr.o Dlr-~bo
E ~ , c I c Ver ~ FwarPre H ~ r w m e ~ 1 m Amda il] Ihap //rr,,,b;awl
,/ri ~
~ ~ p ~ r ? x.2 / . . .I, , ,;
~ h n
. .. .
.
...
J.'-'lr . -
Bob's Auto Parts
I
il
Customer 0 r d & 15:42,20th April 4 tires 1 oil 6 spark plugs $434.00 22 Short St. Smalltown 15:43.20& April 1 tires 0 oil 0 spark plugs $100.00 33 Main Rd, Newtown 15:43, 20lh April 0 tires 1 oil 4 spark plugs $26.00 127 Acacia St, Springiield
Figura 2.4. La secuencia de comandos vieworders.php muestra todos 10s pedidos
actuales del archivo orders.txt en la ventana del navegador Vamos a examinar las funciones d e esta secuencia d e comandos en detalle.
Apertura de un archivo para s u lectura: fopen0 De nuevo, abrimos el archivo utilizando fo p e n ( ) . En este caso abrimos el archivo para su lectura unicamente, por lo que utilizamos el mod0 de archivo ' r ' :
Desarrollo Web con P H P y MySQL
C6mo saber cuiindo parar: feof() En este ejemplo, utilizamos el bucle w h i l e para leer el archivo hasta alcanzar el final del archivo. El bucle w h i l e busca el final del archivo utilizando la funci6n feof while
0: ( ! f e o f ( S f p ))
La funci6n f e o f ( ) toma un puntero de archivo como su unico parimetro. Devuelve t r u e si el puntero de archivo se encuentra al final del archivo. En este caso (y en general a1 leer desde un archivo), leemos desde el archivo hasta que alcanzamos EOF.
Cdmo leer linea a linea: fgets(), fgetss() y fgetcsv() En nuestro ejemplo, utilizamos la funci6n f g e t s $order=
fyets (Sfp,
()
para leer desde un archivo:
999) ;
Esta funci6n se utiliza para leer, linea a linea, un archivo. En este caso, leer5 hasta que encuentre un nuevo cardcter de linea (\n), un EOF o haya leido 998 bytes del archivo. La longitud de lectura es la longitud menos un byte. Se pueden utilizar muchas funciones diferentes para leer archivos. La funci6n f g e t s ( ) resulta util para tratar con archivos que contengan texto plano con el que queramos trabajar en grupos. Una variacion interesante de esta funcion es la funcion f g e t s s ( ) ,cuya sintaxis es la siguiente: s t r i n g fgetss ( i n t fp,
i n t l o z g i tud, s t r i n g [etiquetas-permi t i d a s ] ) ;
Esta funci6n es muy parecida a la funci6n f g e t s ( ) con la salvedad de que elimina todas las etiquetas PHP y HTML que encuentra. Si desea dejar alguna etiqueta en particular, puede incluirlas en la cadena etiquetas-permitidas. Se utiliza f g e t s s ( ) por seguridad a1 leer un archivo escrito por otra persona o que contenga entradas de usuario. La inclusion de codigo HTML sin restricciones en el archivo puede estropear el formato atentamente organizado y la inclusion de c6digo PHP podria ofrecer rienda suelta a un usuario malintencionado sobre su servidor. La funcidn f g e t c s v ( ) es otra variacion sobre f g e t s ( ) . Su sintaxis es la siguiente: array fgetcsv contenedorl 1 )
(
int
fp,
int
longitud
[,
string
delimitador
[,
string
Se utiliza para dividir las lineas del archivo si se ha utilizado un caracter de delimitacion, como el caracter de tabulacion sugerido antes o una coma como se suele hacer en las hojas de c~lculoy otras aplicaciones. Si desea reconstruir las variables del pedido de manera individual en lugar de en forma de linea de texto, f g e t c s v ( )
2 . Almacenamiento y recuperacio'n de datos
nos permite hacerlo con facilidad. Se invoca de la misma forma que f g e t s se le pasa el delimitador utilizado para separar campos. Por ejemplo:
( ) ,per0
recupera una linea desde el archivo y la divide a1 encontrar un tabulador ( \ t ) . Los resultados se devuelven en una matriz ( $ o r d e r en el ejemplo de c6digo). En un capitulo posterior examinaremos las matrices. El pardmetro de longitud deberia ser mayor que la longitud en caracteres de la linea m i s larga que incluya el archivo que este intentando leer. El pardmetro contenedor se utiliza para especificar por qu6 estd encerrado cada campo en una linea. Si no se especifica, se tomardn las comillas dobles (") como elemento predeterminado. Este pardmetro se agreg6 en PHP 4.3.0.
Lectura de todo el archivo: readfile(), fpassthruo, file() En lugar de leer un archivo linea a linea, podemos leer todo el archivo de una vez. Esta operaci6n se puede realizar de cuatro maneras. La primera utiliza la funci6n r e a d f i l e ( ) . Podemos sustituir la secuencia de comandos entera que escribimos anteriormente por una linea: Una llamada a la funci6n r e a d f i l e ( ) abre el archivo, imprime el contenido de manera esthndar (en el navegador) y cierra el archivo. Su sintaxis es la siguiente: int readfile (string nornbre d? a r c h l v o , int [ u s a r p l n i - l u d e - p a t h ] )
;
El segundo pardmetro ppcimal especifica si PHP deberia buscar el archivo en i n c l u d e p a t h y funciona de la misma forma que f open ( ) . La funci6n devuelve el
numero total de bytes leidos desde el archivo. En segundo lugar, puede utilizar f p a s s t h r u ( ) . Necesitari abrir el archivo utilizando f o p e n ( ) primero. A continuaci6n puede utilizar el puntero del archivo como argument0 hasta f p a s s t h r u ( ) , que eliminard 10s contenidos del. archivo desde la posici6n del puntero hasta la salida e s t h d a r . Cierra el archivo cuando termina. Podemos sustituir la secuencia de comandos anterior por f p a s s t h r u ( ) de la siguiente forma:
La funci6n f p a s s t h r u ( ) devuelve t r u e si la lectura resulta satisfactoria y f a 1 s e en caso contrario. La tercera opci6n para leer el archivo entero consiste en utilizar la funci6n f i l e ( ) . Esta funci6n es idhtica a r e a d f i l e ( ) con la salvedad de que en lugar de imprimir el archivo en la aplicaci6n esthdar, lo convierte en una matriz. Examinaremos esta
Desarrollo Web con PHP y MySQL
opci6n de manera m i s detallada en un capitulo posterior. Simplemente como referencia, se invoca utilizando el siguiente c6digo: Esta linea de c6digo lee el archivo entero en una matriz llamada $ f i l e a r r a y . Cada linea del archivo se almacena en un elemento separado de una matriz. Esta funci6n no es segura para datos binarios. Por ultimo, desde la versi6n PHP 4.3.0 puede utilizar la funcidn f i l e -g e t c o n t e n t s ( ) . Esta funci6n es identica a r e a d f i l e ( ) con la salvedad de que devuelve el contenido de un archivo en forma de cadena en lugar de dirigir la salida al navegador. La ventaja de esta nueva funci6n es que ofrece seguridad binaria, a diferencia de la funci6n file().
Lectura de un car6cter: fget()+ Otra opci6n para procesar un archivo consiste en leerlo caricter a caricter. Para ello, se puede utilizar la funci6n f g e t c ( ) . Esta funci6n toma un punter0 de archivo como dnico parimetro y devuelve el siguiente caracter de un archivo. Podemos sustituir el bucle w h i l e en nuestra secuencia de comandos original por una que utilice f g e t c ( ) : while
( !
f e o f ( $ f p ))
i $char = fgetc($fp); if (!feof($fp)) echo ($char=-"\nu ? '
/ > I :
$char);
1
Este codigo lee un solo caricter del archivo a la vez utilizando f g e t c ( ) y lo almacena en la variable $_chal;hasta que se alcanza el final del archivo. A continuacibn, sustituimos 10s caracteres de final de linea del texto, /n, por saltos de linea, < b r />. El unico objetivo es limpiar el formato. Como 10s navegadores no representan una linea nueva en HTML como tal sin este c6dig0, todo el archivo se imprimiri en una linea (pruebelo). Utilizaremos el operador ternario para realizar esta operaci6n de manera satisfactoria. Un pequefio efecto secundario product0 del uso de f g e t c ( ) en lugar de f g e t s ( ) es que devolveri el caricter E O F mientras que f g e t s ( ) no lo hari. Es necesario probar f e o f ( ) de nuevo tras la lectura del caricter para evitar que se imprima EOF en el navegador. No resulta normal leer un archivo caricter a caricter a menos que queramos procesar cada uno de ellos por alguna raz6n concreta.
Lectura de una longitud arbitraria de bytes: fread() Por ultimo, podemos utilizar la funci6n f r e a d ( ) para leer un numero arbitrario de bytes de un archivo.
2. Almacenamiento y recuperacidn de datos
Su sintaxis es la siguiente: string
freadiint
fp, int
l o n g i tud);
Funciona de la siguiente forma: lee la longitud de bytes que se especifique o hasta llegar a1 final del archivo, segun qu6 sea lo primero.
Otras funciones de archivo utiles Existen otra serie de funciones de archivo que resultan titiles de vez en cuando.
Comprobacidn de la existencia de un archivo: file exists0 Si desea comprobar si un archivo existe sin abrirlo, puede utilizar la funci6n f i 1e-e x i s t s ( ) como se indica a continuaci6n: if [fiLe-exists("$DOCUMENTpROOT/../orders/orders.txt")) echo 'There are orders waiting to be processed.'; e 1s e echo 'There are currently no orders.';
Como averiguar el tamaAo de un archivo: filesize() La funci6n f i l e s i z e ( ) p e r m i t e comprobar el tamafio de un archivo. Esta funci6n devuelve el tamafio del un archivo en bytes: echo
-
-
filesi~e("$DOCUMENT~ROOT/../~rders/orders.txt");
Se puede utilizar en combinaci6n con f r e a d ( ) para leer todo un archivo (o parte de un archivo). Podemos sustituir toda nuestra secuencia de comandos por Sfp = fopen("$DOCUMENT ROOT/../orders/orders.txt", 'r'); echo fread ( $fp, filesize i "$DOCUMENT~ROOT/.. /orders/orders.txt" fclose( Sfp ) ;
) ) ;
Eliminacion de un archivo: unlink() Si desea eliminar un archivo tras procesar 10s pedidos, puede hacerlo con ayuda de la funci6n u n l i n k ( ) . (No existe una funci6n llamada d e 1e t e.) Por ejemplo: Esta funci6n devuelve f a 1 s e si el archivo no se puede eliminar, lo que suele ocurrir si 10s permisos asociados a1 archivo no resultan suficientes o si no existe el archivo.
Dc.snrrollo Web corz P H P y MySQL
Navegaci6n dentro de un archivo: rewind(), fseeko y dtell() Puede manipular y descubrir la ubicacion del puntero del archivo dentro d e un a r c h i v o u t i l i z a n d o r e w i n d ~ ) ,f s e e k ( ) y f t e l l ( ) . La funcion r e w i n d ( ) restablece el puntero del archivo a1 comienzo del archivo. La funci6n f t e l l ( ) indica la distancia a la que se encuetra el puntero dentro del archivo en bytes. Por ejemplo, podemos agregar las siguientes lineas a la parte final de nuestra secuencia de comandos (antes del comando f c l o s e ( ) ).
1
Customer Orders 15:42, 20th April 4 tires 1 oil 6 spark plugs $434.00 22 Short St, S~nalllowm 15:43,20th April 1 tires 0 oil 0 spark plugs $100.00 33 Main Rd, Newtown 15:43,20th April 0 tires I oil 4 spark plug $26.00 127 Acacia St, Springiield
I
Final position of Ihe file poinicr is 234 ABcr rewind, the position is 0
Figura 2.5. Tras leer 10s pedidos, el puntero apunta al final del archivo, una distancia de 234 bytes. La llamada de retroceso lo establece a la posicion 0, es decir al principio del archivo
La funcion f seek ( ) se puede utilizar para establecer el puntero del archivo en otro punto dentro del archivo. Su sintaxis es la siguiente: Una llamada a f s e e k ( ) establece el puntero f p en un punto desde 10s que desplaza 10s bytes indicados. El parimetro punto de parfida se agreg6 en PHP 4.0.0. Su valor predeterminado es SEEK S E T que es en principio del archivo. Los otros valores posibles son SEEK-CUR (la ubi&ci6n actual del punter0 del archivo) y SEEK-END (el final del archivo). La funcion r e w i n d equivale a llamar a la funcion f s e e k con un desplazamiento 0. Por ejemplo, podemos utilizar f seek ( ) para buscar el registro intermedio de un archivo o para realizar una b k q u e d a binaria. A menudo, si alcanza el nivel de complejidad d e un archivo d e datos en el que necesite realizar este tip0 d e tareas, le resultarii mucho m i s sencillo utilizar una base de datos.
2 . Alrrrncennrnierrto y recuperncidn de dntos
Rlocweo de archivos Imagine una situaci6n en la que dos clientes intenten realizar un pedido d e un prodrrcto a la vez. (Algo que no resulta extrafio, en especial si el volumen d e trifico del sitio Web comienza a tener cierta importancia.) Piense en qu6 ocurriria si LIII cliente llama a la funcion f o p e n ( ) y comienza a escribir, y entonces otro cliente llama a la misma funci6n y t a n ~ b i hescribe. iQu6 contendri a1 final el archivo? i S e r i uno d e 10s pedidos o el otro? 0 algo menos util, como dos pedidos entremezclados. La respuesta depende del sistema operativo, per0 a menudo resulta imposible d e saber. Para evitar problemas como este, se puede utilizar el bloqueo d e archivos. Para implementar este recurso en PHP se utiliza la funci6n f l o c k ( ) . Esta funci611 deberia invocarse tras abrir u n archivo, per0 antes d e que se lea o escriba ningGn dato. Su sintaxis es la siguiente:
Es necesario pasarle un punter0 a1 archivo abierto y un numero que represente el tipo d e bloqueo deseado. Devuelve true si el bloqueo se logra satisfactoriamente y false si no es asi. En la tabla 2.2 se recoge un resumen con 10s valores posibles del parimetro operaciidn. Estos valores cambiaron en la versi6n 4.0.1 d e PHP. En la tabla se recopilan ambos conjuntos d e valores. Tabla 2.2. Valores de operacion de la funcion flock()
Valor de operacibn
SignJficado
LOCK-SH (antes 1)
Bloqueo de lectura. El archivo se puede compartir con otros lectores.
LOCK-EX (antes 2)
Bloqueo de escritura. Es exclusive. El archivo no se puede compartir.
LOCK-UN (antes 3)
Liberar bloqueo existente.
LOCK-NB (antes 4)
Si se agrega el numero 4 a la operacion, se impide que el bloqueo al intentar obtener uno.
Si va a utilizar f l o c k ( ) , tendri que agregarlo a todas las secuencias d e comandos que utilicen el archivo ya que d e lo contrario carecer6 d e valor. f l o c k ( ) no funciona con el sistema d e archivos NFS ni con otros sistemas d e archivos d e red. Tampoco se puede utilizar con sistemas d e archivos antiguos que no admitan bloqueos como FAT. En algunos sistemas operativos se implementa en el nivel d e proceso y n o funcionari correctamente si utiliza un API d e servidor multiproceso.
Desarrollo W e b con PHP y MySQL
Para utilizarlo en el ejemplo, es necesario modificar p r o c e s s o r d e r .p h p de la siguiente forma: = fopen("SD0CUMENT-ROOT/../orders/orders.txt", 'a'); flock(Sfp, LOCK-EX); / / bioquee el archivo para su escritura fwriteiSfp, $outputstring); flock($fp, LOCK-UNI; / / desactive el bloqueo d e escritura f c l o s e ( S f p );
Sfp
.
Tambi6n deberia agregar bloqueos a v i e w o r d e r s p hp: = fopen("SD0CUMENT-ROOT /../orders/orders.txt", Ir1); / / bloquee el archjvo para lectura flock($fp, LOCK-SH); / / lee desde el archivo flockiSfp, LOCK-UN); / / desactive el bloqueo d e lectura fclose1Sfp);
Sfp
Nuestro c6digo resulta ahora mas s6lido per0 no es perfecto. iQu6 ocurrira si dos secuencias de comandos intentan obtener un bloqueo a la vez? Que se crearh una carrera en la que 10s procesos competirhn por conseguir bloqueos sin saber qui6n lo lograrh primero, lo que puede ser fuente de mas problemas. Lo mejor es un utilizar un DBMS.
La opcion mas acertada: 10s sistemas de adrninistracion de base de datos Hasta el momento todos 10s ejemplos vistos utilizan archivos planos. En la siguiente secci6n examinaremos c6mo utilizar MySQL, un sistema de administraci6n de bases de dafos raacional. Es posible que se est6 preguntando por qu6 molestarse en recurrir a este sistema.
Problemas con el uso de archivos planos El uso de archivos planos plantea una serie de problemas: Cuando un archivo supera un determinado tamaiio, el trabajo se ralentiza. La busqueda de un determinado registro o de un grupo de ellos resulta dificil dentro de un archivo plano. Si 10s registros estan ordenados, puede utilizar algun tip0 de busqueda binaria en combinaci6n con un registro de ancho fijo para buscar sobre un campo clave. Si desea buscar patrones de informaci6n (por ejemplo, para extraer todos 10s clientes que viven en una determinada ciudad), tendrh que leer cada registro y comprobarlo de manera individual.
2 . Alrnacenamiento y recuperacidn de datos
Los accesos simultdneos pueden resultar dificiles de solucionar. Ya hemos visto cdmo bloquear archivos, pero este mecanismo puede dar lugar a una carrera entre procesos. Tambi6n pueden dar lugar a cuellos de botella. En determinados niveles de trdfico, puede ocurrir que un grupo grande de usuarios tenga que esperar a que se desbloquee el archivo para poder realizar.un pedido. Si la espera es muy larga, se irdn a comprar a otra parte. El procesamiento de archivos que hemos visto hasta el momento es de tip0 secuencial, es decir, partimos del principio del archivo y lo leemos progresivamente hasta llegar a1 final. Si queremos insertar o eliminar registros de la parte central del archivo (acceso aleatorio), la operacidn resultard complicada ya que serd necesario leer todo el archivo en memoria, realizar 10s cambios y volver a escribir el archivo completo. Si el archivo de datos es grande, la carga serd significativa. Aparte de las funciones que ofrecen de 10s permisos de archivos, no existe una forma sencilla de aplicar diferentes niveles de acceso a datos.
Como resolver estos problemas Los sistemas de administracidn de bases de datos dan una respuesta a todos estos problemas: Los RDBMS proporcionan acceso mds rdpido a 10s datos que 10s archivos planos. MySQL, el sistema de base de datos que utilizaremos en este libro, es uno de 10s mds rdpidos. Resulta sencillo consultar 10s RDBMS para extraer conjuntos de datos que se correspondan con deterGnados criterios. Los RDBMS incorporan mecanismos integrados para resolver el problema de 10s accesos simultdneos para que 10s programadores no tengan que preocuparse. Los RDBMS proporcionan acceso aleatorio a 10s datos. Los RDBMS incorporan sistemas de privilegios. MySQL dispone de funciones especiales en este sentido. Probablemente, la razdn principal para utilizar un RDBMS es que implementan todas las funciones (o a1 menos la mayor parte de ellas) que se desean para un sistema de almacenamiento. Puede escribir su propia biblioteca de funciones de PHP, per0 ipor qu6 tomarse esa molestia? En la segunda parte de este libro, se analizard el funcionamiento general de las bases de datos y cdmo configurar MySQL para crear sitios Web dotados debases de datos.
Desarrollo Web con P H P y MySQL
Lecturas adicionales En un capitulo posterior veremos c6mo interactuar con 10s sistemas de archivos. En concreto, se indicari c6mo cambiar permisos, derechos y nombres de archivos, c6mo trabajar con directorios y c6mo interactuar con el entorno del sistema de archiVOS. Tambih puede consultar la secci6n dedicada a1 sistema de archivos del manual enlinea de P H P e n h t t p : //www.php. n e t / f i l e s y s t e m .
A continuacion En el siguiente capitulo, analizaremos las matrices y c6mo utilizarlas para procesar datos en secuencias de comandos PHP.
En este capitulo se explica c6mo utilizar una importante estructura de programaci6n: las matrices. Las variables que hemos visto en 10s capitulos anteriores s610 almacenan un valor. Una matriz es una variable capaz de almacenar un conjunto o secuencia de valores. Una matriz puede constar de una gran cantidad de elementos. Cada elemento puede albergar un unico valor, como texto o numeros, u otra matriz. Las matrices que contienen otras matrices se conocen como matrices multidimensio-nales. PHP admite matrices indexadas numericamente y matrices asociativas. Es probable que este familiarizado con las matrices indexadas numericamente si ha utilizado algun lenguaje de programaci6n, pero si no ha programado nunca en PHP o en Per1 es muy probable que no conozca las matrices asociativas. Estas matrices permiten utilizar valores mfis 6tiles como indice. Las matrices asociativas permiten asociar a cada elemento palabras u otro tip0 de informaci6n con significado en lugar de indices numericos. En este capitulo retomaremos el ejemplo de la aplicaci6n Bob's Auto Parts y utilizaremos matrices para facilitar el trabajo con informaci6n repetitiva como 10s pedidos de 10s clientes. Asi mismo, escribiremos c6digo mfis breve y claro para realizar parte de las tareas desarrolladas en el capitulo anterior. Nos centraremos en 10s siguientes aspectos: Matrices indexadas numericamente Matrices asociativas Matrices multidimensionales Ordenaci6n de matrices
3 . Uso de matrices
iQuC es una matriz? En un capitulo anterior vimos las variables escalares. Una variable escalar es una ubicaci6n con nombre en la que se almacena una variable; de manera similar, un matriz es una ubicaci6n con nombre para almacenar un conjunto de valores, que, por tanto, permite agrupar variables escalares. Utilizaremos la lista de productos de Bob para crear la matriz de nuestro ejemplo. En la figura 3.1 se puede ver una lista de tres productos almacenados en formato de matriz y una variable, denominada $ p r o d u c t s , que contiene tres valores. (En un instante explicaremos cdmo crear un variable como &a).
Tires
Oil
product0
Spark Plugs
*
Figura 3.1. Los productos de Bob se pueden almacenar en una matriz
Tras colocar la informaci6n en una matriz, podemos trabajar con ella de varias formas utiles. Si utilizamos la estructura de bucle vista en un capitulo anterior, podemos ahorrar trabajo aplicando las mismas acciones a cada valor de la matriz. Podemos trasladar todo el conjunto de informaci6n de un sitio a otro como si se tratara de una unidad. De esta forma, bastari con una sola linea de c6digo para pasar todos 10s valores a una funci6n. Por ejemplo, podriamos ordenar todos 10s productos alfabeticamente pasindoselos a la funci6n s o r t ( ) de PHP. Los valores almacenado? en ups matriz se denominan elementos de matriz. Cada elemento de matriz lleva asociado un indice (tambien denominado clave) que se utiliza para acceder a1 elemento. Las matrices de la mayor parte de 10s lenguajes de programaci6n constan de indices numericos que suelen comenzar en cero o en uno. PHP admite este tip0 de matrices. PHP tambidn admite matrices asociativas con las que estarin familiarizados 10s programadores de Perl. Estas matrices pueden utilizar pricticamente cualquier valor como indice de matriz, sobre todo cadenas. Comenzaremos por examinar las matrices indexadas numericamente.
Matrices indexadas numericamente La mayor parte de 10s lenguajes de programaci6n permite el uso de las matrices indexadas numericamente. En PHP, 10s indices comienzan en cero de manera predeterminada per0 se puede variar este parimetro.
Desarrollo W e b con P H P y MySQL
Inicializacion de matrices indexadas numkricamente Para crear la matriz ilustrada en la figura 3.1, utilice la siguiente linea de c6digo de PHP: $products
=
array(
'Tires',
O i l ,
'Spark
Plugs'
);
Esta linea de c6digo crea una matriz llamada p r o d u c t s que contiene 10s tres valores dados 'Tires', 'Oil' y 'Spark Plugs'. Como en el caso de la instruction e c h o , a r r a y ( ) es miis una unidad estructural del lenguaje que una funci6n. Puede que no necesite inicializar manualmente 10s elementos de una matriz como en el siguiente ejemplo. Todo depende de 10s contenidos de la matriz. Si tiene 10s datos que necesita en otra matriz, puede copiarlos utilizando el operador =. Si quiere almacenar una secuencia ascendente de numeros en una matriz, puede utilizar la funci6n r a n g e ( ) para crear la matriz automiiticamente. La siguiente linea de c6digo crearii una matriz denominada n u m b e r s cuyos elementos son 10s 10 primeros numeros. $numbers
=
r a n g e ( 1 , l O );
Si tiene la information almacenada en un archivo del disco duro, puede cargar 10s contenidos directamente del archivo, como veremos en un secci6n posterior. Si 10s datos destinados a la matriz se almacenan en una base de datos, puede cargar sus contenidos directamente desde la base de datos, como veremos en un capitulo posterior. T a m b i h puede utilizar varias funciones para extraer parte de una matriz o para volver a ordenarla. En una secci6n posterior veremos parte de estas funciones.
Acceso a 10s coplteiiidos de matrices Para acceder a 10s contenidos de una matriz, utilice su nombre. Si la variable es una matriz, utilice el nombre de variable o el indice para acceder a 10s contenidos. La clave o el indice indican a qu6 valores almacenados accedemos. El indice se coloca entre corchetes tras el nombre. Escriba $ p r o d u c t s [ O ] , $ p r o d u c t s [I]y $ p r o d u c t s [ 2 I para utilizar 10s contenidos de la matriz de productos. El primer elemento de la matriz es el elemento cero. Se trata del mismo sistema de numeraci6n utilizado en C, C++, Java y otros lenguajes, per0 puede que a1 principio le cueste acostumbrarse a 61. Como ocurre con otras variables, para cambiar 10s contenidos de 10s elementos de matriz se utiliza el operador =. La siguiente linea sustituirii el primer elemento de la matriz, ' T i r e s I, por F u s e s I. $products [0]
=
'Fuses';
3. Uso de matrices
La linea que se incluye a continuaci6n podria utilizarse para agregar un nuevo elemento ( ' FUS e s ' ) a1 final de la matriz, lo que nos da un total de cuatro elementos: $products[3]
=
'Fuses';
Para mostrar 10s contenidos, podriamos escribir: echo
"$products[O]
$products[l]
$products[2]
$products[3]";
Tenga en cuenta que aunque el an6lisis de cadenas que realiza PHP es bastante inteligente, puede que resulte un poco confuso. Si tiene problemas porque las matrices u otras variables no se interpretan correctamente a1 encerrarlas entre comillas dobles, puede colocarlas fuera de las comillas. La instrucci6n e c h o anterior funcionar6 correctamente, per0 en gran parte de 10s ejemplos posteriores, de mayor complejidad, no se utilizan cadenas con comillas. Como ocurre con otras variables de PHP, no es necesario inicializar las matrices o crearlas por adelantado ya que se crean automtiticamente la primera vez que se utilizan. El siguiente c6digo crear6 la misma matriz $ p r o d u c t s : $products [O] $products[l] $products[2]
= = =
'Tires'; 'Oil'; 'Spark Plugs';
Si la matriz $ p r o d u c t s no existiera todavia, la primera linea crearia una nueva matriz con un ~ n i c o elemento y las siguientes lineas agregarian valores a la matriz.
Uso de bucles para acceder a la matriz Como la matriz se indexa a partir de una secuencia de n ~ m e r o spodemos , utilizar un bucle f o r para mostrar las contenidos de manera m6s sencilla. for
( $i = 0; $i<3; $it+ ) echo "$products [$i] ";
Este bucle produce resultados similares a1 c6digo anterior, per0 exige menos trabajo ya que no es necesario escribir c6digo para trabajar con cada elemento de una matriz. Una de las caracteristicas destacadas de las matrices indexadas es la posibilidad de utilizar un sencillo bucle para acceder a cada uno de sus elementos. En el caso de matrices asociativas no resulta tan sencillo utilizar bucles para recorrerlas, per0 permiten usar indices con valores significativos. Tambien podemos recurrir el bucle f o r e a c h que estd especialmente disefiado para su uso con matrices. En este ejemplo podemos utilizarlo de la siguiente forma: foreach ($products as $current) echo $current.' ' ;
Este c6digo almacena elemento a elemento en la variable $ c u r r e n t y 10s imprime.
Matrices asociativas En la matriz de productos, permitimos que PHP asigne a cada elemento el indice predeterminado. Esto significa que el primer elemento que agregamos se convierte en 0, el segundo en 1y asi sucesivamente. PHP admite el uso de matrices asociativas. En una matriz asociativa, podemos asociar cualquier clave o indice que deseemos a un valor.
Inicializacion de una matriz asociativa El siguiente c6digo crea una matriz asociativa utilizando 10s nombres de productos y 10s precios como valores. $prices
=
array( 'Tires'=>100, 'Oil'=>10, 'Spark Plugs1==>41 ;
Como acceder a elementos de matriz De nuevo, utilizamos el nombre de la variable y una clave para acceder a 10s contenidos. De esta forma podemos acceder a la informaci6n almacenada en la matriz de precios como $ p r i c e s [ ' T i r e s ' 1, $ p r i c e s [ ' O i l ' ] y $ p r i c e s [
' Spark
Plugs
' 1.
Como en el caso de las matrices indexadas, las matrices asociativas se pueden crear e inicializar elemento a elemento. El siguiente fragment0 de c6digo crea la misma matriz $ p r i c e s . En lugar de crear una matriz con tres elementos, esta versi6n crea una matriz con un unico elemento y, a continuaci611, crea dos m6s.
-
$prices = array( 'TireC'=>100 $prices['Oil'] = 10; $prices['Spark Plugs'] = 4;
);
Aqui tambien existe una pequeiia diferencia, aunque el c6digo sea equivalente. En esta versi611, no creamos una matriz de manera explicita sin0 que se crea automdticamente a1 agregarle el primer elemento. $prices ['Tires'] = 100; $prices ['Oil'] = 10; $prices['Spark Plugs'] = 4;
Uso de bucles con matrices asociativas Como 10s indices de esta matriz asociativa no est6n formados por ntimeros, no podemos incluir u n simple contador dentro de bucle f o r para que funcione con la matriz. Podemos utilizar el bucle f o r e a ch o las instrucciones 1i s t ( ) y e a c h ( ) . El bucle f o r e a c h presenta una estructura ligeramente diferente cuando se utiliza
3 . Uso de rnntrices
con matrices asociativas. Podemos usarlo tal y como hicimos en el ejemplo anterior o incorporar las claves: foreach echo
( S p r i c e s as $ k e y =) $value) $ k e y . '=-,' . $ v a l u e . ' i b r / > I ;
El siguiente c6digo devuelve 10s contenidos d e la matriz $ p r i c e s utilizando Ia instruccion e a c h ( ) :
El resultado de este fragment0 de c6digo se muestra en la figura 3.2. En un capitulo anterior, vimos 10s bucles w h i l e y la instrucci6n e c h o . El c6digo anterior utiliza la funci6n e a c h ( ) ,que no se ha visto todavia. Como estamos llamand o a e a c h ( ) dentro de un bucle w h i l e , 10s elementos de la matriz se devolverAn uno a uno y se detendri a1 alcanzar el final d e la matriz.
I
I
-
Tires 100 Oil - 10 Spark Plugs - 4
Figura 3.2. Se puede utilizar una instruccion each() para recorrer matrices
En este codigo, la variable $ e l e m e n t es una matriz. A1 llamar a e a c h ( ), nos devuelve una matriz con cuatro valores y 10s cuatro indices hasta las ubicaciones d e matriz. Las ubicaciones k e y y 0 contienen la clave del elemento actual y las ubicaciones v a l u e y 1contienen el valor del elemento actual. Aunque da igual cuAl se escoja, en nuestro ejemplo hemos optado por utilizar las ubicaciones con nombre en lugar de las ubicaciones con n ~ m e r o . Existe una forma mAs habitual y elegante de realizar esta tarea. Podemos utilizar la funci6n l i s t ( ) para dividir una matriz en un ndmero de valores y separar 10s dos valores que nos proporciona la funci6n e a c h ( ) de la siguiente forma: Slistl
$product,
$price
)
=
eachl
Sprices
i;
Esta linea utiliza e a c h ( ) para tomar el elemento actual desde $ p r i c e s , lo devuelve en forma d e una matriz y convierte al siguiente elemento en el actual.
Dcsarrolln Web coil P H P y MySQL
Tambi6n utiliza la funci6n l i s t ( ) para convertir 10s elementos 0 y 1de la matriz devueltos por each ( ) en dos nuevas variables llamadas $ p r o d u c t y $ p r i c e . Podemos utilizar u n bucle para recorrer la matriz $ p r i c e s entera y mostrar 10s resultados utilizando esta breve secuencia d e comandos. w h i l e ( l i s t ( Sprnduct, S p r i c e ~ c h u "$product - $pric?.:.hr
)
=
each(
Sprices
)
)
/'i";
El resultado de este codigo es el mismo que el generado por la secuencia de comandos anterior, per0 resulta m6s sencilla d e leer porque la instrucci6n l i s t ( ) permite asignar nombres a las variables. Una cosa en la que fijarse a1 utilizar e a c h ( ) es que la matriz realiza el seguimiento el elemento actual. Si queremos utilizar la matriz dos veces en la misina secuencia d e comandos, debemos reestablecer el elemento actual a1 principio d e la matriz utilizando la funci6n r e s e t ( ) . Para recorrer la matriz de precios de nuevo con ayuda de un bucle, utilice el siguiente cbdigo:
Este codigo restablece el elemento actual a1 principio d e la matriz y nos permite recorrerla d e nuevo.
Matrices muitidimensiona~es Las matrices no tienen por qu6 estar formadas por una simple lista d e claves y valores ya que cada ubicaci6n de la matriz puede contener otra matriz. De esta forma podemos crear una matriz de dos dimeiisiones. Para hacerse una idea del concept0 d e las matrices bidimensionales, piense en ellas como una tabla, o cuadricula, con altura y anchura o con filas y columnas. Si queremos almacenar mi5s de un dato de cada producto de Bob, podemos utilizar una matriz bidimensional. La figura 3.3 muestra 10s productos d e Bob en una matriz bidimensional en la que cada fila representa un producto y cada columna un atributo de producto.
Code
Description
Price
TIR
Tires
100
OIL
Oil
10
SPK
Spark Plugs
4 r
atributo de producto
Figura 3.3. Podemos almacenar mas informacion sobre 10s productos de Bob en una matriz bidimensional
3. Uso de matrices
Utilizando PHP podriamos escribir el siguiente c6digo para configurar 10s datos de la matriz que se muestra en la figura 3.3. $products
a r r a y ( a r r a y ( 'TIR', a r r a y ( 'OIL', a r r a y ( 'SPK',
=
' T l r e s ' , 100 ) , 'Oil', 10 ), 'Spark Plugs', 4
)
);
En esta definici6n puede ver que la matriz de productos contiene ahora tres matrices. Para acceder a 10s datos de una matriz unidimensional, recuerde que necesitamos el nombre de la matriz y el indice del elemento. En una matriz bidimensional la operaci6n es similar con la salvedad de que cada elemento consta de dos indices, una fila y una columna. La fila superior es la fila 0 y la columna situada m i s a la izquierda es la columna 0. Para visualizar 10s contenidos de esta matriz, podriamos acceder manualmente a cada elemento de la siguiente forma: I ' .$products ' I ' .$products I ' .$products
echo echo echo
1
[ O ] [O]
.' I ' .$products [Ol
[ l ][ O ] . ' 1 [2] [0] .' I
' '
[I].' 1 .$products [ l l I l l . ' l . $ p r o d u c t s [ 2 ] [ I ] .' 1
121 . ' l < b r I>'; [21. ' l I ; . $ p r o d u c t s [ 2 1 [21 . ' l < b r / > I ;
' . S p r o d u c t s I01 ' .$products [ l l
'
Tambien podemos colocar un bucle for dentro de otro bucle for para obtener el mismo resultado. for
$row
(
0;
=
$row
< 3; S r o w t t
)
t for
(
$column
=
0;
$column
< 3; $column++
)
i echo
' I ' .$products [$row] [$column];
I echo
' < b r
1
/ > I ;
-
*
Ambas versiones generan el mismo resultado en el navegador.
La Linica diferencia entre 10s dos ejemplos es que el c6digo seri m i s breve si utiliza la segunda versi6n con una matriz de gran tamaiio. Si lo prefiere puede crear nombres de columna en lugar de nLimeros, como se ilustra en la figura 3.3. Para ello, puede utilizar matrices asociativas. Para almacenar el mismo conjunto de productos, con columnas con nombre como las de la figura 3.3, se utiliza el siguiente c6digo: $products
=
a r r a y ( a r r a y ( C o d e => ' T I R ' , D e s c r i p t i o n => P r i c e => 1 0 0 r
'Tires',
Desarrollo W e b con PHP y MySQL array( Code => 'OIL', Description => 'Oil', Price => 10 )
I
array ( Code => 'SPK', Description => 'Spark Plugs', Price = > 4 ) );
Resulta mds sencillo trabajar con esta matriz si s610 se desea recuperar un valor
y es mds sencillo recordar que la descripci6n almacenada e n la columna D e s c r i p t i o n que recordar que estd almacenada en la columna 1. El uso de matrices asociativas evita tener que memorizar que se ha almacenado un articulo en [x][y]. Es f6cil encontrar 10s datos utilizando la referencia a una ubicaci6n utilizando nombres de fila y columna significativos. Sin embargo, perderemos la posibilidad de utilizar un sencillo bucle f o r para recorrer cada columna. Una forma de escribir c6digo para mostrar esta matriz es la siguiente: for
$row
(
0; $row c 3; $row++
=
)
I
echo 'I'.$products[$row! ['Code'l.'~'.$products[$raw]['Description']. '.$pruducts[$row]['Price'].'l I ;
El uso de un bucle f o r permite recorrer la matriz externa $ p r o d u c t s , numkricamente indexada. Cada fila de la matriz $ p r o d u c t s es un matriz asociativa. Podemos utilizar las funciones e a c h ( ) y li s t ( ) en un bucle w h i l e para recorrer matrices asociativas. Por lo tanto, necesitamos utilizar u n bucle w h i l e dentro de un bucle f o r : for
(
$row
=
0; $raw < 3;-$row++
)
I
while i list( $key, $value
)
=
each( $products[ $row
]
)
)
I
echo "I$value"; echo 'l
/ > I ;
1
No tenemos por qu6 limitarnos a dos dimensiones. De la misma forma que 10s elementos de las matrices pueden contener otras matrices, esas nuevas matrices pueden contener a su vez otras. Una matriz tridimensional tiene altura, anchura y fondo. Si el simil de las matrices bidimensionales como tablas con filas y columnas le ayud6 a imaginarselas, piense en las matrices tridimensionales como un conjunto apilado de tablas. Para hacer referencia a cada elemento, se utilizard la capa, la fila y la columna. Si Bob dividiera sus productos en categorias, podriamos utilizar una matriz tridimensional para almacenarlos. La figura 3.4 muestra 10s productos de Bob en una matriz tridimensional.
710d, g'
-
.?
8
L-
Car Parts
-
Code
Description
Price
CAR-TIR
T~res
100
011
10
CARglL
CAR-SPK
Spark Plugs
-
4
Figura 3.4. Esta rnatriz tridimensional nos perrnite dividir 10s productos en categorias
Si examina el c 6 d i g o q u e define esta matriz, o b s e r v a r 5 q u e u n a m a t r i z tridimensional es una matriz q u e contiene matrices d e matrices. TIR', ' CAF: - 01 L ' , 'CfiR
, i,.h -,, ,
SFK',
ti,^?,<*,
] V
35 1 , , >.r. y ' Fl r k F 1 I. (;I :-: '
j,
'Oil',
,
0
Como esta matriz s610 consta d e indices numkricos, podemos utilizar bucles for anidados para mostrar sus contenidos.
Debido a la forma e n la q u e se crean las matrices multidimensionales, podriamos crear matrices d e cuatro, cinco o seis dimensiones. El lenguaje no tiene limites a este
Desarrollo W e b con P H P y MySQL '
respecto, per0 resulta dificil visualizar estructuras con m i s de tres dimensiones. La mayor parte de 10s problemas del mundo real se corresponden 16gicamente con estructuras de tres o menos dimensiones.
Como ordenar matrices A menudo resulta util ordenar datos relacionados que estkn almacenados en una matriz. Es sencillo tomar un matriz unidimensional y ordenarla.
Uso de sort() El siguiente c6digo da como resultado una matriz que se ordena en orden alfabktico ascendente: $products = a r r a y ( s o r t ( $ p r o d u c t s );
'Tires',
O i l ,
'Spark
Plugs'
);
Los elementos de nuestra matriz quedardn ordenados de la siguiente forma: oil, S p a r k Plugs, T i r e s .
Tambikn podemos ordenar 10s valores numkricamente. Si tenemos una matriz con 10s precios de 10s productos de Bob, podemos ordenarla en sentido ascendente como se muestra a continuation:
Los precios se ordenarin ahora de la siguiente forma: 4,10,100. Tenga en cuenta que la fu?ci6n de ordenaci6n discrimina entre mayusculas y minusculas, y que las letras mayusculas van delante de las minusculas. Por lo tanto, la "A"va antes que "Z", per0 la "Z" va antes que la "a".
Uso de asorto y ksort() para ordenar matrices asociativas Si quisikramos utilizar una matriz asociativa para almacenar articulos y sus precios, necesitariamos utilizar diferentes tipos de funciones de ordenaci6n para mantener agrupadas las claves y su valores a1 ordenarlos. El siguiente c6digo crea una matriz asociativa en la que se incluyen tres productos y sus precios asociados, y ordena la matriz en orden ascendente por 10s precios. Sprizes = array( a s o r t ( $ p r i c e s );
'Tiresl=>lOO,
'Oil'=>10,
'Spark
Plugsf=>3
);
La funci6n a s o r t ( ) ordena la matriz en funci6n del valor de cada elemento. En la matriz, 10s valores son 10s precios y las claves son las descripciones textuales. Si
-
en lugar de o r d e n a ~la matriz por el precio, queremos hacerlo por la descripcidn, se utilizard la funcidn k s o r t ( ) , que ordena la matriz por la clave y no por su valor. Como resultado se ordenardn las claves de la matriz alfabkticamente: Oil, Spark Plugs, Tires. $prices = array( 'Tires'=>100, 'Oil'=>10, 'Spark Plugs1=>4 ksort($prices);
);
Inversion del orden Hemos visto las funciones s o r t ( ) , a s o r t ( ) y k s o r t ( ) . Estas tres funciones ordenan las matrices en orden ascendente. Pero cada una de ellas tiene una funcidn correspondiente para ordenar las matrices en orden descendente. Estas funciones inversas son r s o r t ( ) , a r s o r t ( ) y k r s o r t ( ) . Las funciones de ordenacidn inversa se utilizan de la misma forma que las funciones d e ordenacidn normales. La funcidn r s o r t ( ) ordena u n matriz unidimensional indexada numkricamente en orden descendente. La funcidn a r s o r t ( ) ordena una matriz asociativa unidimensional en sentido descendente utilizando el valor de cada elemento. La funcidn k r s o r t ( ) ordena una matriz asociativa unidimensional en orden descendente utilizando la clave de cada elemento.
Ordenacion de matrices multidimensionales La ordenacidn de matrices con m6s de una dimensidn o aplicando un orden distinto a1 alfabetico o numkrico resulta m6s complicado. PHP sabe cdmo comparar dos nLimeros o dos cadenas de texto,gero en una matriz multidimensional cada elemento de una matriz es otra matriz. PHP no sabe cdmo comparar dos matrices, por lo que es necesario crear un metodo para compararlas. En la mayor parte de las ocasiones, el orden de las palabras o nLimeros resulta bastante obvio per0 en el caso de objetos complicados, se convierte en una operacidn m6s problemdtica.
Ordenaciones definidas por el usuario A continuacidn se repite la definicidn de una matriz bidimensional utilizada anteriormente. Esta matriz almacena 10s tres productos que comercializa Bob con un cddigo, una descripcidn y un precio. $products
=
array( array( 'TIR', 'Tires', 100 ) , array( 'OIL', 'Oil', 1 0 ) , array( 'SPK', 'Spark Plugs', 4
)
);
Si ordenamos esta matriz, ique orden se aplicar6 finalmente a 10s valores? Como sabemos que contenidos representan, existen dos posibilidades a1 menos. Podemos
Desarrollo Web con PHP y MySQL
ordenar 10s productos en orden alfabetico utilizando su descripci6n o hacerlo numericamente por su precio. Ambas opciones son posibles, pero necesitamos utilizar la funci6n u s o r t ( ) y decirle a PHP c6mo comparar 10s articulos. Para ello tenemos que escribir nuestra propia funci6n de comparacion. El siguiente c6digo ordena esta matriz en orden alfabetico utilizando la segunda columna de la matriz: la descripci6n. function
compare($x,
$y)
i ( $ x [ l l == S y l l l I r e t u r n 0; else i f ( Sxlll < $y[ll r e t u r n -1; else r e t u r n 1;
i f
Hasta el momento, hemos utilizado varias funciones incorporadas en PHP. Para ordenar esta matriz, hemos definido una funci6n propia. En un capitulo posterior se analizari en detalle la creaci6n de funciones. Las funciones se definen utilizando la palabra clave f u n c t i o n . Es necesario asignar un nombre a la funci6n. Los nombres deberian ser descriptivos. Muchas funciones toman parimetros o argumentos. Nuestra funci6n c o m p a r e ( ) toma dos, uno llamado x y otra llamado y. El objetivo de esta funci6n es tomar dos valores y determinar su orden. En este ejemplo, 10s parametros x e y serin dos matrices dentro de la matriz principal y cada una representari un producto. Para acceder a la descripci6n de la matriz x, escribimos $ x [ 1] porque se trata del segundo elemento de estas matrices y la numeraci6n comienza ensero. Utilizamos $ x [ 1] y $ y [ 1] para comparar las descripciones de las matiices pasadas en la funci6n. A1 final de la funcibn, se puede devolver una respuesta a1 c6digo de llamada. Para devolver un valor, utilizamos la palabra clave r e t u r n . Por ejemplo, la linea r e t u r n 1; devuelve el valor 1 a1 c6digo que invoc6 la funci6n. Para utilizar la funci6n c o m p a r e ( ) con u s o r t ( ) , debemos comparar x e y. La funci6n debe devolver 0 si x es igual a y, un numero negativo si es menor y un numero positivo si es mayor. La funci6n devolveri 0,1, o - 1, segun 10s valores de x e Y. La linea final del c6digo llama a la funci6n incorporada de PHP u s o r t ( ) dentro de la matriz que queremos ordenar ( $ p r o d u c t s ) y el nombre de la funci6n de comparaci6n ( c o m p a r e ( ) ). Si quisikramos ordenar la matriz de otra forma, bastaria con escribir una funci6n de comparaci6n diferente. Para ordenar la matriz por el precio, debemos examinar la tercera columna de la matriz y crear la siguiente funci6n de comparaci6n function
c o m p a r e ($x, $y)
3 . Uso de matrices
if ( $x[21 == Sy121 ) return 0; else i f ( $x[21 < Sy[2] return -1; else return 1;
)
I
A l l l a m a r a u s o r t ( $ p r o d u c t s , compare),lamatrizseordenardenordenascendente por el precio. La "u" de u s o r t ( ) equivale a "usuario" porque requiere una funci6n de comparaci6n definida por el usuario. Las versiones u a s o r t ( ) y u k s o r t ( ) de a s o r t y k s o r t tambien requieren una funci6n definida por el usuario. A1 igual que a s o r t ( ) , la funci6n u a s o r t ( ) deberia utilizarse a1 ordenar una matriz asociativa por su valor. Utilice a s o r t si 10s valores son numeros o texto. Defina una funci6n de comparaci6n y utilice u a s o r t ( ) si 10s valores son objetos mds complicados que las matrices. A1 igual que k s o r t ( ) , u k s o r t ( ) deberia utilizarse para ordenar una matriz asociativa por su clave. Utilice k s o r t ( ) si sus claves son numeros o texto. Defina una funcion de comparacidn y utilice u k s o r t ( ) si sus claves son objetos m6s complicados que matrices.
Ordenaciones de usuario inversas s o r t ( ) ,a s o r t ( ) y k s o r t ( ) tienen funciones inversas que se establecen colocando una "r" delante del nombre de la funci6n. Las ordenacionei definidas por el usuario no disponen de variantes inversas, per0 se puede ordenar una matriz multidimensional en orden inverso. Para ello, bastard con escribir una funci6n de comparaci6n que devuelva 10s valores al reves. Para ordenar una matriz en orden inverso, la funcion tendra que devolver 1 si x es menor que y y - 1 si x es mayor que y. Por ejemplo: function
-
-
reverseCompare($x,
$y)
{
if
( $x[2] == $y[2] ) return 0; else if ( $x[21 < $y[21 return 1; else returrt -1;
)
I
La funci6n u s o r t ( $ p r o d u c t s , r e v e r s e c o m p a r e ) dard como resultado una matriz en orden descendente por el precio.
Reordenacion de matrices En algunas aplicaciones puede que necesitemos manipular el orden de las matrices de varias formas. La funci6n s h u f f l e ( ) reordena de manera aleatoria 10s
Desarrollo W e b con P H P y MySQL
elementos de la matriz. La funcidn array reverse ( ) devuelve una copia de la matriz con todos 10s elementos en brden inverso.
Uso de shuffle() Bob quiere destacar un n6mero reducido de sus productos en la pfigina principal del sitio. El ntimero de productos que comercializa es grande, per0 quiere seleccionar tres productos de manera aleatoria para que aparezcan en la pfigina principal. Su intencidn es que 10s visitantes que vuelvan a1 sitio vean algo diferente en cada visita y no se aburran. Resultaria muy sencillo conseguir este objetivo si todos 10s productos se incluyeran en una matriz. El listado 3.1 muestra tres imfigenes seleccionadas de manera aleatoria. Para ello, se aplica un orden aleatorio a 10s elementos de la matriz y se muestra el primer0 de 10s tres articulos. Listado 3.1. bobs-front-page.php. Uso de PHP para generar una pagina principal dinamica en el sitio Bob's Auto Parts
=
a r r a y ( ' t i r e . j p g l , ' o i l . j p g V , 'sparkPplug.jpgl, 'daar.jpg', 'steering-wheel. jpg', 'thermostat.jpg', 'wiper blade. jpg', 'gasket.jpq', 'brake pad. jpg');
srand ( (float)microtime()*l000000); shuffle($pictures); ?>
Bobls Auto Parts Bobls Auto Parts
-
-
i echo '
i echo 'No orders pending. Flease try again later. ';
1 echo "\nu; echo ''; for i $ 1 = 0 ; SiiSnumber-of-orders; $it+)
i //divida cada linea $1 ine = explode ( "\tn , $orders [$i] ) ; / / Mantenga ordenado ~Gr~Lcamente el nhmero d e articulos $line [l] = intvai ( $line [l] ) ; $line [2] = intval ( $line [2] ) ; $line [3] = intval ( $line [3] ) ; / / muestre cada pedido echo "Order Date | Tires | Oil | Spark PI ugs | Total | A d d r e s s . : / t h > |
---|
$line[O] | $line [1]i/td> | $lir~e[2]i/td> | $lir~e[3]i/td> |
I echo " | "; ?>
El codigo del listado 3.3 carga el archivo completo en una matriz per0 a diferencia del ejemplo del listado 3.2, aqui utilizamos la funcion e x p l o d e ( ) para dividir cada linea para poder procesar y aplicar formato antes de impresi6n.
Desarrollo Web coil P H P y MySQL
En la figura 3.6 se ilustra el resultado d e esta secuencia d e coniandos. La funcion e x p l o d e tiene la siguiente sintaxis:
I
m
& c h w Ed#u&n Ver Famdas Herramtentas A y d a
I/Customer Orders r -
-- - -
Order Date
~ire;,%
15 42, 20lh ApllI '15 43,201h April
4
i$GiZii&i r T z !
Address
1 6 $434 00 22 Shod St, Smalltown 1 -0 - - -0 $100 00 33 M& Rd. ~ e S & v n 115.43,2 0 1 h ~ ~ 1 l l ~ 6 r l 4 826 00 127-AcactaSI, Springfield
-
.
-
--
-
.
I
-I
_
Figura 3.6. Tras dividir 10s registros del pedido con la funcion explode, podemos colocar cada seccion del pedido en una celda de tabla diferente para mejorar su aspect0
En el capitulo anterior, utilizamos el carficter d e tabulacidn como delimitador a1 almacenar estos datos. Por ello, aqui llamanios a: Este cddigo divide las cadenas pasada en partes. Cada cariicter d e tabulacion separa 10s elementos. Por ejemplo, la cadena
se divide en "15:42, 20th April", "4 tires", "1 oil", "6 spark plugs", "$434.00" y "22 Short St, Smalltown". Fijese eg que el parimetro opcional liruite se puede utilizar para restringir el nlimero mfiximo d e partes devueltas. En este cddigo no se ha realizado una gran cantidad de operaciones de procesamiento. En lugar d e devolver 10s articulos en cada linea, s610 mostramos el numero de cada uno y agregamos una fila de encabezados para mostrar qu6 representan. Existen varias formas de extraer numeros de estas cadenas. En este caso, hemos utilizado la funcidn i n t v a l ( ) . Como se menciono en un capitulo anterior, i n t v a l ( ) convierte una cadena en un entero. El proceso d e conversi6n resulta razonablemente inteligente e ignorarfi partes, como la etiqueta d e este ejemplo, que no se pueden convertir en un entero. En el siguiente capitulo abordaremos varias formas de procesar cadenas.
Hasta el momento, s610 hemos analizado aproximadamente la mitad d e las funciones disponibles para el procesamiento d e matrices. Existen otras muchas que resultarin d e utilidad de vez en cuando.
3. Uso de matrices
Navegacion dentro de una matriz con each(), Ya mencionamos anteriormente que todas las matrices constan de un puntero interno que apunta a1 elemento actual de la matriz. Ya se utilizd antes este puntero indirectamente con la funcidn e a c h ( ) ,per0 podemos utilizarlo directamente y manipularlo. Si crea una nueva matriz, el puntero actual se inicializarii con el puntero a1 primer elemento de la matriz. Si llamamos a c u r r e n t ( Snombre -m a t r i z ) se devolverii la primer elemento. Si llamamos a n e x t ( ) o a e a c h ( ) , el puntero avanzard un elemento. Si llamamos a e a c h ( Snombre mat r i z ) , se devuelve el elemento actual antes de que el puntero avance. La fun& n e x t ( ) se comporta de manera ligeramente diferente: si llamamos a n e x t ( Snombre -mat r i z ) ,el punter0 avanzarii y devolverii el nuevo elemento actual. Ya hemos visto que r e s e t ( ) devuelve el puntero a1 primer elemento de la matriz. De manera similar, si llamamos a e n d ( $nomb re-ma t r i z ) ,el puntero se enviarii a1 final de la matriz. r e s e t ( ) y end ( ) devuelven el primer y el dtimo elemento de la matriz, respectivamente. Para recorrer una matriz en orden inverso, podemos utilizar e n d ( ) y p r e v ( ) . La funcidn p r e v ( ) es la opuesta a la funcidn n e x t ( ) . Mueve el puntero actual un puesto hacia atriis y devuelve el elemento actual. Por ejemplo, el siguiente cddigo muestra una matriz en orden inverso: $value = end ($array); while ($value)
t echo "Svaluecbr / > " ; Svalue = prev($array);
I
Si $ a r r a y se declararade laiguiente forma: $array
=
arrayil, 2, 3);
El resultado se mostraria en el navegador de la siguiente forma:
Eluso d e e a c h ( ) , c u r r e n t ( ) , r e s e t ( ) , e n d ( ) , n e x t ( ) , p o s ( ) y p r e v ( ) nos permite escribir nuestro propio cddigo para navegar a traves de una matriz en cualquier orden.
Aplicacidn de cualquier funcion a cada elemento de una matriz: array-walk() En ocasiones, puede que necesitemos trabajar o modificar cada elemento de un matriz de la misma forma. Para ello, podemos utilizar la funcidn a r r a y-walk:
Desarrollo W e b con PHP y MySQL
La sintaxis de esta funci6n es la siguiente: int array-walkiarray mat, st ring func, [mixed datos-de
-
usuario] )
De manera similar a como hicimos anteriormente a1 llamar a u s o r t ( ) , la funci6n a r r a y walk ( ) espera que declaremos una funci6n propia. Como pu
myPrint($value)
t echo "$value " ;
1 array-walkisarray,
'myprint');
La funci6n debe tener una firma especial. Para cada elemento de la matriz la funcion a r r a y wa 1k toma la clave y el valor almacenado en la matriz y todo lo que pase como datoxde-usuario, y llama a la funci6n de la siguiente forma: Sufunci6n(valor,
clave,
d a t o s-d e u s u a r i o ) -
En la mayor parte de 10s casos, la funci6n so10 utilizard 10s valores de la matriz. En algunos casos, puede que tambi6n necesite pasar un pardmetro a la funci6n utilizando el pardmetro datos-de-usuario. En ocasiones puede que est6 interesado en la clave de cada elemento asi como en'su valor. Como en el caso de My P r i n t ( ) ,la funcidn puede optar por ignorar la clave y el pardmetro datos-de-usuario. Podemos escribir un ejemplo un poco mds complicado, en el que una funcidn modifique 10s valores de las matrices y necesite un pardmetro. Fijese en que a pesar de no estar interesados en la clave, tenemos que aceptarla para poder aceptar el tercer pardmetro. function
i
myMultiply(&$value,
$key,
Sfactor)
$value * = Sfactor;
En este ejemplo, se define una funcibn, myMultiply ( ) , que multiplicard cada elemento de la matriz por un factor suministrado. Necesitamos utilizar el tercer pariimetro opcional de array-wal k ( ) para tomar un pardmetro que pasar a nuestra funci6n y utilizarlo como factor por el que multiplicar. Como necesitamos este pardmetro, podemos definir la funci6n myMu 1t i p 1y ( ) para que tome tres
3. Uso d t nzntriccs
parimetros: u n valor d e elemento d e matriz ( $ v a l u e ) , una clave d e elemento d e matriz ( $ k e y ) y otro parimetro ( S f a c t o r ) . Vamos a optar por ignorar la clave. Un punto sutil en el que fijarse es la forma d e pasar $ v a l u e . El simbolo & colocado delante del nombre d e la variable en la definici6n d e m y M u l t i p l y ( ) significa que $ v a l u e se pasar6 por referencia. Este modo d e pasar variables permite que la funci6n modifique 10s contenidos d e la matriz. Analizaremos este mod0 en un capitulo posterior. Por el momento, fijese simplemente en que a1 pasar por referencia se utiliza un simbolo & delante del nombre d e la variable.
C6mo comhr elememtos de una matriz: count(), sizeof(), and arrav, -count-values() En u n ejemplo anterior utilizamos la funci6n c o u n t ( ) para contar la cantidad d e elementos d e una matriz d e pedidos. La funci6n s i z e o f ( ) tiene el mismo objetivo. Ambas funciones devuelven el numero d e elementos d e una matriz que se le han pasado. Obtendremos 1para el n6mero d e elementos e n una variable escalar normal y 0 si pasamos una matriz vacia o una variable que no se haya establecido. La funcion a r r a y - c o u n t - v a 1 u e s ( ) e s m6s compleja. Si llama a a r r a y - c o u n t - v a l u e s ( $ a r r a y ) , esta funci6n contar6 el numero d e veces que tiene lugar cada valor unico en la matriz $ a r r a y . (Se determina por la cardinalidad d e la matriz). La funcion devuelve una matriz asociativa que contiene una tabla d e frecuencia. Esta matriz contiene 10s valores exclusivos d e S a r r a y como claves. Cada clave tiene un valor numeric0 que indica las veces que tiene lugar la clave correspondiente en $ a r r a y . Por ejemplo, el siguiente c6digo:
.
3 d r r ; i y = a r r a y ( 4 , 5 , 1, 2 , $,I,-:
=
-
3, 1, 2, 1 ) ;
a r r a y - c c , u n t -v a l u e s ( S a r r a y ) ;
crea una matriz llamada S a c que contiene - --
clave
--
-
--
-
valor
Esto indica q u e 4,5 y 3 ocurren una vez en $ a r r y, 1 ocurre tres veces y 2 ocurre dos veces.
Desnrrollo Web con P H P IJ MIJSQL
C o n v e r s i h de matrices en variables escalares: wtract() Si tenemos una matriz asociativa con una serie d e pares d e valor y clave, podemos convertirlas e n u n conjunto d e variables escalares utilizando la funcion extract ().
Esta funcidn tiene la siguiente sintaxis:
El objetivo d e e x t r a c t
()
es tomar una matriz y crear variables escalares con
10s nombres d e las claves d e la matriz. Los valores d e estas variables se establecen en funcidn d e 10s valores d e la matriz. A continuacidn se incluye un ejemplo:
Este c6digo genera el siguiente resultado:
La matriz tiene tres elementos con claves: k e y l , k e y 2 y k e y 3 . La funci6n e x t r a c t ( ) nos permite crear tres variables escalares, $ k e y l , $ k e y 2 y $ k e y 3 . Por el resultado podemos ver que 10s valores d e $ k e y l , $ k e y 2 y $ k e y 3 son 'valuel', 'value2' y 'value3', respectivamente. Estos valores proceden de la matriz original. La funcion e x t r a c t ( ) consta d e dos parametros opcionales: tipo-extraccidn y prefijo. La variable t i p 0 e x t ~ a c c i o nindica a e x t r a c t ( ) c6mo resolver las colisiones. st as tienen lugar cuando ya existe una variable con el mismo nombre que una clave. La respuesta predeterminada consiste en sobrescribir la variable existente. En la tabla 3.1 se recogen 10s valores posibles de este parimetro.
-
.Tabla 3.1. Valores permitidos del parametro tipos-extraccion de la funcion extract()
r--Tipo
Significado
EXTR-OVERWRITE
Sobrescribe la variable existente cuando tiene lugar una colision.
EXTR-SKIP
Salta un elemento cuando tiene lugar una colision.
EXTR-PREFIX-SAME
Crea una variable denominada $ p r e f ix-key cuando tiene lugar una colision. Se debe incluir el parametro pref ij0 .
EXTR-PREFIX-ALL
Coloca delante de todos 10s nombres de variables el valor del p r e f i j o. Se debe incluir el parametro p r e f i j o.
Tipo
Significado
EXTR-IF-EXISTS
Extrae solamente variables que ya existen (es decir, rellena las variables existentes con valores procedentes de la matriz). Esta opcion s e agrego a la version 4.2.0 y resulta ~itil para convertir, por ejemplo, $-REQUEST en u n conjunto de variables validas.
EXTR-PREFIX-IF-EXISTS
Solo crea una version con prefijo si ya existiese una version sin prefijo. Esta opcion s e agrego en la version 4.2.0.
EXTR-REFS
Extrae variables como referencia. Esta opcion s e agrego en la version 4.3.0.
Las opciones m i s Gtiles son las predeterminada, EXTR OVERWRITE, y EXTR PREFIX-ALL. Las otras funciones pueden resultar de uclidad si sabemos que s e v a a producir una colisi6n y queremos saltarla o utilizar prefijos. A continuaci6n se recoge u n sencillo ejemplo utilizando EXTR P R E F I X ALL. Como puede observar, las variables creadas se denominan prefix-fui6n bajoInombre d e clave.
Este c6digo devolvera d e nuevo v a l u e 1 v a l u e 2 v a l u e 3 . Tenga en cuenta que para que e x t r a c t ( ) extraiga u n elemento, la clave d e dicho elemento debe ser un nombre vilido d e variable, lo que significa que se no se tendrsn en cuenta las claves que comiencen por n6meros o que incluyan espacios.
En este capitulo se trata lo que e n nuestra opini6n son las funciones d e matriz mfis utiles d e PHP, per0 no se han estudiado todas. En el manual en linea d e PHP, disponible en h t t p : / /www p h p n e t / a r r a y , encontrari una breve descripci6n d e todas ellas.
.
.
En el siguiente capitulo se analizarin las funciones d e procesamiento. Veremos c6mo realizar operaciones d e busqueda, sustitucion, divisi6n y combinaci6n d e cadenas. Asi mismo, se examinarin las potentes funciones d e expresiones regulares capaces de realizar pricticamente cualquier operaci6n sobre una cadena.
En este capitulo, veremos c6mo puede utilizar las funciones de cadena de PHP para aplicar formato y manipular texto. Tambikn veremos c6mo utilizar funciones de cadena o funciones de expresiones regulares para buscar (y reemplazar) palabras, frases y otros patrones dentro de una cadena. Estas funciones resultan utiles en muchos contextos. Con frecuencia se suele limpiar o modificar el formato de 10s datos recibidos de 10s usuarios para almacenarlos en una base dedatm. Las funciones de busqueda son magnificas para crear motores de busqueda (entre otras cosas). En este capitulo, analizaremos 10s siguientes aspectos: Formato de cadenas Combinaci6n y divisi6n de cadenas Comparaci6n de cadenas Coincidencia y sustituci6n de subcadenas con funciones de cadena Uso de expresiones regulares
Aplicaci6n de ejemplo: Smart Form Mail En este capitulo, vamos a examinar las funciones de cadena y de expresiones regulares en el context0 de la aplicaci6n Smart Form Mail. Agregaremos estas se-
cuencias d e comandos a1 sitio Bob's Autor Parts que hemos desarrollado en 10s 61timos capitulos. E n concreto, varnos a crear un sencillo torrnulario para que 10s clientes d e Bob expsesen sus quejas y agradecirnientos, corno se ilustra en la figura 4.1. Sin embargo, nuestra aplicaci6n incorporarci una mejora con respecto a 10s forrnularios d e este tiyo que se incluyen e n la Web. En lugar d e remitir el formulario For correo electr6nico a una direcci6n gen6rica corno i n f o r m a c i o n @ ej e m p l o com, intentaremos que s u procesamiento resulte mas avanzado. Para ello, se analizara el texto en busca d e palabras clave y frases, y se rernitirci el correo electr6nico a1 ernpleado apropiado d e la compariia d e Bob. Por ejemplo, si el correo contiene la palabra "avertising", el formulario podria dirigirse a1 departarnento d e marketing - Si el correo procede d e un cliente importante, se &rigi& dirictamente a Bob.
.
1 Customer Feedback RI Your name:
Your email address
I
I feedback:
~end?eedback
Figura 4.1. El formulario para comentarios de Bob pregunta a 10s clientes su nombre, direccion de correo electronico y comentarios
Cornenzarernos por la sencilla secuencia d e cornandos que se rnuestra en el listado 4.1 e iremos agregando elementos progresivarnente. Listado 4.1. processfeedback.php: secuencia de comandos basica de Email Forms Contents
Desarrollo Web con PHP y MySQL Srnailcontent
=
Sfromaddress
=
'Customer name: '.$name."\n" .'Customer ernail: '.Semail."\n" ."Customer commerits: \n".Sfeedback."\n"; 'From: webserver@example.corn';
mail [Stoaddress, Ssubj ect, Smailcontent, Sfromaddress) ; ?>
< t i t l e > B o b l s Auto Parts - Feedback Submitted Feedback submitted Your feedback has been sent. < / html>
Por regla general, deberia comprobar si 10s usuarios han rellenado todos 10s campos obligatorios del formulario con ayuda de isset ( ) ,por ejemplo. Hemos omitido esta operaci6n en la secuencia de comandos asi como en otros ejemplos para no alargar el andlisis. En esta secuencia de comandos, hemos concatenado 10s campos del formulario y hemos utilizado la funci6n mail ( ) de PHP para enviar un correo electronic0 a informaci6nee j emplo .com.A continuaci6n, analizaremos la funci6n mail ( ) . La funci6n mai 1 ( ) envia correos electrbnicos. Su sintaxis es la siguiente: boo1 mail (string to, string t e m a , string m e n s a j e , string [ e n c a b e z a d o s a d i c i o n a l e s [ , string p a r i r n e t r ~ s ~ a d i c i o n a i e ]s )] ;
Los primeros tres parbmetros son obligatorios y representan la direcci6n a la que dirigir el correo electr6nic0, la linea de asunto y 10s contenidos del mensaje, respectivamente. El cuarto pardmetro se puede utilizar para enviar otros encabezados vblidos. Los encabezados vdlidos de correo electr6nicos se describen en el documento RFC822, que estd &sponible en linea si desea obtener mds detalles. (Los RFC o Solicitudes de comentarios son la fuente de una gran cantidad de estdndares de Internet, como se comentard en un capitulo posterior.) Aqui hemos utilizado el cuarto pardmetro para agregar una direccidn "From: " a1 correo electrbnico. Tambi6n puede utilizarlo para agregar campos "Reply-To: " y "Cc:",entre otros. Si desea incluir mbs de un encabezado, s610 serb necesario separarlos mediante caracteres de nueva linea (\n)en la cadena, de la siguiente forma:
El quinto parbmetro se puede utilizar para pasar otro argument0 a1 programa que tenga configurado para enviar correo. Para poder utilizar la funci6n ema il ( ) ,configure su instalaci6n de PHP para que apunte a1 programa utilizado para enviar correos electr6nicos. Si la secuencia de comandos no funciona correctamente, consulte el apendice A. A lo largo de este capitulo, optimizaremos esta secuencia de comandos bdsica utilizando funciones de procesamiento de cadenas y expresiones regulares de PHP.
4 . Manipulacio'n de cadenas y expresiones regulares
Aplicacion de formato a cadenas A menudo es necesario limpiar las cadenas que envian 10s usuarios (por regla general procedentes de una interfaz de formulario HTML) para poder utilizarlas.
Limpieza de cadenas: chop(), Itrim() y trim() El primer paso del proceso de limpieza consiste en quitar todos 10s espacios en blanco no necesarios de la cadena. Aunque no resulta obligatorio, puede resultar util si se va a almacenar la cadena en un archivo o base de datos, o si vamos a compararla con otras cadenas. PHP incorpora tres funciones que resultan de utilidad en este sentido. Utilizaremos la funci6n t r i m ( ) para limpiar 10s datos de entrada de la siguiente forma:
La funci6n t r i m ( ) elimina 10s espacios en blanco desde a1 principio a1 final de una cadena, y devuelve la cadena resultante. De manera predeterminada, limpia 10s caracteres de nueva linea y retorno del carro ( \ n y \ r), tabuladores horizontales y verticales ( \ t y \v), caracteres de final de cadena ( \ 0 ) y espacios. Tambikn permite pasar un segundo parimetro para incorporar otros caracteres que eliminar a la lista predeterminada. Existen otras funciones l t r i m ( ) o chop ( ) que puede utilizar. Ambas son similares a t r i m ( ) :toman la cadena en cuesti6n como parimetro y devuelven la cadena con formato. La diferencia entre estas tres es que t r i m ( ) elimina 10s espacios en blanco desde el principio a1 final de la cadena, 1t r i m ( ) elimina 10s espacios en blanco desde el principio (.o desde la izquierda) unicamente y c h o p ( ) elimina 10s espacios en blanco desde el final (o desde la derecha) Gnicamente.
Aplicaci6n de formato a cadenas para presentaciones PHP consta de un conjunto de funciones que permiten volver a aplicar formato a una cadena de diferentes formas. Uso
de formato HTML: la funcion nl2br()
La funcidn n l 2 b r ( ) toma una cadena como pardmetro y sustituye todas las lineas nuevas con la etiqueta XHTML < b r / > (o la etiqueta < b r > en las versiones anteriores a la 4.0.5). Esta funci6n resulta util para imprimir una cadena de gran tamaiio en el navegador. Por ejemplo, hemos utilizado esta funci6n para aplicar formato a la informaci6n recibida del cliente y devolverla: Your feedback (shown below) has been
sent.
Desarrollo Wcb con P H P y MySQL
Recuerde que HTML no tiene e n cuenta 10s espacios en blanco sin procesar, por lo que si 11o filtramos este resultado a travgs de n l 2 b r ( ) , aparecerin en una sola linea (a excepcion d e las lineas nuevas forzadas por la ventana del navegador), como se ilustra e n la figura 4.2.
Aplicacicin cle frwtnnho a una cadena para c u irnprcsion Hasta el momento, hemos utilizado la instrucci6n echo para mostrar cadenas en el navegador. PHP tambien incluye la instrucci6n print ( ) , que realiza la misma funci6n que echo, per0 devuelve un valor ( t r u e o f a l s e , para denotar el resultado d e la operaci6n).
1
Customer name: Jane Smith Customer m a i l : jane@somewhere Customer conunenls: Thank you for provicling elech.ouic ordering on your websitc. With nlZbr: Customer name: Jane Smith Customer email: jane@somewhere Customer comuenls: Thank you for providing elecbotlic ordering on y o w website.
Figura 4.2. El uso de la funcion nl2br() rnejora la representacion de cadenas largas dentro de HTML
Estas dos t6cnicas imprimen una cadena sin mfis. Puede aplicar formato mAs sofisticado utilizando las.funoiones p r i n t f ( ) y s p r i n t f ( ) . st as funcionan bssicamente d e la misma forma, con la excepcion d e que la primera imprime una cadena con formato en el navegador y la segunda devuelve una cadena con formato. Si ha programado previamente en C, observarfi que estas funciones son iguales que sus versiones d e C. Si no lo ha hecho, lleva cierto tiempo acostumbrarse per0 resultan fitiles y potentes. Las sintaxis d e estas funciones es la siguiente:
El primer parsmetro pasado a ambas funciones es una cadena d e formato que describe la forma b6sica del resultado con c6digo d e formato e n lugar d e variables. Los demds par6metros son variables que se sustituirsn e n la cadena d e formato. Por ejemplo, con echo,utilizamos las variables deseadas para imprimir en linea. Por ejemplo:
4 , Mnt~ip~rlacibtr de mdenns y a p r e s i o n e s regrrlnres
Para obtener el mismo resultado con p r i n t f ( ) ,se utilizari:
La secuencia Gs utilizada en la cadena de formato se denomina especificaci6n d e conversi6n. Su objetivo es "ser reemplazada por una cadena". En este caso, s e r i sustituida con $ t o t a l , interpretada como una cadena. Si el valor almacenado en $ t o t a l fuera 12.4, ambas instrucciones imprimirian 12.4. La ventaja d e p r i n t f ( ) es que podemos utilizar una especificaci6n d e conversi6n m i s util para especificar que $ t o t a l es un numero d e coma flotante y que deberia constar d e dos decimales tras el punto, como se indica a continuation:
La cadena d e formato puede incluir varias especificaciones d e conversi6n. Si tenemos n especificaciones d e conversi6n, tendri n argumentos tras la cadena d e formato. Cada especificaci6n d e conversi6n s e r i reemplazada por un argument0 con nuevo formato en el orden e n el que se liste. Por ejemplo:
Las especificaciones de conversi6n utilizarin la variable $ t o t a l per0 en la segunda se utilizarii la variable $ t o t a l s h i p p i n g . Cada especificaci6n d e conversi6n s&ue el mismo formato, a saber:
Todas las especificaciones d e conversi6n comienzan por un siinbolo % .Si desea imprimir un simbolo 3, necesitari utilizar 9, A . El caricter de rellcno es opcional. Se utilizari para rellenar 10s espacios de la variable con la anchura especifirada. Por ejemplo, podemos agregar ceros iniciales a un n6mero en un contador. El simbolo - es opcional. Especifica que 10s datos del campo se justificarin a la izquierda, en lugar d e a la derecha (opci6n predeterminada). El especificadoramhura indica a p r i n t f ( ) el espacio (en caracteres) que se debe dejar para que la variable se sustituya. El especificador precisidiz deberia comenzar por una coma decimal. Deberia contener el nilmero d e espacios deseados tras la coma decimal. La parte final d e la especificaci6n es un c6digo d e tipo. En la tabla 4.1 se recoge un resumen. Tabla 4.1. Codigos de tipo de especificacion de conversion
Se interpreta carno u n entero y se imprime como u n numero binario. Se interpreta como u n entero y se imprime como u n caracter.
Desnrrollo W e b con P H P y MySQL
S e interpreta como u n entero y s e imprime como u n numero decimal. S e interpreta como u n doble y s e imprime como u n numero con coma flotante. S e interpreta como u n entero y s e imprime como u n numero octal. s
Se interpreta como una cadena y se imprime como una cadena S e interpreta como u n entero y s e imprime como u n numero decimal con minusculas para 10s digitos a-f. S e interpreta como u n entero y s e imprime como u n numero hexadecimal con mayusculas para 10s digitos A-F.
Desde la versicin 4.0.6 se puede utilizar la numeraci6n d e argumentos, lo clue significa que no es necesario utilizar el mismo orden que las especificaciones d e conversion. Por ejemplo:
Basta con agregar la posicion del argument0 directamente tras el simbolo E, seguido por el cariicter d e escape $. En este caso, 2\$ significa "sustituir con el segundo argumento d e la lista". Este m6todo tambien se puede utilizar para repetir argumentos. vi,i\,t,\,
~ ~ , i , - ~r ~ ' d > ~ i , ,
3,
rnin(r\,.t~l,>c
~ . , : d ~ ~ t ~ ~
$\rj I J ~ , >
--
Podemos modificar el uso & mayusculas y minlisculas en una cadena. Este recurs o n o resulta especialmente util en nuestra aplicacion, pero examinaremos algunos ejemplos. Si comenzamos por la cadena del tema, $ s u b j e c t , que vamos a utilizar e n nuestro correo electr6nic0, podemos cambiar el formato d e mayusculas y m i n ~ s c u l a s con ayuda d e varias funciones. El efecto d e estas funciones se resume e n la tabla 4.2. La primera columna muestra el nombre d e la funcion, la segunda describe s u efecto, la tercera muestra c6mo se aplicara a la cadena $ s u b J e c t y la ultima indica que valor se devolverii d e la funci6n. Tabla 4.2. Funciones para la aplicacion de mayusculas y minusculas a cadenas y sus
efectos
$subject
Information procedente del sitio Web
Funcion
escripci6n
Us0
Valor
strtoupper ( )
Convierte la cadena en rnayusculas
strtoupper ($subject)
INFORMACION PROCEDENTE DEL SlTlO WEB
strtolower ( )
Convierte la cadena en rninusculas
strtolower ($subject)
Inforrnacion procedente del sitio W e b
ucfirst ( )
Pone en rnayusculas el primer caracter de la cadena si es un caracter alfabetico
ucf irst ($subject)
inforrnacion procedente del sitio W e b
ucwords ( )
Pone en rnaylisculas ucwords ($subject) la prirnera letra de cada palabra de la cadena que cornience por un caracter alfabetico
Inforrnacion Procedente Del Sitio W e b
Adem6s d e utilizar funciones d e cadena para modificar el formato d e las cadenas visualmente, podemos utilizar parte d e estas funciones para variar el formato d e cadenas para SLI almacenamiento en una base d e datos. Aunque el tema d e la escritura d e cadenas en bases de datos no se examinari hasta la segunda parte de este libro, seguidamente analizaremos c6mo aplicar formato a cadenas para su almacenamiento en bases d e datos. Determinados caracteres s o p perfectamente vtilidos como parte d e una cadena per0 pueden originar problemas, en especial a1 insertar datos en una base d e datos ya que esta podria interpretarlos como caracteres d e control. Los caracteres problerniticos son las comillas (simples o dobles), las barras invertidas y el car6cter NUL. Debemos buscar una forma d e marcar estos caracteres para indicar a las bases d e datos, como MySQL, que se trata d e caracteres especiales y no d e una secuencia d e control. Para marcar estos caracteres corno caracteres especiales, se agrega una barra invertida delante de ellos. Por ejemplo, las comillas dobles ( " ) se convertirtin en \ " (barra invertida seguida de las comillas dobles) y la barra invertida ( \ ) se convierte en \ \ (doble barra invertida). (Esta regla se aplica universalmrnte 10s caracteres especiales, d e manera que si tiene \ \ en una cadena, debera sustituirla por \ \ \ \ . ) PHP incorpora dos funciones especificamente disefiadas para marcar caracteres especiales. Antes d e escribir cadenas en una base d e datos, deberia modificar SLI formato con la funci6n AddSlas hes ( ), por ejemplo:
Drstrvrollo W e b con P H P y M!ySQL ~
~
~~
-
-
Como muchas otras funciones d e c a d e n a , ~ d d ~ lhaess ( ) toma una cadena con10 pardmetro y devuelve la cadena con formato nuevo. A1 utilizar A d d s l a s h e s ( ) , la cadena se almacenari e n la base d e datos con las barras. Al recuperar la cadena, deberci acordarse de quitar dichas barras. Para ello puede utilizar la funci6n S t r i p s l a s h e s ( ) : :fc.~dk.?,:~
St:ipSl,~~t~r~!?(::fe+?.:ik~a::l:;;
=
La figura 4.3 muestra 10s efectos d e utilizar estas funciones e n la cadena.
1
Customer feedhack hefore AddSlnshes:
-
Your customer service I-epresentalivetold me. "We don't give any g~nrantees." What kind of service is hat?
I I
Customer feedback after AddSIashes: Your customer senice I-epreserilalivetold me, \"We dorr\'t give my gunranlnlecs.\" R%atkind of sewice is that'?
Your custorner service repl-esentative told me, 'We don't give any guamlees." What kind orscn,ice is hat?
Figura 4.3. Tras llamar a la funcion AddSlashesO, se colocaran barras delante de todas las comillas. La funcion StripSlashes() quitara las barras
Tambien puede configurar PHP para agregar y quitar barras automiticamente. Esta funci6n se conoce como_comillas migicas y cornentar6 en mayor detalle en u n capitulo posterior.
A menudo, necesitamos examinar partes d e una cadena por separado. Por ejemplo, puede que necesitemos examinar las palabras d e una frase (para cornprobar s u ortografia, por ejemplo) o dividir u n nombre o una direccidn d e correo electrdnico en sus componentes. PHP incorpora varias funciones d e cadena (y una funcion d e expresi6n regular) que nos permite realizar esta tarea. En nuestro ejemplo, Bob quiere recibir todos 10s comentarios procedentes de b i g c u s t o m e r . comdirectamente, por lo que dividiremos la direcci6n d e correo electr6nica escrita por el cliente e n partes para determinar si se trata d e clientes importantes d e Bob.
4. Manipulacidn de cadenas y expresiones regulares
Uso de explode(), implode() y ioin() La primera funci6n que podriamos utilizar para este objetivo es explode ( ) cuya sintaxis es la siguiente: array
explode (string
separador,
string
en trada
[,
int
1 imi te] ) ;
Esta funci6n toma una entrada de cadena y la divide en partes en una cadena de separador especificada. Las partes se reunen en una matriz. Puede limitar el numero de partes con el parfimetro opcional de limitacibn, agregado en PHP 4.0.1. Para obtener un nombre de dominio de la direcci6n de correo electr6nico del cliente en su secuencia de comandos, podemos utilizar el siguiente c6digo:
Esta llamada a la funci6n explode ( ) divide la direcci6n de correo electr6nico del cliente en dos partes: el nombre de usuario, que se puede almacenar en $email a rra y [ 0 ] y el nombre de dominio en $ ema i1 array [ 1] . Ahora ya podemos bar el nombre de dominio para determinar el orTgen del cliente y enviar sus comentarios a la persona apropiada. (Semall array[l]=='b~gcustomer.com') Stoaddress = 'bob@example.com'; else Stoaddress = 'feedback@example.c n m ' ; lf
-
Si el dominio estuviera en mayusculas, la operaci6n no funcionaria. Podemos evitar este problema convirtiendo el dominio a todo maydsculas o todo minusculas y realizar la comprobaci6n seguidamente: $email-array[ll
=
-
strtoupper ($email-array[ll);
-
Puede invertir 10s efectos de explode ( ) utilizando las funciones implode ( ) o join ( ) ,que son idbnticas. Por ejemplo:
Este c6digo toma 10s elementos de la matriz $ email array y 10s combina con la cadena pasada en el primer parfimetro. La llamada a l a funci6n es muy similar a explode ( ) , per0 el efecto es el contrario.
Uso de strtok() A diferencia de explode ( ) ,que divide una cadena en pequefias partes de una sola vez, strto k ( ) va extrayendo partes (llamadas simbolos) de la cadena una a una. Esta funci6n es una alternativa util a la'funci6n explode ( ) para procesar una cadena palabra a palabra. La sintaxis d e la propiedad strto k ( ) es la siguiente: string
strtok (string
entrada,
string
separador) ;
.
Desarrollo Web con PHP y MySQL
El separador puede ser un cardcter o una cadena de caracteres pero la cadena de entrada se dividird en cada uno de 10s caracteres de la cadena del separador en lugar de en toda la cadena (como ocurria con e x p l o d e ) . La tarea de llamar a la funci6n s t r t o k ( ) no resulta tan sencilla como pudiera parecer por su sintaxis. Para obtener el primer simbolo de una cadena, se invoca s t r t o k ( ) con la cadena divida en las partes deseadas y un separador. Para obtener las siguientes partes de la cadena, se pasa u n 6nico pardmetro: el separador. La funci6n mantiene su propio puntero interno dentro de la cadena. Si desea restablecer el puntero, puede pasarle la cadena de nuevo. La funci6n s t r t o k ( ) se suele utilizar de la siguiente forma: $token = strtok ($feedback, ' echo $token.' I ; while ($token!='')
' );
I $token = strtoki' echo $token.'
'); > I ;
i;
Como de costumbre, conviene comprobar que el cliente ha escrito alg6n comentario en el formulario, utilizando la funci6n e m p t y ( ) . En nuestro caso se ha omitido para no alargar el ejemplo. Este c6digo imprime cada simbolo del comentario del cliente en una linea distinta y recorre en bucle el comentario hasta que no quedan m6s simbolos. En las versiones de PHP anteriores a la 4.1.0, s t r t o k ( ) no funcionaba de forma exactamente igual a como lo hace en C. Si una cadena de destino contiene dos instancias de un separador seguidas (en este caso dos espacios), s t r t o k ( ) devuelve una cadena vacia. Este resultado no se puede diferenciar de la cadena vacia que se devuelve a1 llegar a1 final de la cadena de destino. Asi mismo, si uno de 10s simbolos es 0, se devolverd la cadena vacia. Esto convierte a la funci6n s t r t o k ( ) de PHP en algo menos util que la de C. La nueva versi6n funciona correptamente ya que salta las cadenas vacias.
Uso de su bstr() La funci6n s u b s t r ( ) permite acceder a una subcadena situada entre el punto inicial y el punto final de una cadena. En nuestro ejemplo no resulta apropiado pero puede ser util si intenta acceder a partes de cadenas con formato fijo. La funci6n s u b s t r ( ) tiene la siguiente sintaxis: string substr (string cadena, int ~ n i c i o [ ,int lonyi t u d ]
) ;
Esta funci6n devuelve una subcadena copiada de cadena. Si se llama a esta funci6n con un n6mero positive desde el par6metro inicio (6nicamente), se obtendr6 la cadena desde la posici6n inicio hasta el final de la cadena. Por ejemplo:
4 . Manipulacidn de cadenas y expresiones regulares
devuelve our customer service is excellent. Tenga en cuenta que la posici6n inicial es 0, como ocurre con las matrices. Si llama a la funci6n subst r ( ) con un valor inicio negativo (Gnicamente), obtendrii la cadena desde su final menos 10s caracteres inicio hasta el final de la cadena. Por ejemplo:
En este caso se devuelve exce 11en t. El pariimetro de longitud se puede utilizar para especificar un nGmero de caracteres que devolver (si es positivo) o el cariicter final de la secuencia de retorno (si es negativo). Por ejemplo: s u b s t r ( $ t e s t , 0,
4 ;
devuelve 10s primeros cuatro caracteres de la cadena, en concreto, Your. El siguiente c6digo: echo
substr($test,
4,
-13);
devuelve 10s caracteres situados entre el cuarto y el cariicter decimotercero, es decir, customer service.
Hasta el momento s610 hemos utilizado el operador == para comparar si dos cadenas son iguales. Pero PHP permite realizar comparaciones un poco miis avanzadas. Las hemos dividido en dos categorias: coincidencias parciales y otras. En primer lugar estudiaremos las demiis y 2eguidamente pasaremos a estudiar las coincidencias parciales, para lo cual atanzaremos en el desarrollo del ejemplo Smart Form.
Estas funciones se pueden utilizar para ordenar cadenas y, por tanto, para ordenar datos. La sintaxis de la funci6n st rcmp ( ) es la siguiente: i n t strcrnpistring strl, s t r i n g str2);
La funci6n espera recibir dos cadenas, que compararii. Si son iguales, devolverii 0. Si la cadena st rl viene tras (o es mayor que) str2 en orden lexicogriifico, st rcmp ( ) devolverii un nGmero mayor que cero. Si str 1 es menor que str 2 , strcmp ( ) devolverii un nGmero menor que cero. Esta funci6n discrimina entre ma-
yGsculas y minGsculas.
La funci6n strcasecmp ( ) es idkntica con la diferencia de que no discrimina entre mayusculas y minusculas. La funcion strcasecmp ( ) y su pareja strnatcasecmp ( ) , que no discrimina entre mayusculas y minusculas, se agregaron en PHP 4. Estas funciones comparan cadenas en funci6n de un "orden natural", que se parece mtis a la forma en la que lo hace un humano. Por ejemplo, st rcmp ( ) ordenarti la cadena " 2 " como mayor que la cadena " 12 " porque lexicogrtificamente resulta mayor. strcasecmp ( ) hace exactamente lo contrario. Si desea saber mtis sobre el orden natural, dirijase a http: //www.naturalordersort. org/.
Comprobacion de la longitud de una cadena con strlen() Podemos comprobar la longitud de una cadena con la funci6n strlen ( ) . Si se pasa en una cadena, devolverti su longitud. Por ejemplo, strlen ( ' hello ' ) devuelve 5. Esta funci6n se puede utilizar para validar datos de entrada. Considere la direcci6n de correo electr6nico de nuestro formulario, almacenada en $email.Una forma elemental de validar una direcci6n de correo electr6nico almacenada en $email consiste en comprobar su longitud. Si partimos de unos ctilculos aproximados, la longitud minima de una direcci6n de correo electr6nico es de seis caracteres, por ejemplo a @a.to (suponiendo que el c6digo del pais no tiene dominios de segundo nivel, y que el nombre del servidor y la direcci6n s610 tienen una letra respectivamente). Por lo tanto, si la direcci6n no tiene esta longitud minima, se generarti un error: I
-
-
echo 'That email address is not valld'; exit; / / fir~alice la ejecuci6n d e la secuencia d e comandos d e P H E
I
Obviamente, se trata de una forma muy simple de validar la informaci6n. En la siguiente secci6n examinaremos formas mejores.
Como buscar subcadenas y reemplazarlas con funciones de cadena Resulta habitual comprobar si una subcadena dada estti presente en una cadena de mayor tamafio. Esta coincidencia parcial suele ser mtis util que comprobar la igualdad entre cadenas. En nuestro ejemplo Smart Form, queremos buscar determinadas frases clave dentro de 10s comentarios de 10s clientes y enviar el correo a1 departamento adecuado. Si
4. Manipulacidn de cadenas y expresiones regulares
queremos enviar correos electr6nicos relacionados con las tiendas de Bob a1 encargado del departamentos de ventas, tendremos que saber si aparece la palabra "shop" (o alguna variaci6n) en el mensaje. Podriamos utilizar funciones ya vistas, como e x p l o d e ( ) o s t r t o k ( ) para recuperar palabras individuales del mensaje y compararlas utilizando el operador == o s t r c m p 0 . Sin embargo, podemos hacer lo mismo con una unica llamada de funci6n a una de las funciones de comparacidn de cadenas o de expresiones regulares. h t a s se utilizan para buscar un patr6n dentro de una cadena. Examinaremos cada conjunto de funciones por separado.
Busqueda de cadenas en cadenas: strstro, strchr(), strrchr(), stristro Para buscar una cadena dentro de una cadena, podemos utilizar cualquiera de las funcionesstrstr ( ) , s t r c h r ( ) , s t r r c h r ( ) o s t r i s t r 0. La funci6n s t r s t r ( ) es la mhs generica y se puede utilizar para buscar una cadena o caracter dentro de una cadena d e mayor tamafio. Tenga en cuenta que en PHP, la funci6n s t r c h r ( ) es exactamente igual que la funci6n s t rs t r ( ) ,aunque su nombre implique que se utiliza para buscar un carhcter en una cadena, de manera similar a la versi6n de C de esta funci6n. En PHP, se pueden utilizar las dos funciones para buscar una cadena dentro de otra cadena, incluyendo la posiblidad de buscar una cadena que contenga un solo carhcter. La sintaxis de s t r s t r ( ) es la siguiente: string strstr(string pajar, string aguja);
En la funci6n se pasa el parhpetro pajar sobre el que buscar y un parhmetro aguja que encontrar. Si se encuedra una coincidencia exacta de aguja, la funcidn devolverh el pajar desde la aguja en adelante o, de lo contrario, devolverh f a 1 s e . Si la aguja tiene lugar en mhs de una ocasibn, la cadena devuelta comenzarh desde la primera ocurrencia de aguja. Por ejemplo, en la aplicaci6n Smart Form, podemos decidir d6nde enviar el correo electr6nico d e la siguiente forma: Stoaddress
=
'feedback@exarnple.cornl;
/ / el valor predeterninado
/ / Cambie Stoaddress si s e curnple el criterio if (strstrisfeedback, 'shop')) Stoaddress = 'retail@exarnple.cornl; else if (strstriSfeedback, 'delivery')) Stoaddress = 'fulfilment@example.corn'; else if (strstrisfeedback, 'bill')) 'accounts@example.corn'; Stoaddress =
Este c6digo busca determinadas palabras claves en el comentario del usuario y envia el correo a la persona adecuada. Por ejemplo, si el cliente escribe "I still haven't
Desarrollo W e b con P H P y MySQL received delivery of my last order" (todavia no he recibido mi tiltimo pedido), se detectar6 la cadena "delivery" (entrega) y el comentario se e n v i a r i a fulfilment@example.com. Existen dos variantes de st rstr ( ) . La primera es stri st r ( ) , que es pricticamente idbntica con la salvedad de que no distingue entre maytisculas y mintisculas. Esta funci6n resulta titil en nuestra aplicaci6n ya que el cliente podria escribir 'delivery', 'Delivery' o 'DELIVERY'. La segunda variante es st rrchr ( ) , que es, de nuevo, pricticamente idhtica, per0 devuelve pajar desde la tiltima ocurrencia de la aguja en adelante.
usqueda de la posicion de una subcadena: str Las funciones st rpos ( ) y st rrpos ( ) funcionan de la misma forma que st rs t r ( ) , con la diferencia de que en lugar de devolver una subcadena, devuelven la posici6n numbrica de una aguja en un pajar. La funci6n st rpos ( ) tiene la siguiente sintaxis: i r ~ t s t r p o s ( s t r i r ~ y pajar-, s t r i n g
ayuja,
int
[desplazamienrsl
) ;
El valor entero devuelto representa la posici6n de la primera ocurrencia de aguja dentro de pajar. El primer caricter es la posici6n 0 como de costumbre. Por ejemplo, el siguiente c6digo imprimiri el valor 4 en el navegador: $ t e s t = 'Hello w ~ ~ r l d ' ; e c h o s t r p o s ( $ t ~ s t ,' 0 ' 1 ;
En este caso, s610 hemos pasado un caricter como aguja, per0 puede ser una cadena de cualquier longitud., El parimetro opcionai de desplazamiento se utiliza para especificar un punto dentro de pajar a partir del cual iniciar la btisqueda. Por ejemplo:
Este c6digo imprimiri 7 en el navegador porque PHP ha comenzado a buscar el caricter o en la posici6n 5 y, por lo tanto, no veri el situado en la posici6n 4. La funci6n st rrpos ( ) es pricticamente idbntica, per0 no devuelve la posici6n de la ultima ocurrencia de aguja en pajar. A diferencia de s t r p o s o , s610 funciona con un unico caricter aguja. Por lo tanto, si la pasamos en una cadena como aguja, s610 utilizari el primer caricter de la cadena para establecer la coincidencia. En cualquiera de estos casos, si aguja no esti en la cadena, s t rpos ( ) o st rrpos ( ) devolveri fa1se,lo cual puede plantear un problema porque fa1se en un lenguaje con control debil de tipos como PHP equivale a 0, es decir, a1 primer caricter de una cadena. Para evitar este problema podemos utilizar el operador === y probar 10s valores devueltos: Sresult
=
strpos($test,
'HI);
Tenga en cuenta que solo funcionara en PHP 4 ya que en las versiones anteriores puede probar si es f a l s e examinando el valor devuelto para determinar si se trata d e una cadena (es decir, fa 1 s e ) .
La funcion d e buscar y reemplazar cadenas puede resultor extremadamente Litil con cadenas. Se puede utilizar para personalizar documentos generados por PHP (por ejemplo, sustituyendo < < n o m b r e > >con el nombre de una persona y < < d l r e c c i o n > > con SLI direcci6n). T a m b i h puede utilizarla para censurar el uso d e determinados tckminos, por ejemplo en u n foro o incluso e n la aplicacion Smart Form. De nuevo, puede utilizar funciones d e cadena o funciones d e expresion regular con este fin. La funci6n d e cadena que m i s se suele utilizar para realizar s ~ ~ s t i t u c i o n eess s t r -r e p l a c e ( ) . A continuaci6n se recoge su sintaxis:
Esta funci6n sustituira todas las instancias d e nguja en pajar por izueua-aguja y devolvera la nueva version d e yajar.
Nota
.
-
Desde PHP 4.0.5 puede pasar todos 10s parametros como matrices y la funcion se comportara de manera bastante inteligente. Puede pasar una matriz de palabras para su sustitucion, una matriz de palabras con la que sustituirlas (respectivamente) y una matriz de cadenas a las que aplicar estas reglas. La funci6n devolvera una matriz de cadenas revisadas. En el formulario Smart Form podrian aparecer palabras malsonantes incluidas por los usuarios al manifestar sus quejas. Como programadores, podemos evitar que 10s distintos departainentos d e Bob reciban los insultos:
La funcion s u b s t r r e p l a c e ( ) se utiliza para buscar y reemplazar una determinada subcadena d e k a cadena en funci6n d e su posici6n. SLIsintaxis es la siguiente:
Esta funci6n sustituird parte d e la cadena cadel~ncon la cadena sustrtrrc~cirz.La parte quc se sust~tuircidepende d e 10s valores d e 10s parimetros ~ n i c i oy lorzcyltlid. El valor irliclo representa el desplazamiento dentro d e la cadena en el que comenzard la sustitucicin. Si el valor fuera 0 o positivo, el desplazamiento se estableceria con respecto al principio d e la cadena; si fuera negativo, el desplazamiento se estableceria con resyecto al final d e la cadena. Por ejemplo, esta linea d e c6digo sust ~ t u i rel i ~ l t i m ocardcter d e $test con "x":
El valor l o l ~ g i t u des opcional y representa el punto en el clue PHP dejar6 d e realizar sustituciones. Si n o se indica este pardmetro, la cadena scrd sustituida desde el irricio hasta el final dc. la cadena. Si el valor del pardmetro l o ~ g i t ~ es i d cero, la cadena d e sustituci6n se i ~ ~ s e r t a r ~ i dentro d e la cadena sin sobrescribir la cadena existente. Una l o r r ~ i t u dpositiva representa el nrjmero d e caracteres q u e se sustituiran con la nueva cadena. Una lorlgitrd negativa representa el punto en el que le gustaria detener la sustituci6n d e caracteres, contados desde el final d e la cadena.
PHP admite d m estilos d e sintaxis d e expresicin regular: POSIX y Pcrl. El estilo POSIX d e expresi6n regular sc compila en PHP d e manera predeterminada, pero se puede utilizar el estilo Perl compilando en biblioteca PCRE (Expresi6n regular y compatible con Perl). . En nuestro caso, utilizaremos el estilo POSIX q u e e s 1116s sencillo, pero si es programador d e Perl o desea saber m& sobre la biblioteca PCIIE, consulte el manual en linea d i r i g i h d o s e a h t t p : / / p h p . n e t .
Nota Las expresiones regulares de POSlX resultan mas sencillas de aprender y se ejecutan con mas rapidez, per0 no son seguras para datos binarios. Por lo tanto, las coincidencias d e patrcin rcalizadas hasta ahora utilizaban funciones d e cadena. Nos hemos limitado a las coincidencias exactas o a la coincidencia exacta d e subcadenas. Si desea establecer coincidencias m6s coniplejas, deberia utilizar expresiones regulares. El uso d e las expresiones regulares resulta dificil d e comprender a1 principio pero pueden llegar a ser extremadamente Citiles.
4 . Manipulacidn de cadenas y expresiones regulares
10s fundamentos Una expresi6n regular es una forma de describir un patr6n en un texto. La coincidencia exacta (o literal) que hemos realizado hasta el momento es una forma de expresi6n regular. Por ejemplo, en una secci6n anterior buscamos las expresiones regulares "shop" y " d e l i v e r y " .
En PHP, el establecimiento de coincidencias con expresiones regulares se parece m i s a utilizar la funci6n s t r s t r ( ) que a realizar una comparaci6n de igualdad, porque se hace coincidir una cadena con alguna parte de otra cadena (puede ser cualquier parte de la cadena a menos que se especifique otra cosa.) Por ejemplo, la cadena "shop" coincide con la expresi6n regular "shop". Pero tambien con las expresiones regulares "h", "ho" etc. Podemos utilizar caracteres especiales para indicar un metasignificado ademis de hacer coincidir caracteres de forma exacta. Por ejemplo, mediante el uso de caracteres especiales se puede indicar que ocurra un patr6n a1 inicio o a1 final de una cadena, que parte de un patr6n se pueda repetir o que 10s caracteres de un patr6n Sean de un tip0 dado. Tambien podemos buscar coincidencias literales de caracteres especiales. Examinaremos todas estas posibilidades.
Conjuntos y clases de caracteres El uso de conjuntos de caracteres aumenta el potencial de las expresiones regulares con respecto a las expresiones de coincidencia exacta. Los conjuntos de caracteres se pueden utilizar para hacer coincidir cualquier caricter de un tip0 dado (en realidad son un tip0 de comodin). En primer lugar, puede-utilkar el caricter como comodin para sustituir cualquier otro caricter individual a excepci6n del caricter de nueva linea ( \ n ) . Por ejemplo, la expresi6n regular
coincide con las cadenas ' c a t ' , ' s a t ' y ' mat I , entre otras. Este tip0 de comodin de coincidencia se suele utilizar para bkquedas de nombres de archivo en sistemas operativos. Sin embargo, las expresiones regulares permiten especificar el tip0 de caricter que se desea buscar y, de hecho, se puede especificar un conjunto a1 que pertenezca un caricter. En el ejemplo anterior, las expresiones regulares coinciden con ' c a t ' y ' mat ' per0 tambien con ' # a t ' . Si desea limitar el rango de coincidencias a un caricter entre la a y la z, puede hacerlo de la siguiente forma:
Todo aquello que quede encerrado entre 10s corchetes ( [ I ) se considerari una clase de caricter (un conjunto de caracteres a 10s que debe pertenecer un carficter
D t s a r r o / / o Wcb rorl PHP y MySQL
coincidente). Tenga en cuenta que la expresion incluida entre 10s corchetes coincide con un 6nico car6cter. Puede incluir u n conjunto d e caracteres; por ejemplo:
significa cualquier vocal. Tambien puede describir un rango, como hicimos anteriormente utilizando un guion o un conjunto d e rangos.
Este conjunto d e rangos equivale a cualquier carscter alfabetico ya sea may6sculas o minLisculas. Tambien puede utilizar conjuntos para excluir un caracter del conjunto. Por ejemplo:
equivale a cualquier caracter que no est6 entre la a y la z. El simbolo de acento circunflejo significa rzo cuando se coloca dentro d e corchetes. Si se utiliza fuera d e 10s corchetes tiene otro significado, que examinaremos e n breve. A d e m i s d e enumerar conjuntos y rangos, se pueden utilizar varias clases de caracter predefinido en una expresi6n regular, que se recogen en la tabla 4.3. Tabla 4.3. Clases de caracteres para su uso en expresiones regulares de estilo de POSIX.
-.-
=
--
.
-----**-
Clase
Coincidencia
[[:alnum:]]
~ g r a c t e r e salfanumericos
[[:alpha:]]
Caracteres alfabeticos
-
-
.
-
Letras en minusculas Letras en mayusculas Digitos decimates Digitos hexadecimales Puntuacion Tabuladores y espacios Espacios en blanco Caracteres de control Todos 10s caracteres imprimibtes [[:graph:]
I
Todos 10s caracteres imprimibles a excepcion del espacio
Repeticion Con frecuencia necesitamos especificar que se van a dar varias ocurrencias de una cadena o clase de caricter concreta. Para ello, podemos utilizar dos caracteres especiales dentro de una expresi6n regular. El simbolo * significa que el patr6n se puede repetir cero o m i s veces y el simbolo + indica que el patr6n se puede repetir una o varias veces. El simbolo puede aparecer directamente tras la parte de la expresi6n a la que se aplique. Por ejemplo: [ [ :alnurn: ]
1+
significa "a1menos un caricter alfanum6rico".
Su bexpresiones Suele resultar util poder dividir una expresi6n en subexpresiones para representar, por ejemplo, "a1 menos una de estas cadenas seguidas exactamente por una de esas otras". Para ello, se pueden utilizar 10s parkntesis, exactamente de la misma forma que haria en una expresi6n aritmetica. Por ejemplo: (very )*large
equivale a ' l a r g e ' , ' v e r y l a r g e ' , ' v e r y v e r y l a r g e ' , etc.
Recuento de s bexpresiones Podemos especificar cuintas veces se repite un elemento utilizando expresiones numericas entre llaves ( { 1 ). Podemos mostrar el numero exacto de repeticiones ( { 3 ) significa exactamented repticiones), un rango de repeticiones ( { 2 , 4 ) significa de 2 a 4 repeticiones) o un rango sin cerrar de repeticiones ( I 2 , ) significa a1 menos dos repeticiones). Por ejemplo, equivale a ' v e r y ' , ' v e r y v e r y ' y ' v e r y v e r y v e r y '
Anclajes al principio o al final de una ca Podemos especificar si una subexpresi6n dada deberia aparecer a1 final, a1 principio o en ambos lugares. Esta opci6n resulta bastante util cuando queremos estar seguros de que en la cadena s610 aparece el t6rmino de busqueda y nada mis. Se utiliza el acento circunflejo ( ^ ) a1 principio de una expresi6n regular para indicar que debe aparecer a1 principio de una cadena buscada. El simbolo $ se utiliza a1 final de una expresi6n regular para indicar que debe aparecer a1 final.
Por ejemplo, la siguiente expresi6n busca coincidencias con b o b al principio d e una cadena:
La siguiente expresi6n busca coincidencias con corn a1 final d e u n a cadena:
Por ultimo, la siguiente expresi6n busca coincidencias con cualquier caricter u n co d e la a la z, en s u propia cadena:
Puede representar una opci6n en una expresi6n regular utilizado una bnrra vertical. Por ejemplo, si deseamos buscar coincidencias con corn, e d u o n e t , podemos utilizar la siguiente expresi6n:
Si desea buscar coincidencias con 10s caracteres especiales mencionados como ., o $, debe anteponerles una barra invertida ( \ ) . Si desea representar una barrn invertida, debe sustituirla por d o s barras inversas, \ \ . (
En las t a b l a ~4.4 y 4.5 se recogen un resumen d e todos los caracteres especiales. La tabla 4.4 muestra el significado d e 10s caracteres especiales fuera d e corchetes y la tabla 4.5 muestra s u significado cuando se ~ ~ t i l i z adentro n ellos. Tabla 4.4. Resurnen de caracteres especiales utilizados en expresiones regulares POSlX
fuera de corchetes Significado Caracter de escape Coincidencia al principio de la cadena Coincidencia al final de la cadena Coincidencia de cualquier caracter a excepcion del caracter de nueva linea (\n)
Carhcter
Significado
I
lnicio de una opcion alternativa (como OR) lnicio de un subpatron Final de un subpatron Repetir 0 o mas veces Repetir 1 o mas veces lnicio del cuantificador rninlmax lnicio del cuantificador minlmax
Tabla 4.5. Resumen de caracteres especiales utilizados en expresiones regulares POSlX dentro de corchetes
Caracter
\
Caracter d e escape
h
NO, solamente si se utiliza en una posicion inicial
-
Usado para especificar rangos de caracter
En la aplicacion Smart Form, las expresiones regulares se pueden utilizar con dos fines. El primer0 consiste en.dete?tar terminos concretos e n 10s comentarios enviados por 10s clientes. Podemos utilizar expresiones regulares para ahorrarnos trabajo. Si utilizamos funciones de cadena, tendremos que realizar tres blisquedas si queremos encontrar ' s h o p I , ' customer s e r v i c e ' o ' retail ' cuando bastaria con una expresion regular para realizar la misma operacion:
El segundo uso consiste e n validar las direcciones d e correo electronic0 del cliente en nuestra aplicaci6n codificando el formato estandarizado d e una direction d e correo electronic0 en una expresi6n regular. El formato incluye varios caracteres alfanumdricos o d e ptintuaci6n, seguidos por el simbolo @, por una cndena alfanumdrica y guiones, seguidos por un punto, por m i s caracteres alfanum6ricos y guiones, y posiblemente por m6s puntos, hasta llegar al final d e la cadena, que se codifica d e la siguiente forma:
Desarrollo W e b con PHP y MySQL
La subexpresi6n [ a- zA-z0- 9 \ - \ . ] t significa "la cadena debe comenzar con una letra, un numero, un gui6n bajG u n gui6n medio o un punto o una combinaci6n de estos caracteres". El simbolo @ equivale a1 literal @. La subexpresi6n [ a-ZA-z0-9\ - ] + equivale a la primera parte del nombre del host incluyendo caracteres alfanum6ricos y guiones. Como puede observar se ha quitad0 la barra invertida delante del gui6n dado que se trata de un caracter especial cuando va entre corchetes. La combinaci6n \ . equivale a1 literal .. La subexpresi6n [ a-ZA-z0- 9\ - \ . ] t $ equivale a1 resto del nombre del dominio, incluyendo letras, numeros, guiones y m i s puntos si fueran necesarios, hasta el final de la cadena. Si analiza esta expresion, descubriri que es posible crear direcciones no vilidas equivalentes a la expresibn regular. Resulta pricticamente imposible capturar todos 10s casos, per0 hemos logrado mejorar bastante la situacibn. Puede volver a definir esta expresi6n de muchas formas. Por ejemplo, puede enumerar todos 10s TDL vilidos. Ahora bien, es necesario tener cuidado a la hora de restringir elementos ya que una funci6n de validaci6n que rechace un 1%de 10s datos v6lidos resulta mucho m i s molesta que una que permita un 10% de datos no vilidos. A
Busqueda de subcadenas con expresiones regulares La busqueda de subcadenas es la aplicaci6n principal de las expresiones regulares que acabamos de desarrollar. Las dos funciones disponibles en PHP para buscar coincidencias con expresjoneoregulares son e r e g ( ) y e r e g i ( ) . int ereg (string p a t r d n ,
string b6squeda,
array [ c o i n c i d e n c i a s ] )
;
Esta funcibn busca la cadena bu'squeda para encontrar coincidencias con la expresi6n regular patrdn. Si se encuentran coincidencias para las subexpresiones de patrdn, se almacenar6n en la matriz coincidencias, u n subexpresih por cada elemento de matriz. La funci6n e r e g i ( ) es identica con la salvedad de que no discrimina entre mayusculas y min6sculas. Podemos adaptar el ejemplo Smart Form para utilizar expresiones regulares de la siguiente forma: if ( ! e r e g i ( I A [ a - z A - Z 3 - 9- \-\.]+@[a-zA-50-9\-]+\.[a-zA-ZO-9\-\.I+$', Semail i ) t echo 'That is not a valld email address. Please return t o the' . ' previous page and try again.'; exit;
4. Manipulacidn de cadenas y expresiones regulares
Stoaddress = ' f e e d b a c k @ e x a m p l e . i o r n ' ; / / e l v a l o r predeterrninado if (ereqii'shoplcustorner servlieretail', $feedback)) = 'retail@example.iorn'; $toaildress e l - e i f (ereqi('deliver.*fulfil.*', $ f e e d b a c k ) ) Sraaililress = ' f u l f i l r n e n t @ e x a m p l ~ . ~ n r n ' ; e l s e i f i e r e g i ( ' b i l l a c c o u r ~ t ' ,$ f e e d b a c k ) ) Stoaddress = 'accounts@exarnple.corn'; i f
( e r e g i ( ' b i q c u r t . i m e r \ . corn', $ernail) = 'hnb@exarnple.corn'; $toaddress
Tambien podemos utilizar expresiones regulares para buscar y reemplazar subcadenas de la misma forma que utilizamos s t r r e p l a c e ( ) . Las dos funciones disponibles para realizar esta operaci6n son e r e g -r e p l a c e ( ) y e r e g i -r e p l a c e ( ) . Lafunci6nereg-r e p l a c e ( ) tienelasiguientesintaxis: s t r i n g e r e g -r e p l a c e ( s t r i n q hbsqueda);
patrbn,
string
s u s t i tucibn,
string
Esta funci6n busca la expresi6n regular patrdn en la cadena bu'squeda y la reemplaza con la cadena sustitucidn. La funci6n e r e g i -r e p l a c e ( ) es id4ntica con la diferencia de que no discrimina entre mayusculas y minusculas.
Otra funci6n de expresi6n regular util es s p l i t
()
,cuya sintaxis es la siguien-
te: array
split(string
patrdn,
strinq
hbsqueda,
int
[rndx] ) ;
Esta funci6n divide la cadena busqueda en subcadenas en la expresi6n regular patrdn y devuelve subcadenas en una matriz. El valor entero m i x limita el numero de elementos que puede incluir la matriz. Esta funci6n resulta util para dividir nombres de dominio o fechas. Por ejemplo, $domain = 'yal1ara.cs.rrnit.elu.a~'; S a r r = s p l i t ( ' \ . ', Sdc~main); while ( l i s t ( $ k e y , $value) = each ( S a r r ) ) ?tho ' < b r / > ' . $ v a l u e ;
Esta funci6n divide el nombre del host en cinco componentes e imprime cada uno en una linea distinta.
Comparacion de funciones de cadenas y funciones de expresiones regulares En general, la ejecuci6n de funciones de expresiones regulares resulta menos eficaz que las funciones de cadena con funcionalidad similar. Si su aplicaci6n es sencilla, utilice expresiones de cadena.
Lecturas adicionales PHP consta de una gran cantidad de funciones de cadena. En este capitulo hemos visto las m6s sencillas, per0 si tiene una necesidad concreta (como la traduccidn d e caracteres a1 cirilico), consulte el manual en linea d e PHP para averiguar si dispone de ella. La cantidad de material disponible sobre expresiones regulares es ingente. Puede comenzar por la p6gina man de la funcidn r e g e x p si est6 utilizando UNIX. Tambien encontrar6 articulos muy buenos en d e v s h e d . corny p h p b u i l d e r corn. En el sitio Web de Zend, se incluye una funci6n de validacidn para correos electr6nicos m6s compleja y potente que la desarrollada en este capitulo. Se denom i n a M a i l V a l ( ) y est6 disponible en h t t p : / / w w w . zend. com/codex p h p ? i d = 88&single=l. La correcta comprensi6n de las expresiones regulares lleva cierto tiempo. Cuanto m6s ejemplos examine y ejecute, m6s seguro se sentir6 utiliz6ndolas.
.
.
A continuacion
-
En el siguiente capitulo, veremos varias formas de utilizar PHP para ahorrar tiempo y esfuerzos de programaci611, y evitar la redundancia a1 utilizar c6digo preexistente.
En este capitulo explicaremos cdmo la reutilizaci6n del cddigo permite desarrollar codigo mds coherente, fiable y sencillo de mantener con menos esfuerzo. Mostraremos thcnicas para dividir el c6digo en m6dulos y reutilizarlo. Para ello, comenzaremos por explicar el sencillo uso de las instrucciones r e q u i r e ( ) e i n c l u d e ( ) que permiten utilizar el mismo cddigo en varias pdginas. Explicaremos por qu6 resultan preferibles a las inclusiones en el lado del servidor. En el ejemplo que presentaremos se recclrre a archivos de inclusidn para lograr un aspecto visual y operativo uniforme en todo el sitio. Explicaremos cdmo escribir funciones propias y llamarlas utilizando funciones de generacidn de pdginas y formularios como ejemplos. En este capitulo abordaremos 10s siguientes aspectos: Reutilizacidn del cddigo Utilizacidnde r e q u i r e
()
e include
()
Introducci6n a las funciones Definicidn de funciones Pardmetros Recuperacidn de valores Llamadas por referencias frente a llamadas por valor Ambito Recursidn
5. Reutilizacidn de cddigo y creacidn de funciones
iPor quC reutilizar cbdigo? Uno de 10s objetivos de 10s ingenieros informiticos consiste en reutilizar c6digo para no tener que escribirlo de nuevo. No porque se trate de un grupo especialmente vago sin0 porque la reutilizaci6n de c6digo contribuye a reducir 10s costes, a aumentar la fiabilidad del c6digo y a mejorar la uniformidad de 10s resultados. Lo ideal seria que 10s nuevos proyectos se crearan combinando componentes de c6digo ya existentes, con un minimo de desarrollo desde cero.
Costes Durante la vida util de un fragment0 de c6dig0, se invierte mis tiempo en modificarlo, probarlo y documentarlo que en crearlo. Si esti escribiendo c6digo comercial, deberia intentar limitar el numero de lineas que se utilizan dentro de la organizaci6n. Una forma prictica de lograrlo consiste en volver a utilizar c6digo ya creado en lugar de escribir versiones ligeramente diferentes del mismo c6digo para realizar una nueva tarea. Menos c6digo significa menos costes. Si ya existe software que satisface sus necesidades para un proyecto, adqui6ralo. El coste de comprar software existente es siempre inferior a1 coste de desarrollar un product0 equivalente. Ponga mucha atenci6n si el software existente no cubre exactamente sus necesidades ya que su modificaci6n podria resultar mis dificil que su creaci6n desde cero.
Legibi lidad Si un m6dulo de c6digo se utiliza en otra parte de la organizaci611, es muy probable que se haya probado exhaustivamente. Aunque se trata de un5s p&as lineas, si se vuelve a escribir, es probable que pasemos algun elemento por alto incorporado por su autor original o que se agreg6 a1 c6digo tras descubrir un fa110 durante la fase de prueba. El c6digo existente suele ser mis fiable que el c6digo reci6n creado.
Uniformidad Las interfaces externas de nuestro sistema, incluidas las interfaces de usuario y las interfaces para 10s sistemas externos, deben ser uniformes. Para escribir c6digo nuevo que resulte uniforme con respecto a la forma en la que funcionan el resto de las partes del sistema se necesita una voluntad y un esfuerzo deliberado. Si reutilizamos c6digo ejecutado en otra parte del sistema, la uniformidad quedari garantizada automiticamente. Sobre todas estas ventajas, la reutilizaci6n del c6digo significa menos trabajo, siempre y cuando dicho c6digo sea modular y est6 bien escrito. A1 trabajar, intente reconocer secciones de su c6digo a las que pueda llamar en el futuro.
Desarrollo Wcb con PHP y MySQL
Uso d e require() e include() PHP incorpora dos instrucciones muy sencillas per0 d e gran utilidad para permitir la reutilizaci6n d e cualquier tip0 de ccidigo. Mediante el uso de las instrucciones r e q u i e r e ( ) o i n c l u d e ( ) puede cargar u n archivo en su secuencia d e comandos de PHP. El archivo puede contener todos aquellos elementos que se incluirian por regla general e n una secuencia d e comandos, incluidas instrucciones d e PHP, etiquetas HTML, funciones d e PHP o clases d e PHP. Estas instrucciones funcionan d e manera similar a las inclusiones del lado del servidor que ofrecen muchos servidores Web y a las instrucciones # i n c l u d e d e C o C++.
El siguiente c6digo se almacena en u n archivo llamado r e u s a b l e . php:
El siguiente c6digo se almacena en un archivo llamado m a i n . php:
Si carga r e s u a b l e . php, es probable que no le sorprenda ver aparecer la secuencia "Here is a very simple PHP statement." en el navegador. Si carga el archivo m a i n . p h p ocurrir5 algo u n tanto mas interesante. El resultado d e esta secuencia d e comandos se ilustra en la figura 5.1.
This is the main file. Here is a very simple PHI' stderncnt. ?he script will end now.
Figura 5.1. El resultado de main.php muestra el resultado de la instruccion require()
Se necesita un archivo para utilizar la instrucci6n r e q u i r e ( ) . En el ejemplo anterior, utilizamos el archivo r e u s a b l e . p h p . A1 ejecutar nuestra secuencia d e comandos, la instruccidn r e q u i r e ( )
se sustituye por 10s contenidos del archivo solicitado y, a continuaci611, se ejecuta la secuencia de comandos. Esto implica que a1 cargar m a i n . php, se ejecuta como si la secuencia de comandos estuviera escrita de la siguiente forma: I ; echo 'Here is a very simple PHP statement. I ; ?>
/ > I ;
A1 utilizar r e q u i r e ( ) es necesario tener en cuenta las diferentes formas en las que se procesan las extensiones de nombre de archivo y las etiquetas de PHP.
Extensiones de nombre de archivo y require() PHP no examina la extensi6n del nombre de archivo en el archivo requerido. Esto significa que puede asignar el nombre que desee a su archivo siempre y cuando no tenga previsto llamarlo directamente. A1 utilizar r e q u i r e ( ) para cargar el archivo, se convertiri de manera efectiva en parte de un archivo de PHP y se ejecutari como tal. Por regla general, las instrucciones de PHP no se procesarin si estuvieran en un archivo llamado, por ejemplo, p a g e . h t m l . S610 se llama a PHP para analizar archivos a1 definir extensiones como php. Sin embargo, si carga la pigina p a g e . h t m l a traves de una instrucci6n r e q u i r e ( ) , se procesarin todas las instrucciones de PHP incluidas en su interior. Por lo tanto, puede utilizar cualquier extensi6n que desee para archivos de inclusibn, per0 conviene utilizar una convenci6n 16gica, como i n c . Recuerde que si almacena 10s archivos que terminan en . i n c o alguna otra extensi6n no estindaron ekirbol de documentos Web y 10s usuarios 10s cargan directamente en el navegador, podran ver el c6digo en forma de texto sin procesar, incluidas las contraseiias. Por lo tanto, es importante almacenar 10s archivos de inclusi6n fuera del arb01 de documentos o utilizar extensiones estandar.
.
.
Etiquetas de PHP y require() En nuestro ejemplo, el archivo reutilizable ( r e u s a b l e . php) se escribe de la siguiente forma:
/ > I ;
?>
El c6digo de PHP se coloca dentro del archivo en etiquetas de PHP. Necesitari realizar esta operaci6n si desea que el c6digo PHP incluido en el archivo requerido sea tratado como c6digo de PHP. Si no abre una etiqueta de PHP, su c6digo seri tratado como texto o cddigo HTML y no se ejecutari.
Desnrrollo Web con PHP y MySQL
!)so do require0 para olantillas de sitios Web Si las piginas Web d e su compaiiia presentan un aspecto visual y operativo uniforrne, puede utilizar PHP para agregar la plantilla y 10s elernentos estindar utilizandorequire ( ) . Por ejernplo, las p6ginas del sitio Web de la compafiia TLA Consulting presentan la apariencia que se muestra en la figura 5.2. Cuando se necesita crear una nueva psgina, el desarrollador puede abrir una existente, recortar el texto del archivo e introducir el nuevo texto, y guardar el archivo con otro nornbre.
I
Archrm EdlaOn Ver Favorlloa Henam~enlas Ayuda
.I
.4 I,
Welcome to the home of TLA Consulting. Please take some time to get to know us.
Ii
W e specialiie in s e ~ n g your business needs and hope to hear from you soon.
Figura 5.2. El sitio W e b de T LIA Consulting presenta un aspecto visual y operativo ' estandar en todas sus paginas
Considere la siguiente situaci6n: imagine un sitio Web que lleva rnucho tiernpo activo y consta d e decenas, centenas o miles d e piiginas con un estilo corntin. Entonces se toma la decision d e cambiar parte d e s u aspecto. Puede tratase d e un cambio pequefio, corno agregar una direction d e correo electronic0 a1 pie d e pigina d e todas las pAginas o incluir una nueva entrada en el menu d e navegacion. Seguro clue n o le apetece aplicar este pequefio cambio a todas las p6ginas. La posibilidad de reutilizar secciones de c6digo HTML comunes a todas las piginas es una opcion mucho m$s prActica que cortar y pegar 10s cambios e n decenas, centenas o miles piginas. En el listado 5.1 se recoge el codigo fuente d e la pigina d e inicio (home. h t m l ) ilustrada en la figura 5.2. Listado 5.1. home.html. Codigo HTML de la pagina de inicio de TLA Consulting
5. Reutilizacidn de cddigo y creacidn de funciones TLA Consultinq Pty Ltd
< ! page header -> <:td aliqn="riqht"> <:hl>TLA Consulting | ispan c l a s s = " m e n u " > H o m e < / s p a r ~ > < / t d > | C o n t a c t < / s p a r ~ > < / t d > | | |
-
-
! page content -> We specialize in serving your busir~ess needs and hope to hear from you soon. <
< ! - page footer ->
Desarrollo W e b con PHP y MySQL
En el listado 5.1 puede ver que el archivo consta de un numero de secciones distintas. El encabezado contiene las definiciones CSS (del ingles, Cascading Style Sheet, Hoja de estilo en cascada) utilizada por esta pdgina. La secci6n titulada "page header" (encabezado de pigina) muestra el nombre de la compaiiia y el logotipo, la secci6n "menu bar" (barra de menus) crea la barra de navegaci6n de la pdgina y la secci6n "page content" (contenido de pdgina) integra el texto exclusivo de esta pdgina. A continuacibn, aparece el pie de pdgina. Podemos dividir este archivo y designar las distintas partes como h e a d e r . i n c , home. p h p y f oo t e r .i n c . Las secciones h e a d e r . i n c y f o o t e r .i n c contendrdn c6digo que se reutilizard en otras pdginas. El archivo home. p h p sustituye a home. h t m l y contiene el texto exclusivo de esta pdgina y dos instrucciones r e q u i r e ( ) como se muestra en el listado 5.2. Listado 5.2. horne.php. El codigo PHP que produce la pagina de inicio de TLA
! page cc,ntent -> cpjwelcome to the home of TLA Consultinq. Please take some time to get to know us.We specialize in serving your business needs and hope to hear from you soon.
?>
-
La instrucci6n r e q u i r e ( ) de home. p h p carga 10s archivos h e a d e r . i n c y footer. inc.
-
Como se mencion6, el nombre asignado a estos archivos no afecta a la forma en la que se procesan a1 llamarlos con r e q u i r e ( ) . Una convenci6n habitual, aunque del todo opcional, consiste en llamar a archivos parciales que terminardn incluidos en otros archivos a l g o .i n c (aqui i n c equivale a incluir). Tambien resulta habitual, ademds de conveniente, colocar 10s archivos que se incluirdn dentro de un directorio a1 que puedan acceder sus secuencias de comandos per0 no permitir que se carguen individualmente a traves del servidor Web. De esta forma impediremos su carga, lo que dard lugar a a) que se produzcan errores si la extensi6n del archivo es .p h p per0 s610 contienen una pdgina o secuencia de comandos parcial o b) permitir que se pueda leer el c6digo fuente si ha utilizado otra extensi6n. El archivo h e a d e r . i n c contiene las definiciones de CSS utilizadas por la pdgina, las tablas que muestran el nombre de la compaiiia y 10s menus de navegaci6n como se ilustran en el listado 5.3. El archivo f o o t e r . i n c contiene la tabla que muestra el pie de pdgina en la parte inferior de cada pdgina. Este archivo se muestra en el listado 5.4.
5. Reutilizacidn de cddigo y creacidn defunciones Listado 5.3. header.inc. El encabezado reutilizable para todas las paginas Web de TLA TLA Consulting Pty Ltd
< ! page header > ctd align="left">
-> itd width="25%"> r  C o n t a c t < / s p a r ~ > < / t d > Services | Site Map |
< ! - menu
Listado 5.4. footer.inc. El pie de pagina reutilizable para todas las paginas Web de TLA <
! page footer -> hcopy; TLA Consulting Pty Ltd. < / td>
Este enfoque facilita la tarea de lograr una apariencia uniforme en un sitio Web y permite crear una pigina Web con el mismo etilo escribiendo algo asi como: Here is the corltent for this page
Pero incluso tras crear una gran cantidad de piginas utilizando este encabezado y este pie de pigina, resulta sencillo modificar sus respectivos archivos. Con inde-
pendencia del tip0 de carnbio que desee realizar (una pequefia variacidn o modificar el disefio completo del sitio), s610 necesitarfi realizar el carnbio una vez. No tendri que variar cada pigina del sitio porque todas ellas se cargan en 10s archivos de encabezado y pie de pigina. El ejemplo visto utiliza unicamente HTML en el cuerpo, en el encabezado y en el pie de pigina. Pero no tiene por qu6 ser asi. Dentro de estos archivos, podriamos utilizar instrucciones de PHP para generar dinfimicamente partes de las piginas.
Uso de auto-prepend-file y auto-append-file Si queremos utilizar la instruccidn r e q u i r e ( ) para agregar el encabezado y el pie de pigina de todas las piginas, existe otra forma de hacerlo. Dos de las opciones deconfiguraci6ndelarchivophp.incsonauto-p r e p e n d -f i l e y a u t o -a p p e n dfile.
-
-
Si asignamos estas opciones a 10s archivos de encabezado y pie de pigina, estaremos seguros de que se cargarfin antes y despu6s de cada pigina. En Windows, la configuraci6n presentari este aspecto: a u t o prepend-file = "c:/inetpub/include/header.incCC auto append-file = "c:/inetpub/include/footer.inc" --
-
En UNIX, la configuraci6n presentari este aspecto: a u t o prepend-file = "/horne/username/include/header.inc" auto-append-file = "/horne/usernarne/include/footer.inc" -
Si utiliza estas directivas no necesitari escribir las instrucciones r e q u i r e ( ), per0 10s encabezados y pies de pigina dejarin de ser opcionales. Si esti utilizando un servidor Web Apache, puede cambiar varias opciones de configuraci6n como 6stas en directorios individuales. Para ello, debe configurar el servidor para permitir que el archivo o archivos de configuraci6n principales Sean sustituidos.
5. Reutilizacidn de cddigo y creacidn de funciones
Para configurar las funciones de anexi6n a1 principio o a1 final de un directorio, Cree un archivo llamado .h t a c c e s s en el directorio. Este archivo debe contener las siguientes dos lineas: p h p -v a l u e p h p -v a l u e
a u t o prepend-file a u t o append file -
-
"/horne/usernarne/include/header.inc" "/horne/usernarne/include/footer.inc"
Fijese en que la sintaxis resulta ligeramente diferente con respecto a la misma opci6n en php.ini asi como el elemento p h p v a l u e situado a1 principio de la linea. No hay signo igual. Tambih puede alterar-otra serie de pardmetros de configuraci6n de esta forma. La sintaxis ha cambiado desde PHP 3. Si estd utilizando una versi6n antigua de PHP, las lineas del archivo h t a c c e s s presentardn este aspecto:
.
php3-auto-prepend-file php? a u t o a p p e n d f i l e -
-
-
/horne/username/include/header.inc /horne/username/include/footer.inc
La posibilidad de establecer opciones en el archivo . h t a c c e s s en lugar de hacerlo en el archivo php.ini o en 10s archivos de configuraci6n de su servidor Web brindan una gran versatilidad. Puede alterar 10s pardmetros en un equipo compartido que s610 afecte a sus directorios. No es necesario reiniciar el servidor Web ni disponer de acceso de administrador. Una de las desventajas del metodo . h t a c c e s s es que 10s archivos se leen y se analizan cada vez que se solicita un archivo de dicho directorio en lugar de uno a1 inicio, lo que afecta a1 rendimiento.
Uso de include() Las instrucciones r e q u i r e ( ) y i n c l u d e ( ) son pricticamente identicas. La unica diferencia entre ambas es que cuando fallan, la instrucci6n r e q u i r e ( ) devuelve i instrucci6n i n c l u d e ( ) devuelve una advertencia. un error terminal, mientrasque k Existe un cambio en cuanto a1 funcionamiento de estas instrucciones. En las versiones de PHP anteriores a la 4.0.2, existian diferencias importantes en su funcionamiento. Si estd utilizando una versi6n antigua de PHP, lea las siguientes lineas. La instrucci6n i n c l u d e ( ) se evalua cada vez que se ejecuta y no se evalua si no se ejecuta. La instrucci6n r e q u i r e ( ) se ejecuta la primera vez que se analiza la instrucci6n, independientemente de si el bloque de c6digo que la contiene se ejecuta. Este hecho no tiene mucha importancia si el trdfico del servidor es reducido per0 implica que el c6digo que incluya instrucciones r e q u i r e ( ) dentro de estructuras condicionales resultarii ineficaz. if ($variable
==
true)
i require('filel.incl); else
I require('file2.inc1);
Desnrrollo Web con PHP y MySQL
Este codigo cargari innecesariamente ambos archivos cada vez que se cargue la secuencia de comandos, per0 s610 utilizari una en funci6n del valor de $ v a r i a b l e . Sin embargo, si el c6digo se ha escrito utilizando dos instrucciones i n c l u d e ( ) , s610 se cargari uno de 10s archivos y se utilizard como en la siguiente versi6n: ifi$variable
==
true)
1 include('filel.inc');
I else
1 include('file2.inc');
A diferencia de 10s archivos cargados a traves de una instrucci6n r e q u i r e ( ) , aquellos cargados con i n c l u d e ( ) pueden devolver un valor. Por lo tanto, podemos indicar a otras partes del programa sobre el &xitoo el fa110 del archivo incluido o devolver una respuesta o resultado. Si vamos a abrir archivos muchas veces, podemos encargar la tarea a un archivo de inclusi6n en lugar de volver a escribir las mismas lineas de codigo en cada ocasi6n. Este archivo podria llamarse "openf i l e . i n c " y presentaria un aspect0 parecido a1 siguiente:
1 echo ' Oh No! I could not open the file. '; return 0 ; 1
else [
return 1;
I
-
-
?>
Este archivo intentari abrir el archivo $name utilizando el mod0 indicado en $mode. Si fallara, devolveria un mensaje de error y un 0. Si tuviera &xito,devolveria un 1y no generaria ningun mensaje. Puede llamar a este archivo en una secuencia de comandos de la siguiente forma: $name = 'file.t.xt ' ; $mode 'r'; $result = include('openfile.phpl); if ( $result == 1 )
-
i
/ / haga l o que desee hacer curl el archivo / / haga referencia a $fp creado en el archivo d e
inclusidn
1
Tenga en cuenta que podemos crear variables en el archivo principal o en el de inclusi6n u obligatorio, y que la variable existird en ambos.
Este comportamiento es el mismo para las instrucciones r e q u i r e ( ) y i n c l u d e ( ) . No puede utilizar r e q u i r e ( ) de la misma forma que se ha mostrado aqui porque no es posible devolver valores desde esta instrucci6n. La devolution de valores puede resultar util porque nos permite notificar a otras partes del programa sobre un fallo, realizar procesamientos independientes o devolver una respuesta. Las funciones proporcionan un mecanismo que resulta incluso mejor para dividir el c6digo en m6dulos aut6nomos, como veremos en la siguiente secci6n. Si se estii preguntando por qu4 deberia utilizar r e q u i r e ( ) ,dadas las ventajas de la instruccidn i n c l u d e ( ) sobre r e q u i r e ( ) ,la respuesta que es que resulta ligeramente mfis rfipida. Como se mencion6 anteriormente, este comportamiento ha cambiado, por lo que puede evitar el problema actualizando su versi6n de PHP.
Uso de las funciones de PHP La mayoria de 10s lenguajes de programaci6n constan de funciones. 6stas se utilizan para separar el c6digo que realiza una tarea simple y bien definida. Las funciones facilitan la lectura del c6digo y nos permiten volver a utilizarlo cuando necesitamos realizar la misma tarea. Una funci6n es un m6dulo de c6digo aut6nomo que establece una interfaz de llamada, realiza alguna tarea y, opcionalmente, devuelve un resultado. Ya hemos visto una serie de funciones. En 10s capitulos anteriores, hemos llamado a varias funciones integradas en PHP. Tambien hemos creado algunas funciones sencillas y se han comentado. En esta secci6n vamos a analizar en mayor detalle las operaciones de llamar y desarrollar funciones.
Llamada de funciones La siguiente linea representa la llamada miis sencilla a una funci6n: nornbre f u n c i 6 n O ; -
Esta linea llama a una funci6n denominada nornb r e f u n c i 6 n ( ) que no requiere pariimetros. Esta linea de c6digo ignora cualquier valor que pudiera devolver la funci6n. Existen varias funciones que se llaman de la misma forma. La funci6n p h p i n f ( ) suele resultar util para realizar pruebas porque muestra la versi6n de PHP instalada, informaci6n sobre PHP, la configuraci6n del servidor y valores sobre varias variables de PHP y de servidor. Esta funci6n no toma parfimetros y por regla general ignora el valor devuelto. Las llamadas a p h p i n f o ( ) presentan este aspecto:
La mayor parte de las funciones requieren uno o miis parfimetros: informaci6n que se le da a una funci6n a1 llamarla y que influye sobre el resultado de la ejecucion de la
Desarrollo Web con PHP y MySQL
funci6n. Los pardmetros se pasan colocando 10s datos o el nombre de una variable con 10s datos incluidos dentro del parhtesis tras su nombre. La llamada a una funci6n con un parfimetro presenta este aspecto: nombre funci5n('par6metro'); -
En ese caso, el parfimetro utilizado es una cadena que contiene unicamente la palabra p a r a m e t r o , per0 las siguientes llamadas tambikn son correctas segun la funcidn: nornbre funcibn(2); nornbre-funci6n (7.893); nornbre-funcihn(Svariab1e); -
En la ultima linea, $ v a r i a b l e puede ser cualquier tip0 de variable de PHP, incluso una matriz. Un parfimetro puede ser cualquier tip0 de datos per0 las funciones concretas suelen necesitar tipos de datos dados. Para saber cufintos parfimetros tom6 una funcibn, qu6 representa cada uno de ellos y el tip0 que necesitan, basta con consultar su sintaxis. A1 describir las funciones solemos incluir su sintaxis. A continuacibn, se recoge la sintaxis de la funcidn f o p e n ( ) : int fopen ( string n o m b r c d z - a r c h i vo, u s a r r u t a-i n z l u s i d n ] ) ;
string
modo,
[ int
-
Esta sintaxis nos indica varias cosas y es importante saber interpretarlas. En concreto, el termino i n t que aparece delante del nombre de la funci6n indica que devolver6 un valor entero. Los parfimetros de la funcidn se incluyen dentro de 10s par6ntesis. En el caso de f o p e n ( ) tenemos tres. El nombre del archivo y el mod0 son cadenas y el parfimetro es un entero. Los corchetes que rodean a la expresidn usar-ruta-inclusidn indican que se trata de un parfimetro opcional. Po
Este cddigo llama a la funci6n f o p e n ( ) . El valor devuelto se almacenarfi en la variable $ f p. Hemos optado por pasarle una variable llamada $name que contiene una cadena que representa el archivo que queremos abrir y una variable llamada $openmode que contiene una cadena que representa el mod0 en el que queremos abrir el archivo. En cuanto a1 tercer parfimetro opcional, hemos decidido no utilizarlo.
C6mo llamar a una funci6n no definida Si intenta llamar a una funci6n que no existe, obtendrfi un mensaje de error como el ilustrado en la figura 5.3.
5. Retrtilizncidr~de c6digo y creacidn d e funciones
Fatal error: Call to unsupported or undefined function functionname() in /hon1e/hoolrlpublic~htnd/chnpter5!m1delimedphp on line 6
1 .
Figura 5.3. Este mensaje de error es el resultado de llamar a una funcion que no existe
Los mensajes de error que PHP devuelve suelen ser d e gran utilidad. ~ s t nos e indica exactamente en qu6 archivo tuvo lugar el error, en qu6 linea d e la secuencia d e comandos y el nombre d e la funci6n que intentamos llainar. De esta forma resultarri muy sencillo buscar error y corregirlo. Si se recibe este mensaje d e error, hay que comprobar dos cosas:
1. i E s t i escrita correctamente la funcibn? 2. ~ E x i s t ela funci6n e n la versi6n d e PHP que e s t i utilizando? No siempre resulta sencillo recordar como se escribe una funci6n. Por ejemplo, algunos nombres d e funci6n formados por dos palabras utilizan un p i o n bajo para separarlas y otras no. La funci6n stripslashes ( ) se compone d e dos palabras juntas mientras que la funci6n strip tags ( ) utiliza un gui6n bajo para separar sus dos palabras. Si se escribe incorrectamente el nombre d e una funci6n en una llamada se devolveri el error ilustrado en la figura 5.3. Muchas d e las funciones que utilizamos en este libro n o existen en PHP 3.0 ya que asumimos que est6 utilizando la version PHP 4.0. En cada nueva version se definen nuevas funciones por lo que las nuevas funcionalidades y el mayor rendimiento justifican la actualizaci6n. Si desea saber cuando se ha agregado una funci6n concreta, puede consular el manual en linea. Si intenta llamar a una funci6n no declarada en la versi6n que est6 ejecutando obtendrfi como resultado un error como el que se ilustra en la figura 5.3.
Funciones y el uso de mavusculas y minusculas Recuerde que las llamadas a funciones n o discriminan entre maytisculas y minilsculas por lo que las secuencias function name ( ) , Func t ion-Name ( ) o FUNCTION NAME ( ) son igualmente vilidas y devuelven el mismo resultado. Pued e utilizar el patr6n que le resulte m i s sencillo d e leer pero debe intentar mantener cierta uniformidad. En este libro, asi como en la mayor parte d e la documentation d e PHP, se utilizan las minusculas como convention. Es importante recordar que 10s nombres d e funcion se comportan d e manera diferente a 10s nombres d e variable. Los nombres d e variable discriminan entre maylisculas y minhculas, por lo que $ ~ a m ye $name serin dos variables diferentes mientras q u e Name ( ) y name ( ) identifican la misma funci6n.
Desarrollo W e b con PHP y MySQL
En 10s capitulos anteriores se ha incluido una gran cantidad de ejemplos sobre el uso d e las funciones que incorpora PHP. Sin embargo, el verdadero potencial de un lenguaje de programacidn se mide por su capacidad para crear funciones propias.
#or quC deberia crear funciones propias? Las funciones incorporadas de PHP nos permiten interactuar con archivos, utilizar una base de datos, crear grificos y establecer conexiones a otros servidores. Sin embargo, a lo largo de su vida profesional descubrird muchas veces que necesita realizar una operacidn no prevista por 10s creadores del lenguaje. Afortunadamente, PHP permite crear funciones para realizar cualquier tarea deseada. Con toda probabilidad, su cddigo combinari funciones existentes con ldgica propia desarrollada para realizar una tarea. Si esti escribiendo un bloque de cddigo que probablemente desee utilizar de nuevo en varios puntos de una secuencia de comandos o en varias secuencias de comandos, es aconsejable que declare dicho bloque en forma de funcidn. La declaracidn de una funcidn permite utilizar el cddigo creado de la misma forma que las funciones incorporadas. Bastari con llamar a la funcidn y definir 10s parimetros necesarios, lo que implica que puede llamar a la funcidn y volver a utilizarla varias veces en la secuencia de comandos.
Estructura bisica de una funcion La declaracidn de una funcidn crea o declara una nueva funcidn. La declaracidn comienza con la palabra clave function, incluye el nombre de la funcidn, 10s pardmetros obligatorios y conJiene el cddigo que se ejecutard cada vez que se llame a la funcidn. A continuacio'n, se recoge el ejemplo de una funcidn trivial:
I echo ' M y function was called';
1
Esta declaracidn de funcidn comienza con el t6rmino function, para que 10s lectores humanos y el analizador de PHP sepan que lo que viene a continuaci6n es una funcidn definida por el usuario. El nombre de la funcidn es m y -function. Podemos llamar a nuestra nueva funcidn con la siguiente instruccidn: my-function
( ) ;
Como habri supuesto, la llamada a esta funci6n devolveri la frase "My function was called" en el navegador. Las funciones integradas estin disponibles para su uso en todas las secuencias de comandos de PHP, per0 si declara sus propias funciones, s610 estarin disponibles
5 . Reutilizacio'n de cddigo y creacio'n de funciones
para la secuencia o secuencias de comandos en las que se declaren. Conviene incluir en un archivo las funciones rnds utilizadas y recurrir a un instrucci6n r e q u i r e ( ) dentro de las secuencias de comandos para acceder a ellas. Dentro de una funci6n, las llaves encierran el c6digo que realiza la tarea requerida. En su interior se pueden incluir todos aquellos elementos vhlidos de PHP como llamadas de funci6n, declaraciones de nuevas variables o funciones, instrucciones r e q u i r e ( ) o i n c l u d e ( ) y c6digo HTML. Si queremos salir de PHP dentro de una funci6n y escribir HTML, podemos hacerlo de la misma forma que en cualquier otra parte de la secuencia de comandos: mediante una etiqueta de cierre de PHP seguida del c6digo HMTL. A continuaci6n se recoge una modificaci6n vdlida del ejemplo anterior que genera el mismo resultado:
function my_functlon()
1 ?>
My function was called
1 ?>
Fijese en que el c6digo de PHP aparece encerrado entre etiquetas de apertura y cierre de PHP. En la mayor parte de 10s ejemplos de c6digo utilizados en este libro se incluyen estas etiquetas. En este caso se muestran porque resultan necesarias dentro del ejemplo asi como por encima y por debajo de 61.
Designaci6n de funciones Lo mds importante que recordar a la hora de asignar nombres a las funciones es Si su funci6n crea un encabezado de phgina, que deberian ser cortos y de_scri~tivos. e n c a b e z a d o p a g ( ) o e n c a z a d o -p a g serian buenas elecciones. A continuaci6n se indican varias limitaciones: No se puede utilizar el mismo nombre asignado a una funci6n existente. El nombre de la funci6n s610 puede contener letras, digitos y guiones bajos. El nombre de la funci6n no puede comenzar por un digito. Muchos lenguajes permiten volver a utilizar nombres de funciones. Esta opci6n se conoce como sobrecarga de funciones. Sin embargo, PHP no admite esta posibilidad por lo que sus funciones no pueden tener el mismo nombre que una funci6n incorporada o una funci6n existente definida por el usuario. Fijese en que aunque las secuencias de comando de PHP conocen las funciones integradas en el lenguaje, las funciones definidas por el usuario s610 existen en las secuencias de comandos declaradas. Por lo tanto, podemos volver a utilizar el nombre de una funci6n en un archivo diferente aunque esta prhctica genera confusi6n y deberia evitarse.
Los siguientes nombres de funci6n son vilidos: name ( ) name2 ( ) name-three ( namefour (
) )
Estos otros no lo son: 5name [ ) name-six fopen (
( )
(El iiltimo seria vilido si no existiese una funci6n con el mismo nombre.)
Parimetros Para poder realizar su trabajo, la mayor parte de las funciones requieren el uso de uno o varios parimetros. Un parimetro permite pasar datos dentro de una funci6n. A continuaci61-1,se recoge el ejemplo de una funci6n que requiere un parimetro. Esta funci6n toma una matriz unidimensional y la muestra en una tabla. function create-table($data)
I echo '\nn'; $value = next($data);
I
-
-
echo '';
1
Si llamamos a la funci6n c r e a t e-t a b l e ( ) de la siguiente forma: $myparray = array('Line one.','Line two.','Line three.'); create-table ( $my-array) ;
se generari el resultado ilustrado en la figura 5.4. Los pardmetros nos permiten obtener datos creados fuera de la funci6n (en este caso la matriz $ d a t a ) dentro de la funci6n. Como ocurre con las funciones incorporadas, las definiciones establecidas por el usuario pueden tener varios pardmetros asi como pardmetros opcionales. Podemos mejorar la funci6n c r e a t e t a b 1 e ( ) de varias formas, per0 una de ellas podria consistir en permitir que el i&ocador especifique el borde de la tabla u otros atributos. A continuaci611, se recoge una versi6n mejorada de la funci6n. Resulta muy similar, per0 nos permite establecer la anchura del borde de la tabla asi como el espacio y relleno de las celdas.
5. Reutilizacioir de co'digo y creacidn de f'uizciorzes
Line one.
Eme WO.
Line Lh;e<
-
-
Figura 5.4. Esta tabla HTML es el resultado de llarnar a la funcion create-table()
El primer parsmetro c r e a t e t a b l e 2 ( ) sigue siendo obligatorio. Los otros tres parimetros son opcionales p&pe se han definido valores predeterminados. Podemos obtener un resultado muy similar a1 ilustrado en la figura 5.4 con la siguiente llamada a c r e a t e-t a b l e 2 ( ) .
Si queremos mostrar los~misfiosdatos con m i s detalles, podriamos llamar a la funci6n d e la siguiente forma:
No es necesario indicar 10s valores opcionales (podemos suministrar algunos e ignorar otros). Los parimetros se a s i g n a r h de izquierda a derecha. Recuerde que no se puede dejar sin definir un parimetro opcional y definir otro situado por detris. En este ejemplo, si desea pasar un valor para c e l l s p a c i n g , tambi6n deberi pasar otro c e l l p a d d i n g . ~ s t asuele ser una fuente c o m h d e errores d e programaci6n. Tambien es la raz6n por la que 10s parimetros opcionales se especifican a1 final en cualquier lista d e parfimetros. La siguiente llamada d e funci6n:
resulta perfectamente vilida: establece $ b o r d e r en 3 y deja 10s parimetros S c e l l p a d d i n g y $ c e l l s p a c i n g en sus valores predeterminados.
Desarrollo Web con PHP y MySQL
C(FR
Es posible que se haya fijado en que cuando necesitamos utilizar variables dentro de un archivo requerido o incluido, basta con declararlo en la secuencia de comandos antes de la instruccidn r e q u i e r e ( ) o i n c l u d e ( ) , per0 a1 utilizar una funcibn, pasamos dichas variables dentro de la funci6n de manera explicita. Esto se debe en parte a que no existe ningun mecanismo para pasar variables explicitamente a u n archivo requerido o incluido y en parte a que el dmbito de las variables se comporta de forma diferente en las funciones. El Bmbito de una variable controla d6nde resulta visible y el lugar en el que se puede utilizar. Cada lenguaje de programaci6n adopta reglas diferentes a la hora de establecer el Bmbito de las variables. Las de PHP son bastantes simples: El Bmbito de variables declaradas dentro de una funci6n abarca desde la instrucci6n en la que se han declarado hasta las llaves de cierre situadas a1 final de la funci6n. ~ s t eBmbito es el dmbito de funci6n y las variables declaradas asi se denominan variables locales. El dmbito de las variables declaradas fuera de funciones abarca desde la instrucci6n en la que se declaran hasta el final del archivo, per0 no en el interior de funciones. Este Bmbito es el Bmbito global y las variables declaradas asi se denominan variables globales. Las variables superglogales resultan visibles tanto dentro como fuera de las funciones (si desea obtener un listado de estas variables, consulte un capitulo anterior). El uso de las instrucciones r e q u i r e ( ) e i n c l u d e ( ) no afecta a1 Bmbito. Si la instrucci6n se utiliza dentro de una funci6nl se aplicard el Bmbito de la funci6n. Si no se mcue'ntra dentro de una funci6nl se aplica el dmbito de global. La palabra clave g l o b a l se puede utilizar manualmente para especificar que una variable definida o utilizada dentro de una funci6n tiene Bmbito global. Las variables se pueden eliminar manualmente llamando a u n s e t ( $ nornbrev a r i a b l e ) . Una variable deja de tener Bmbito si se elimina. Los siguientes ejemplos le ayudardn a aclarar estos conceptos. El fragment0 de c6digo que se incluye a continuacidn no genera ningun resultado. En concreto, se declara una variable llamada $ v a r dentro de la funci6n f n ( ) . Como la variable se declara dentro de una funci6n, su Bmbito es el de una funci6n y s610 existirB desde donde se declara hasta el final de la funcibn. Cuando volvamos a hacer referencia a $ va r fuera de la funci6n, se crearB una nueva funci6n llamada $ va r . Esta nueva variable tiene dmbito global y estara visible hasta el final del archivo. Por desgracia, si la unica instrucci6n que utilizamos con la nueva variable $ v a r es echo, nunca tendrd un valor.
5. Reutilizacidn d e co'digo y creacio'n defunciones function f n 0
i Svar
=
'contents';
I
echo
Svar;
El siguiente ejemplo muestra lo contrario. En 61 se declara una variable fuera de la funci6n y se intenta utilizar dentro de otra. function
fn()
i echo ' i n s i d e t h e function, Svar = 'contents2'; echo ' i n s i d e t h e function,
t
Svar
=
'.$var.'
/ > I ;
Svar
=
'.$var.'
/ > I ;
-
Svar 'contsnts 1'; f n 0 ; e c h o ' o u t s i d ? t h e function, S v a r
=
'.$var.'
/ > I ;
El resultado de este c6digo serB el siguiente: inside t h e function, Svar = inside t h e function, Svar = contents 2 outside t h e function, Svar = contents 1
Las funciones no se ejecutan hasta que no se llaman, por lo que la primera instrucci6n es $ va r = ' contents 1 ' ;. Csta crea una variable llamada $ va r,con Bmbito global y su contenido es "contents 1". La siguiente instrucci6n ejecutada es una llamada a la funci6n f n ( ) . Las lineas incluidas dentro de la instrucci6n se ejecutan en orden. La primera linea de la funci6n hace referencia a la variable llamada $ va r. A1 ejecutar esta linea, no se puede ver la variable $ va r creada anteriormente, por lo que crea una nueva con Bmbito de funci6n e imprime su valor. Esto crea la primera linea de 10s resultados. ' La siguiente linea de la funci6n establece el contenido de $va r en "contents 2 ". Como estamos dentro de la funcibn, esta linea cambia el valor de la variable $var local, no de la global. La segunda linea del resultado verifica que este cambio funciona. Con esto llegamos a1 final de la funci6n y se ejecuta la secuencia de comandos. La instrucci6n echo demuestra que el valor de la variable global no ha cambiado. Si queremos que una variable creada dentro de una funci6n tenga Bmbito global, podemos utilizar la palabra clave global de la siguiente forma: function
fn()
I global Svar; Svar = 'contents'; echo ' i n s i d e t h e f u n c t i o n ,
Svar
=
'.Svar.'
/ > I ;
1 f n 0 ; echo ' o u t s l l e
the
function,
Svar
=
'
.$var. '
/ > I ;
Desarrollo Web con P H P y MySQL
En el siguiente ejemplo, la variable $var se ha definido como global lo que significa que tras llamar a la funcibn, la variable tambien saldr6 fuera de la funci6n. El resultado de esta secuencia de comandos ser6 el siguiente: inside the function, $var outside t h e function, Svar
= =
contents contents
El Ambito de la variable abarca desde el punto en el que se ejecuta la linea global $var ;. Podriamos haber declarado la funci6n por encima o debajo de la linea de llamada. (Como observarA, existe bastante diferencia entre el Bmbito de funci6n y el Ambito de variable.) La ubicaci6n de la declaraci6n de funci6n no tiene relevancia. Lo importante es el lugar en el que se llame a la funci6n y, por lo tanto, desde el que se ejecuta el c6digo incluido en su interior. T a m b i h puede utilizar la palabra clave global en la parte superior de una secuencia de comandos a1 utilizar por primera vez una variable para declarar que su Ambito abarca la secuencia de comandos. gste es probablemente el uso mBs comun de la palabra clave global. Como puede ver por 10s ejemplos anteriores, resulta perfectamente vBlido volver a utilizar un nombre de variable para una variable dentro y fuera de una funcidn sin que se produzcan interferencias entre ambas. Sin embargo, no conviene utilizar el mismo nombre porque sin un examen atento del c6digo y del Bmbito podria pensarse que se trata de las mismas variables.
Llamadas por referencia frente a llamadas por valor Si desea escribir una f y n c i k llamada increment ( ) que nos permita incrementar un valor, podriamos vernos tentados a escribir lo siguiente: f u n c t i o n i r ~ c r e m e n (t $ v a l u e , $ a m o u n t
=
1)
J
Este c6digo no sirve de nada. El resultado del siguiente c6digo de prueba sera "10". $ v a l u e = 10; irlcrement ( $ v a l u e ); echo Svalue;
Los contenidos de $value no han cambiado. Esto se debe a las reglas de Bmbito. Este c6digo crea una variable llamada $value que contiene 10.A continuaci6n llama a la funci6n increment ( ) . Se crea la variable $value de la funci6n a1 llamarla. Se le agrega una unidad, por lo que el valor de $value pasa a 11 dentro de la funci6n hasta que llega a su fin y volvemos a1 c6digo
5 . Reutilizacidn de cddigo y creacidn de funciones
que la llam6. En este c6dig0, la variable $ v a l u e es diferente porque tiene ambito global y no varia. Una forma de resolver este problema consiste en declarar $ v a l u e en la funci6n como global, per0 esto implica que para poder utilizarla, la variable que queremos incrementar deber6 llamarse $ v a l u e . Una solucidn mejor seria utilizar las llamadas por referencia. La forma normal de llamar a 10s parametros de una funcidn es pasindolos por valor. A1 pasar un pardmetro, se crear6 una nueva variable que contiene el valor pasado. Se trata de una copia del original. Puede modificar este valor como desee, per0 el valor original de la variable fuera de la funci6n seguir6 siendo el mismo. Una solucidn mejor es utilizar las llamadas por referencia. En este caso, cuando se pasa un par6metro a una funcidn, en lugar de crear una nueva variable, la funcidn recibe una referencia a la variable original. Esta referencia tiene un nombre de variable, que comienza por el simbolo del ddlar y se puede utilizar de la misma forma que cualquier otra variable. La diferencia est6 en que en lugar de tener un valor propio, simplemente hace referencia a1 original. Cualquier carnbio realizado a la referencia s610 afectar6 a1 original. Para indicar que un parimetro debe pasarse por referencia se coloca un simbolo & delante del nombre del par6metro en la definici6n de funci6n. No es necesario n i n g h carnbio en la llamada de funci6n. El ejemplo de funcidn anterior, i n c r e m e n t ( ) , se puede modificar para pasar un parimetro por referencia y lograr que funcione correctamente. function
increment(&$value,
$amount
=
1)
Ahora ya disponemos de una funcidn operativa y podemos utilizar el nombre que deseemos para incrementar el valor que nos plazca. Como se indicd anteriormente, resulta confuso utilizar el mismo nombre fuera y dentro de una funcidn, por lo que aplicaremos un nuevo nombre a la variable en la secuencia de comandos principal. El siguiente c6digo d e prueba imprimir6 10 antes d e llamar a i n c r e m e n t ( ) y 11 despuks. $ a = 10; echo $a.'ibr / > I ; i n c r e m e n t ( S a1 ; e c h o $a.' I ;
Final de las funciones La palabra clave r e t u r n detiene la ejecucidn de una funci6n. Cuando una funci6n termina porque todas sus instrucciones se han ejecutado o porque se ha utilizado la palabra clave r e t u r n , la ejecucidn regresa a la llamada de la funcidn.
Desarrollo W e b con P H P y MySQL
Si llama a la siguiente funci6n, s610 se ejecutard la primera instrucci6n e c h o . function t e s t
return0
I echo 'This statement w i l l be e x e c u t e d ' ; return; echo 'This statement w i l l never be e x e c u t e d ' ;
Obviamente, no se trata de una forma muy util de utilizar la instrucci6n r e t u r n . Por regla general, so10 querremos volver desde el centro de una funci6n en respuesta a una condicibn. Por ejemplo, una raz6n habitual para utilizar una instrucci6n r e t u r n es una condici6n de error que detenga una funci6n a1 final. Por ejemplo, si escribimos una funci6n para determinar el numero mds grande de dos especificados, podemos salir de la funcion si falta alguno de 10s numeros. f u n c t i o n l a r g e r ( Sx,
Sy )
i if
( ! i s s e t ( $ s )I I ! i s s e t ( $ y ) )
1 echo 'This return;
f u n c t i o n r e q u i r e s two n u m b e r s ' ;
1 if
(Ssi=Sy) e c h o Sx; else e c k ~ oS y ; echo ' i b r /
> I ;
La funci6n incorporada is s e t ( ) indica si se ha creado una variable y se le ha asignado un valor. En este c6$go, devolvemos un mensaje de error y salimos de la funci6n si uno de 10s par2imetros no lleva definido un valor. Para probarla, utilizamos ! is s e t ( ) , que significa "NO isset()", de manera que la instruccion i f pueda leerse como "si x no estd establecida o si y no estd establecida". La funcion regresard si cualquiera de las dos condiciones resulta ser cierta.Si se ejecuta la instrucci6n r e t u r n , se ignorardn las siguientes lineas de la funci6n. La ejecuci6n del programa regresara a1 punto en el que se invoc6 la funci6n. Si se establecen ambos pardmetros, la funci6n imprimird el mas grande de 10s dos. El resultado del siguiente c6digo:
2.5
1.9 This
function
requires
two
numbers
5 . Reutilizacidn de cddigo y creacidn defunciones
Como devolver valores desde funciones La salida de una funci6n no es la unica raz6n para utilizar la instrucci6n r e t u r n . Muchas funciones utilizan instrucciones r e t u r n para comunicarse con el cddigo que las llam6. En lugar de imprimir 10s resultados de la comparaci6n de la funci6n l a r g e r ( ) , puede que resulte m6s util devolver la respuesta. De esta forma, el c6digo que llame a la funcidn puede decidir si mostrar o utilizarla y c6mo. La funci6n incorporada max ( ) es equivalente y se comporta de esta forma. Podemos escribir la funci6n 1a r g e r ( ) asi: function larger ($x, $y) t
if (!isset($x)ll!isset($y)) return false; else if ($x>=$y) return $x; else return $y;
En este c6digo devolvemos el valor mtis grande de 10s pasados. Obviamente, el valor devuelto serti diferente en caso de error. Si uno de 10s ntimeros desaparece, devolveremos f a l s e . El 6nico pero de este enfoque es que 10s programadores que llamen a esta funcidn deben probar el tip0 de devolucidn con === para asegurarse de que f a 1s e no se confunde con 0. La funci6nmax ( ) de PHP no devuelve nada si se establecen ambas variables y si s610 se establece una, serti la que devolverti. El siguiente c6digo: $a = echo echo echo
1; $b = 2.5; $C = 1.9; larger($a, $b)." "; larger($c, $a)." " ; larger($d, $a)." ";
generarti el siguiente resultado porque Sd no existe y f a l s e no estti visible:
Las funciones que realizan alguna tarea, pero que no necesitan devolver un valor, a menudo devuelven t r u e o f a 1 s e para indicar si se realizan satisfactoriamente o fallan. Los valores booleanos t r u e y fa 1 s e se pueden representar con valores 1y 0, respectivamente, aunque son de tipos diferente.
Bloques de codigo Para declarar que un grupo de instrucciones forma un bloque las colocamos entre llaves. Esta estructura no tendrti efectos sobre el funcionamiento del c6digo pero si
Desarrollo Web con P H P y MySQL
implicaciones especificas como la forma en la que se ejecutan las estructuras de control, como 10s bucles y las estructuras~condicionales. A continuacidn se incluyen dos ejemplos que funcionan de forma muy diferente: Ejemplo sin bloque de c6digo f o r ( S i = 0; S i < 3 ; Slit echo 'Line l < b r / > I ; echo 'Line 2 I;
)
Ejemplo con bloque de c6digo for(Si
=
0;
Si
c:
3;
$i++
)
t echo echo
'Line l
/ > I ; / > I ;
t
En ambos ejemplos, el bucle f o r se itera tres veces. En el primer ejemplo, el bucle f o r s610 ejecuta la linea situada inmediatamente por debajo. El resultado de este ejemplo es el siguiente: Line Line Line Line
1 1
1 2
El segundo ejemplo utiliza un bloque de c6digo para agrupar las dos lineas. Esto implica que el bucle f o r ejecuta ambas lineas tres veces. Line Line Line Line Line Line
1 2
1 2 1 2
Como el c6digo de estos ejemplos est6 sangrado correctamente, es probable que vea la diferencia ensepida. El sangrado del c6digo tiene el objetivo de ayudar a 10s lectores a interpretar visualmente las lineas afectadas por el bucle f o r . Sin embargo, fijese en que 10s espacios no afectan a la forma en la que PHP procesa el c6digo. En algunos lenguajes, 10s bloques de c6digo afectan a1 dmbito de las variables. 6ste no es el caso de PHP.
Recursion PHP admite las funciones de recursi6n. Las funciones de recursi6n se llaman a si mismas. Estas funcione resultan especialmente utiles para navegar por estructuras de datos dindmicas como listas y drboles vinculados. Sin embargo, son pocas las aplicaciones basadas en Web que requieran una estructura de datos de esta comple-
5. Reutilizacidn de cddigo y creacidn de funciones
jidad por lo que el uso de esta funci6n es limitado. La recursi6n se puede utilizar en lugar de la iteraci6n en muchos casos porque ambas permiten realizar una operaci6n de manera repetida. Las funciones recursivas resultan mfis lentas y utilizan mfis memoria que la iteracibn, raz6n por la cual deberia dar prioridad a estfis dtimas. En el listado 5.5 se recoge un breve ejemplo de funci6n recursiva. Listado 5.5. recursion.php. Resulta sencillo invertir una cadena utilizando la recursion
Tambien se muestra la version iterativa. function
reverse-r($str)
I if (strlen($str)>O) reverse-r(substr($str, 1 ) ) ; echo substr($str, 0, 1 ) ; return;
function reverse-i($str) {
for ($i=l; $i<=strlen($str); $i++)
I echo substr($str, -$i, 1 ) ; )
return;
1
En este listado, hemos implementado dos funciones. Ambas imprimen una cadena a1 rev&. La funci6n r e v e r s e r ( ) es recursiva y la funci6n r e v e r s e-i ( ) es iterativa. La funci6n r e v e r s e r ( l t o m a una cadena como parfimetro. A1 llamarla, se llamar6 a si misma y pasarz el pendtimo carficter de la cadena. Por ejemplo, si llama a reverse r i l H e l l o ' ) ; -
-
-
se llamarfi a si misma varias veces con 10s siguientes parfimetros: reverse r ( ' e l l o l ) ; reverse-r('llol); reverse r('1o'); reverse r ( ' o l ) ; reverse-r("); -
-
Cada llamada que realiza a si misma crea una nueva copia del c6digo de funci6n en la memoria del servidor per0 con un parfimetro diferente. Es como si pretend%ramos llamar a una funci6n diferente cada vez. Esto evita que las instancias de la funci6n se confundan. En cada llamada, se prueba la longitud de la cadena pasada. A1 llegar a1 final de la cadena ( s t r l e n ( ) = 0 ) falla la condici6n. La instancia mfis reciente de la funci6n ( r e v e r s e r ( ' ' ) ) seguirfi adelante y ejecutarfi la siguiente linea de c6digo que debe imprimir el primer carficter pasado de la cadena (en este caso, no hay n i n g ~ ncarficter porque la cadena estfi vacia). A continuacibn, esta instancia de la funcidn devuelve el control a la instancia que la llam6, en concreto r e v e r s e -r ( ' o ' ) .
Desarrollo W e b con P H P y MySQL
Esta instruccidn imprime el primer cardcter en su cadena ("0 ") y devuelve el control a la instancia que lo llam6. El proceso continua (se imprime un carticter y se vuelve a la instancia de la funcion superior en el orden de llamada) hasta que el control vuelve a1 programa principal. Las soluciones recursivas presentan un aspect0 muy elegante y matematico. En la mayor parte de 10s casos, sin embargo, resulta mucho mejor utilizar una soluci6n iterativa. El listado 5.5 tambidn incluye la variante iterativa. Como observard, es igual de larga (aunque no siempre es asi) y realiza la misma funci6n. La diferencia principal es que la funci6n recursiva realiza copias de si misma en memoria, lo que implica la sobrecarga de varias llamadas de funci6n. La version recursiva se puede utilizar cuando el c6digo resulta mds breve y elegante que el de la version iterativa, cosa que en este dominio de aplicaciones no suele ocurrir a menudo. Aunque la recursion parece mds elegante, 10s programadores suelen olvidarse de incluir una condition de finalizacion, lo cual implica que la funcion se repetird hasta que el servidor se quede sin memoria o hasta que se exceda el tiempo de ejecucion.
Lecturas adicionales El uso de las funciones i n c l u d e ( ) , r e q u i r e ( ) , f u n c t i o n y r e t u r n tambien se explica en el manual en linea. Si desea saber mas sobre conceptos como el de la recursion, las llamadas por valor o por referencia y el ambito de las variables que afecta a muchos lenguajes, consulte un libro de texto general sobre informdtica.
A continuacion
-
Ahora que ya sabemos utilizar 10s archivos de inclusion, 10s archivos requeridos y las funciones para lograr que nuestro c6digo resulte mds sencillo de mantener y susceptible de utilizar de manera repetida, en el siguiente capitulo se analizara el software orientado a objetos y la compatibilidad que ofrece PHP a1 respecto. El uso de objetos permite lograr objetivos similares a 10s conceptos presentados en este capitulo per0 con ventajas superiores para proyectos complejos.
En este capitulo se explican conceptos relacionados con el desarrollo orientado a objetos y se muestra c6mo implementarlos en PHP. Entre 10s temas clave que trataremos en este capitulo se incluyen 10s siguientes: Conceptos orientados a objetos
-
Creaci6n de clases, atributos y operaciones Uso de atributos de chse
Llamadas a operaciones de clase Herencia Llamadas a mktodos de clases Disefio de clases Desarrollo de c6digo para clases
Conceptos orientados a obietos Los lenguajes de programaci6n modernos suelen admitir o incluso necesitan adoptar un enfoque orientado a objetos para el desarrollo de software. El desarrollo orientado a objetos (00)intenta utilizar las clasificaciones, las relaciones y las propiedades de 10s objetos del sistema para contribuir a1 desarrollo de programas.
6 . PHP orientado a objetos
Clases y obietos En el context0 de software orientado a objetos, un objeto puede ser pricticamente cualquier elemento o concept0 (un objeto fisico como una mesa o un cliente; o un objeto conceptual que s610 existe en el software, como un campo de entrada de texto o un archivo). Por regla general, estaremos mAs interesados en objetos conceptuales, incluidos objetos del mundo real que necesitan representarse en software. El software orientado a objetos se diseiia y construye como un conjunto de objetos independientes con atributos y operaciones que interactuan para cubrir nuestras necesidades. Los atributos son propiedades o variables relacionadas con el objeto. Las operaciones son mktodos, acciones o funciones que el objeto realiza para modificarse a si mismo o para obtener algun efecto externo. La ventaja principal del software orientado a objetos es su capacidad para admitir o fomentar la encapsulaci6n, t a m b i h conocida como ocultaci6n de datos. BAsicamente, el acceso a 10s datos dentro de un objeto s610 estA disponible a travks de operaciones con objetos, conocida como la interfaz del objeto. La funcionalidad de un objeto estA vinculada a 10s datos que utiliza. Podemos alterar 10s detalles de la implementaci6n del objeto para mejorar el rendimiento, agregar nuevas funciones o resolver errores sin tener que modificar la interfaz, cuyos efectos pueden extenderse a todo el proyecto. En otras Areas del desarrollo de software, la programaci6n orientada a objetos es la norma y el software orientado a funciones se considera desfasado. Por varias razones, la mayor parte de las secuencias de comandos orientadas a objetos siguen, por desgracia, diseiiadas y escritas utilizando una metodologia orientada a funciones. Existen varias razones que explican este enfoque. La mayoria de 10s proyectos Web son relativamente pequeiios y sencillos. En la mayor parte de 10s casos, 10s proyectos Web se pueden desawollar satisfactoriamente sin planificar el enfoque debido a su tamaiio. Sin embargo, si intenta aplicar la misma t6cnica para construir algo de mayor tamaiio, la calidad de 10s resultados se verA afectada, si es que se obtiene algun resultado. Muchos proyectos evolucionan a partir de un conjunto de piginas vinculadas para convertirse en una aplicaci6n compleja. Estas aplicaciones, ya se presenten a trav4s de cuadros de dialog0 y ventanas o.pAginasHTML generadas dinAmicamente, necesitan disponer de una metodologia de desarrollo correctamente ideada. La orientaci6n a objetos puede ayudarle a gestionar la complejidad de 10s proyectos, a incrementar la reusabilidad del c6digo y, por tanto, a reducir 10s costes de mantenimiento. En el software orientado a objetos, un objeto es una colecci6n unica e identificable de datos y operaciones almacenados que operan sobre dichos datos. Por ejemplo, podemos tener dos objetos que representen botones. Aunque ambos tengan el texto "Aceptar", una anchura de 60 pixeles, una altura de 20 pixeles y otros atributos i d h ticos, necesitamos disponer de la posibilidad de trabajar con uno o con el otro. En software, existen variables independientes que actuan como identificadores unicos para dichos objetos.
Desarrollo W e b con P H P y MySQL
Los objetos se pueden agrupar en clases. Las clases representan un conjunto de objetos que puede variar, per0 que deben tener un conjunto de caracteristicas en comun. Una clase contiene objetos con operaciones que se comportan de la misma forma y atributos que representan las mismas cosas, aunque 10s valores de dichos atributos varien de objeto a objeto. Podemos imaginar el tkrmino bicicleta como una clase de objetos que describe muchas bicicletas diferentes con una gran cantidad de caracteristicas o atributos en comun; por ejemplo, que tengan dos ruedas, un color y un tamafio, y realicen operaciones, como moverse. Mi bicicleta es un ejemplo de objeto que encaja en la clase bicicleta Compartiri rasgos comunes a todas las bicicletas, incluida una operacidn de movimiento que se comporta de la misma forma en la mayoria de las bicicletas (aunque apenas la utilice). Mi bicicleta tiene atributos con valores unicos porque es verde y no todas las bicicletas tienen ese color.
Polimorfismo Un lenguaje de programacidn orientado a objetos debe admitir el polimorfismo, lo que significa que las clases pueden tener diferentes comportamientos con respecto a la misma operaci6n. Por ejemplo, si tenemos una clase coche y una clase bicicleta, sus operaciones de desplazamiento sertin diferentes. Para 10s objetos del mundo real, este hecho no plantea un problema ya que es poco probable que se confunda el movimiento de una bicicleta con el de un coche. Sin embargo, un lenguaje de programacidn no posee el sentido comun del mundo real, por lo que el lenguaje debe admitir el polimorfismo para determinar quk operacidn de movimiento utilizar con un objeto dado. El polimorfismo es m i s una caracteristica relacionada con 10s comportamientos que con 10s objetos. En PHP, &lo las funciones de miembro de una clase puede ser polim6rficas. Una comparacidn del mundo real es la de 10s verbos en 10s lenguajes naturales, que equivalen a las funciones de miembro. Considere las formas en las que una bicicleta se puede utilizar en el mundo real. Se puede limpiar, mover, desmontar, reparar o pintar, entre otras cosas. Estos verbos describen acciones genkricas porque no se puede saber el tip0 de objeto sobre el que se actda. (Este tip0 de abstracci6n sobre objetos y acciones es una de las caracteristicas que distinguen a la inteligencia humana.) Por ejemplo, la operacidn de mover una bicicleta requiere acciones completamente diferentes a las necesarias para mover un coche, aunque 10s conceptos sean similares. El verbo mover se puede asociar a un conjunto concreto de acciones una vez que se d6 a conocer el objeto sobre el que se actua.
Herencia La herencia nos permite crear una relaci6n jer6rquica entre clases utilizando subclases. Una subclase hereda atributos y operaciones de su superclase. Por ejem-
6. PHP orientado a objetos
plo, un coche y una bicicleta tienen elementos en comun. Podemos utilizar una clase vehiculo para incluir elementos como un atributo de color y una operaci6n de movimiento comun a todos 10s vehiculos y permitir que nuestras clases coche y bicicleta las hereden. Gracias a la herencia, podemos desarrollar y seguir agregando elementos a clases existentes. A partir de una clase bdsica se pueden derivar clases m& complejas y especializadas a medida que surja la necesidad. Como resultado, nuestro c6digo ser6 m6s reutilizable, lo cual es una de las ventajas m i s importantes de un enfoque orientado a objetos. El uso de la herencia puede ahorrarnos trabajo si las operaciones se escriben una vez en una superclase en lugar de varias veces en subclases diferentes. Tambien puede ayudarlos a modelar de manera m i s exacta relaciones del mundo real. Si se establece una relaci6n 16gica del tip0 "es un/unaVen una frase entre dos clases, es probable que la herencia resulte adecuada. La frase "un coche es un vehiculo" tiene sentido, per0 la frase "un vehiculo es un coche" no lo tiene porque no todos 10s vehiculos son coches. Por lo tanto, el coche puede derivarse desde la clase vehiculo
Creacion de clases, atributos y operaciones en PHP Por el momento, las clases se han estudiado de forma bastante abstracta. A1 crear una clase en PHP, se utiliza la palabra clave cla s s.
Estructura de una clase La definici6n bisica debna ?lase presenta este aspecto: class
nombreclase
i
Para que la clase resulte util necesita tener atributos y operaciones. Para crear atributos se declaran variables dentro de una definici6n de clase utilizando la palabra clave var. El siguiente c6digo crea una clase llamada clas sname, con dos atributos $attribute1 y Sattribute2. class classname var Sattributel; var Sattribute2;
Las operaciones se crean declarando funciones dentro de la definici6n de clase. El siguiente c6digo crea una clase denominada classname con dos operaciones que no hacen nada.
Desarrollo Web con PHP y MySQL
La operacion o p e r a t i o n 1 ( ) no toma par6metros y la operacionoperation2 toma dos par6metros. class
()
classname
t function operat
I function operat
Constructores La mayor parte de las clases constan de un tip0 especial de operacidn llamado constructor. Un constructor se llama a1 crear un objeto y suele realizar tareas utiles de inicializacih como establecer atributos con valores de inicio 16gicos o crear otros objetos necesarios. Un constructor se declara de la misma forma que otras operaciones, pero tiene el mismo nombre que la clase. Aunque podemos llamar manualmente a1 constructor, su funci6n principal es hacerlo automiticamente a1 crear un objeto. El siguiente cddigo declara una clase con un constructor: class classname function classname($param)
i echo "Constructor called with parameter Sparam " ;
1 1
-
-
Recuerde que PHP no admite de manera nativa la sobrecarga de funciones, lo que significa que so10 se puede proporcionar una funcion con un nombre dado, incluido el constructor. (Muchos lenguajes de programacidn orientados a objetos admiten este recurso.) Existe una extensidn experimental que permite la sobrecarga de m6todos get y set, per0 no es muy 6til.
Instanciacion Tras declarar una clase, tenemos que crear un objeto (un elemento concreto que forme parte de una clase) con el que trabajar. Esta tarea tambi6n se conoce como crear una instancia e instanciar una clase. Para crear u n objeto se utiliza la palabra clave new. Es necesario especificar a qu6 clase pertenecer6 el objeto y suministrar todos 10s par6metros que requiera el constructor.
6. PHP orientado a objetos
El siguiente cddigo declara una clase llamada c l a s s n a m e con un constructor y crea tres objetos del tip0 c l a s s name: class
classname
{
function
classname ( S p a r a m )
echo "Constructor called with parameter Sparam " ;
1 1
$a $b $C
= = =
new classname ( 'First' ) ; new classname('Second1); new classname();
Como el constructor se llama cada vez que creamos un objeto, este c6digo genera el siguiente resultado: Constrl~ctor called with parameter First Constrllctor called with parameter Second ConstrLctor called with parameter
Uso de 10s atributos de clase Dentro de una clase, disponemos de acceso a una variable especial llamada $ t h i s . Si un atributo de la clase actual se denominara $ a t t r i b u t e , se utilizaria la
secuencia $ t h i s - > a t t r i b u t e para hacer referencia a 61 a1 establecer o acceder a la variable desde una operaci6n dentro de una clase. El siguiente cddigo muestra cdmo establecer o acceder a un atributo dentro de una clase:
- -
class classname var Sattribute; function operation($param) $this->attribute = Sparam echo $this->attribute; 1
Algunos lenguajes de programacidn nos permiten limitar el acceso a atributos declarando dichos datos como privados o protegidos. PHP no admite esta funcidn, por lo que 10s atributos y operaciones que utilicemos resultardn visibles fuera de la clase (es decir, ser6n todos publicos). Podemos realizar la misma tarea como se demostrd anteriormente desde fuera de la clase, utilizando sintaxis ligeramente diferente. class
i
classname
Desarrollo Web con PHP y MySQL var
Sattribute;
1
$a = new classname ( ) ; $a->attribute = 'value'; echo $a->attribute;
No es buena idea acceder directamente a 10s atributos desde fuera de una clase. Una de las ventajas de u n enfoque orientado a objetos es que fomenta la encapsulation. Aunque en PHP no se puede forzar la ocultacion de datos, con un poco de voluntad se pueden extraer ciertas ventajas. Si en lugar de acceder a 10s atributos de una clase directamente, se escriben funciones de descriptores de acceso, todos 10s accesos se realizarfin a trav6s de una unica secci6n de c6digo. Las funciones de descriptores de acceso pueden presentar el siguiente aspecto a1 principio: class classname
i var Sattribute; function getpattribute()
t return Sthis->attribute;
1 function set-attribute($new-value)
I $this->attribute
=
$new-value;
Este c6digo proporciona funciones para acceder a1 atributo denominado S a t t r i b u t e . Tenemos una funci6n llamada g e t a t t r i b u t e ( ) que devuelve simplementeelvalor de S a t t r i b u t e y u n a f u n c i 6 ~ l l a m a d as e t -a t t r i b u t e ( ) que asigna un valor nuevo a S a t t r i b u t e .
A primera vista, podria pacecer que este c6digo no agrega mucho valor. En su forma actual, es probablemente cierto, per0 la raz6n para suministrar las funciones de descripci6n de acceso es sencilla: s610 tendremos una secci6n de c6digo que accede a dicho atributo. Con un solo punto de acceso, podemos implementar elementos de comprobaci6n para'asegurarnos de que s610 se almacenan datos pertinentes. Si en un momento posterior necesitamos que el valor de $ a t t r i b u t e est6 entre cero y cien, bastarii con agregar unas pocas lineas de c6digo y verificar antes de permitir 10s cambios. Podemos modificar la funci6n s e t -a t t r i b u t e ( ) para que presente esta aspecto: function set-attributeisnew-value) if( $new-value >= 0 Sthis->attribute
&& =
$newvalue <= 100 $new-value;
)
I
Este cambio resulta sencillo, per0 si no utilizamos la funci6n de descriptor de acceso, tendremos que recorrer cada linea de c6digo y modificar cada acceso a $ a t t r i b u t e , lo cual resulta pesado y proclive a errores.
6 . P H P orientado a objetos
Con un solo punto de acceso, podemos cambiar libremente la implementacibn subyacente. Si por alguna razbn, optamos por cambiar la forma en la que se almacena $ a t t r i b u t e , las funciones de descriptor de acceso nos permitirin hacerlo variando el cbdigo en un solo punto. Puede que en lugar de almacenar $ a t t r i b u t e como variable queremos recuperarla tinicamente desde la base de datos cuando resulte necesario, calcular un valor actualizado cada vez que se solicite, inferir un valor de 10s valores de otros atributos o codificar 10s datos con un tip0 de dato m6s pequeiio. Sea cual sea el cambio que decidamos realizar, bastar6 con modificar nuestras funciones de descriptor de acceso. El resto de las secciones de cbdigo no se ver6n afectadas mientras las funciones de descriptor de acceso sigan aceptando o devolviendo 10s datos que esperan otras partes del programa.
Llamadas a operaciones de clase Podemos llamar a operaciones de clases de la misma forma que llamamos a 10s atributos de clase. Si tenemos la siguiente clase: class classname
t function operatiorll (
)
1
I function operatior~2(Spararnl, Spararn2)
t
I
-
1
y creamos un objeto dei tipo c l a s s name llamado $a de la siguiente forma: $ a = new classname();
Seguidamente llamamos a las operaciones de la misma forma que a otras funciones: por su nombre y con todos 10s par6metros que se necesiten entre p a r h t e sis. Como estas operaciones pertenecen a un objeto en lugar de a funciones normales, tenemos que especificar a qut! objeto pertenecen. El nombre del objeto se utiliza de la misma forma que 10s atributos de objeto: $a->operationl(); $a->operation2(12, 'test');
Si nuestras operaciones devuelven algo, podemos capturar 10s datos devueltos de la siguiente forma: $x Sy
= =
$a->operationl(); $a->operation2(12,
'test');
Desarrollo W e b con PHP y MySQL
Implementation de la herencia en PHP Si nuestra clase es una subclase de otra, podemos utilizar la palabra clave e x t e n d s para especificarlo. El siguiente c6digo crea una clase llamada B que se deriva de la clase llamada A previamente definida. class
B
extends
A
1 v a r Sattribute:; funct i n n operation2 ( )
Si la clase A se declara de la siguiente forma: class A
i var Sattributel;
todos 10s accesos siguientes a las operaciones y atributos de un objeto de tip0 B serian vAlidos: S b = new B O ; Sb->operation1 ( 1 ; S b - > a t t r i b u t e 1 = 10; So->operatinn2 ( ) ; Sb->attribute2 = 10;
-
-
Fijese en que como la clase B extiende la clase A, podemos hacer referencia a y $ a t t r i b u t e 1, aunque se declararon en la clase A. Como subclase d e ~B, tiene la misma funcionalidad y 10s mismos datos. Ademds, B ha declarado un atributo y una operaci6n propia. Es importante observar que la herencia s610 funciona en una direcci6n. La subclase hereda las funciones de la clase principal o superclase, per0 6sta no toma ninguna funci6n de aqu6lla. Por lo tanto, las dos siguientes lineas de c6digo serian e r r h e a s : o p e r a t i o n 1( )
$ a = new A ( ) ; $ a - > o p e r a t i m ~ n jl ) ; $a->attribute1 = 10; $a->operation20; = 10; $a->attribute2
La c l a s e no ~ tiene una operaci6n o p e r a t i o n 2
()
ni un atributo a t t r i b u t e 2 .
6. PHP orientado a objetos
Reemplazamientos Hemos mostrado una subclase que declara nuevos atributos y operaciones. Tam, a declarar 10s mismos atributos y operaciobi6n resulta vilido, y a veces ~ t i lvolver nes. Podemos hacerlo para asignar un atributo de la subclase, un valor diferente para el mismo atributo de su superclase o aplicar a una operaci6n de la subclase funcionalidad diferente con respecto a la misma operaci6n de su superclase. Este recurso se denomina reemplazamiento. Por ejemplo, si tenemos una clase A: class A
i var Sattribute = 'default value'; function o p e r a t i o n 0 i echo 'Something I ; echo "The value o f \$attribute is $this->attribute " ;
I 1
y queremos alterar el valor predeterminado de S a t t r i b u t e y suministrar nueva funcionalidad para o p e r a t i o n ( ) , podemos crear la siguiente clase B, que reemplaza S a t t r i b u t e y o p e r a t i o n ( ) : class B extends A
t var Sattrlbute = 'cllfferent value'; function o p e r a t i o n 0 t
echo 'Something else I ; echo "The value o f \$attribute is Sthis->attribute " ;
La declaraci6n de B no afecta a la definici6n original de A. Considere las siguientes dos lineas de c6digo: $a = new A ( ) ; $a -> operationi);
Hemos creado un objeto de tip0 A y hemos llamado a la funci6n o p e r a t i o n ( ) . El resultado seri: Something The value of Sattribute is default valu?
si la creaci6n de B no ha alterado a A. Si creamos un objeto de tip0 B, obtendremos un resultado diferente. El siguiente c6digo: $b $b
=
->
new B ( ) ; operation();
Desarrollo Web con P H P y MySQL
Something The value
else of Sattribute
is
different
value
De la misma forma que el suministro de nuevos atributos y operaciones dentro de una subclase no afecta a la superclase, el reemplazamiento de atributos u operaciones dentro de una subclase no afecta a la superclase. Una subclase heredar6 todos 10s atributos y operaciones de su superclase, a menos que se suministren reemplazamientos. Si suministra una definici6n de reemplazamiento, 6sta tendr6 preferencia y reemplazar6 a la definici6n original. A diferencia de otros leguajes orientados a objetos, PHP no permite reemplazar una funci6n y a la vez llamar a la versi6n definida en la clase superior. La herencia puede tener varias capas de profundidad. Por ejemplo, podemos declarar una clase c, que extienda B y que por tanto herede las funciones desde B y desde la clase superior A. La clase C puede a su vez seleccionar atributos y operaciones de sus clases principales para anularlas y reemplazarlas.
Herencia multiple Algunos lenguajes orientados a objetos admiten la herencia mdtiple per0 no asi PHP. Esto significa que cada clase s610 puede heredarse desde una clase superior. No existen restricciones en cuanto a la cantidad de clases secundarias que puede compartir una clase principal. Puede que este concept0 no resulte claro a1 principio. La figura 6.1 muestra tres formas diferentes de derivar las c l a s e s ~B, y C.
Herencia simple
Herencia multiple
Herencia simple Figura 6.1. PHP no admite la herencia multiple
La combinaci6n de la izquierda muestra la clase c que se hereda de la clase B, que a su vez se hereda de la clase A. Cada clase tiene un elemento superior a1 menos, por lo que se trata de una herencia simple perfectamente factible en PHP.
6 . PHP orientado a objetos
En la combinaci6n central, la clase B y la clase c se heredan de la clase A. Cada clase tiene una clase superior como mdximo, por lo que de nuevo estamos ante una herencia permitida en PHP. La combinaci6n de la derecha muestra la clase c que se deriva de la c l a s e y~ de la clase B. En este caso, la clase c consta de dos clases principales lo que la convierte en una clase no vdlida en PHP.
Diseno de clases Ahora que ya conocemos algunos d e 10s conceptos en 10s que se basan 10s objetos y las clases, y la sintaxis para implementarlos en PHP, ha llegado el momento de examinar c6mo disefiar clases utiles. Muchas clases de nuestro c6digo representan clases o categorias d e objetos del mundo real. Las clases que se utilizan en el desarrollo Web pueden incluir pdginas, componentes de interfaces de usuario, carros d e la compra, resoluci6n de errores, categorias de productos y clientes. Los objetos de su c6digo tambien pueden representar instancias especificas de clases mencionadas previamente, por ejemplo, la p6gina principal, un b o t h dado o el carro de la compra utilizado por Fred Smith en un momento dado. El propio Fred Smith puede representarse mediante un objeto de tip0 cliente. Cada articulo comprado por Fred se puede representar como un objeto que pertenezca a una categoria o clase. En el capitulo anterior, utilizamos sencillos archivos de inclusi6n para proporcionar a nuestra compafiia ficticia, TLA Consulting, un aspecto visual y operativo uniforme en las diferentes pdginas del sitio Web. El uso de las clases y la herencia permite crear versiones m6s avanzadas del mismo sitio. Queremos disponer d e ia pcnibilidad de crear p6ginas riipidamente para el sitio TLA que se comporten de igual forma y presenten un aspecto semejante. Estas piginas se podr6n modificar para su adaptaci6n a diferentes partes del sitio. Vamos a crear una clase Page. El objetivo global de esta clase es limitar la cantidad de c6digo HTML necesario para crear una nueva pigina. Nos permitird alterar las partes que cambian d e una pdgina a otra adem6s d e generar autom6ticamente 10s elementos para que no varien. Las clases ofrecen un marco flexible para crear nuevas pdginas y no deberian comprometer nuestra libertad de acci6n. Como estamos generando la pagina desde una secuencia de comandos en lugar de c6digo HTML estdtico, podemos agregar cualquier elemento que resulte inteligente, incluyendo funcionalidad para: Permitirnos alterar elementos de p6gina en un lugar. Si cambiamos la advertencia sobre 10s derechos de autor o agregamos un b o t h adicional, s610 necesitaremos realizar el cambio en un punto. Disponer de contenido predeterminado para la mayor parte de las pAginas, per0 disponer de la capacidad d e modificar cada elemento donde resulte
Desarrollo W e b con PHP y MySQL
necesario y establecer valores personalizados para elementos como el titulo y las etiquetas meta. Reconocer qu4 pdgina se estd visualizando y alterar 10s elementos de navegacidn para adaptarlos (no tiene mucho sentido tener un b o t h vinculado a la pdgina principal dentro de la pdgina principal). Permitirnos sustituir elementos estandar para pdginas particulares. Por ejemplo, si queremos utilizar diferentes botones de navegacidn en las secciones del sitio, deberiamos disponer de la posibilidad de sustituir 10s estdndar.
Escritura del codigo para nuestra clase Tras decidir el aspect0 que queremos que devuelva nuestro codigo y la aplicacidn de una serie de funciones, jcdmo lo implementamos? En una parte posterior del libro abordaremos el diseiio y la gestidn de proyectos de gran tamaiio. Por el momento, vamos a concentrarnos en las partes especificas relacionadas con la escritura de PHP orientado a objetos. Nuestra clase necesitard un nombre logico. Como representa a una pdgina, se denominard Page.Para declarar una clase llamada Page,escribimos class Page
t
i
Esta clase necesita algunos atributos. Estableceremos 10s elementos que es probable que queramos modificar de una pdgina a otra, como 10s atributos de nuestra clase. El contenido principal de la pdgina, que sera una combinacidn de etiquetas HMTL y texto, se denorrfinarZ $content. Podemos declarar el contenido con la siguiente linea de cddigo dentro de la funcidn de clase. var
$content;
Tambien podemos establecer 10s atributos para almacenar el titulo de la pdgina. Es probable que queramos modificar este elemento para indicar con claridad la pagina que estd visualizando nuestro visitante. En lugar de incluir titulos en blanco, suministraremos un titulo predeterminado con la siguiente declaracidn: var $title
=
'TLA Consulting Pty Ltd';
La mayor parte de las pdginas Web comerciales incluyen etiquetas meta para ayudar a 10s motores de busqueda a indexarlas. Para que resulten utiles, las etiquetas meta deberian cambiar de una pdgina a otra. De nuevo, suministramos un valor predeterminado: var $keywords some of
'TLA Consulting, Three Lette~.Abbreviation, my best friends are search engines';
=
6 . PHP orientado a objetos
Los botones de navegaci6n que se muestran en la pagina original de la figura 5.2 (vkase capitulo anterior) deberian mantenerse entre las diferentes paginas para evitar confundir a 10s usuarios, per0 para poder cambiarlos con facilidad 10s convertiremos en un atributo. Como el numero de botones puede ser variable, utilizaremos una matriz y almacenaremos el texto del bot6n y del URL a1 que deberia apuntar. var $buttons
=
array( 'Home' => 'Cor~tact' => 'Services' => 'Site Map' =>
'home.phpl, 'contact .phpl, 'services.phpT, 'map.phpl
Para proporcionar alguna funcionalidad, la clase tambien necesita operaciones. Podemos comenzar por suministrar funciones de descriptores de acceso para establecer y obtener valores de 10s atributos definidos. fistos suelen adoptar la siguiente forma: function SetContent($newcontent)
t $this->content
=
Snewcontent;
I
Como es poco probable que solicitemos alguno de estos valores desde fuera de la clase, hemos optado por utilizar una colecci6n de funciones Get. La funci6n principal de esta clase es mostrar una pigina de c6digo HTML, por lo que necesitaremos una funci6n. Hemos llamado a la funci6n Display ( ) y presenta de la siguiente forma: function Display (
)
i echo "\n\n"; Sthis -> DisplayTitle ( ) Sthis -> DisplayKey'words ( 1 ; $this -> Displaystyles ( ) ; echo "\n\nn; $this -> DisplayHeaderi ) ; $this -> DisplayMenu($this->buttons); echo $this->content; Sthis -> DisplayFooter ( ) ; echo "\n\n";
c
Esta funci6n incluye varias instrucciones echo sencillas para mostrar c6digo HTML, per0 se compone fundamentalmente de llamadas a otras funciones de la clase. Como es probable que haya supuesto por 10s nombres, dichas funciones muestran partes de la p6gina. No es obligatorio dividir las funciones de esta forma. Todas ellas podrian combinarse en una funci6n de mayor tamaiio. En nuestro caso, las hemos dividido por varias razones. Cada funci6n deberia realizar una tarea definida. Cuanto m i s sencilla sea, m i s ficil resultar5 escribirla y probarla. Tampoco conviene excederse: si divide su programa en unidades demasiado pequeiias puede resultar dificil de leer.
Desarrollo Web con P H P y MySQL
El uso de la herencia permite reemplazar operaciones. Podemos reemplazar la funci6n Display ( ) , per0 es poco probable que queramos cambiar la forma en la que se muestra toda la pigina. Resultari mucho mejor dividir la funcionalidad de visualizaci6n en unas pocas tareas independientes y disponer de la posibilidad de reemplazar s610 las partes que deseemos modificar. Nuestra funci6n Display llama a DisplayTitle ( ) , DisplayKeywords 0, Displaystyles 0, DisplayHeader 0,DisplayMenu ( ) y DisplayFooter 0. Por lo tanto, necesitamos definir estas operaciones. Una de las mejoras de PHP 4 sobre PHP 3 es que podemos escribir operaciones o funciones en orden 16gico. Para ello, se llama a la operaci6n o a la funci6n antes que a1 c6digo de la funcion. En PHP 3 y muchos otros lenguajes, necesitamos escribir la funci6n u operaci6n antes de poder llamarla. La mayor parte de nuestras operaciones son bastante simples y necesitan mostrar HTML y quizis 10s contenidos de nuestros atributos. El listado 6.1 muestra la clase completa, que hemos guardado como page. inc para incluir o exigir dentro de otros archivos. Listado 6.1. page.inc. Nuestra clase proporciona una forrna facil y flexible de crear paginas para el sitio TLA
I / / atributos de la clase Page var $content; var $title = 'TLA Consulting Pty Ltd'; var $keywords = 'TLA Consulting, Three Letter Abbreviation, some of my best friends are search engines'; var Sbuttoris = array ( 'Home' => 'home.phpl, 'Contact' => 'contact.php', 'Services' => 'services.php', 'Site Map' => 'map.php9 1;
-
/ / operaciones de Page
function SetContent($newcontent)
t Sthis->content
Snewcontent;
=
I function SetTitle(Snewtit1e)
I Sthis->title
=
Snewtitle;
1 function SetKeywords(Snewkeywords)
i Sthis->keywords
=
Snewkeywords;
1 function
SetButtons(Snewbuttons)
6 . PHP orientado a objetos
1 $this->buttons
=
Snewbuttons;
I function Display() i echo "\n\n"; $this -> DisplayTitle ( ) ; Sthis DisplayKeywords ( ) ; $this -> DisplayStyles ( ) ; echo "\n\nW; $this -> DisplayHeader ( ) ; Sthis -> DisplayMenu($this->buttons); echo $this->content; $this -> D i s p l a y F o o t e r O ; echo "\n\n";
I function DisplayTitleO
1 echo ' $this->title ';
function DisplayKeywords (
)
I echo "<META name=\"keywords\" c o r l t e r ~ t = \ " $ t h i s - > k e y w o r d s \ " > " ;
I function Displaystyles ( ?>
)
i
-
.menu {color:white; font-size:12pt; text-a1ign:center; font-farnily:&lal, sans-serif; font-weight:bold) td {background: black} p ico1or:black; font-size:12pt; text-a1ign:justify; font-family:arial,sans-serifi
function DisplayHeaderO
I ?>
Desarrollo Web con PHP y MySQL
function DisplayMenu(Sbuttons)
i echo "ctable width='lOO%' bgcolc,r='white' cellpadding='4' cell spacing='l ' \ n W ;
=
each($buttonc))
I Sthis -> DisplayButton($width, $name, Surl, !Sthis-> lsURLCurrentPagt($url));
I echo " \nl'; echo "//table>\nn;
1 function IsURLCurrentPage(Sur1) I
ifistrpos( $GLOBALS['SCRIPT-NAME'], Surl )==false)
I return false; else i return true;
I
-
-
function DisplayButtorl ($width, $name, Surl, $active
=
true)
if (Sactive)
i echo "ctd width ='$width%'> $ r ~ a m e < / s p a r ~ > i / a > < / t d ' " ;
i else
i echo " | TLA Corlsulting Pty Ltd | |
r'
1. Utiliza require para incluir contenidos depage .inc,que contiene la definici6n de la clase Page. 2. Crea una instancia de la clase Page, denominada $homepage.
3. Llama a la operaci6n setcontent ( ) dentro del objeto $homepage y pasa texto y etiquetas HTML para que aparezcan en la p6gina. 4. Llama a la operaci6n Display ( ) dentro del objeto $homepage para obligar a la pdgina a mostrarse en el navegador del visitante.
Desarrollo Web con PHP y MySQL Listado 6.2. home.php. Esta pagina de inicio utiliza la clase Page para realizar la mayor parte del trabajo implicado en la generacion de la pagina
=
new P a g e ( ) ;
Shomepage -> SetContenti'Welcome to the home of TLA Consulting Please take some time to get to know us. We specialize in serving your business needs and hope to hear from you soon. ' i;
Shomepage -> Display(); ?>
Como puede observar en este listado, se necesita realizar muy poco trabajo para generar nuevas piginas utilizando la clase Page. El uso de esta clase de la forma ilustrada implica que todas nuestras piginas deben ser muy similares. Si queremos que una secci6n del sitio utilice una variante de la pagina estindar, bastard con copiar p a g e . i n c en un nuevo archivo llamado p a g e 2 . i n c y realizar algunos cambios. Como resultado, cada vez que actualicemos o modifiquemos partes de la pigina p a g e . i n c necesitaremos acordarnos de realizar 10s mismos cambios en p a g e 2 . i n c . Una opci6n mejor consiste en utilizar la herencia para crear un nueva clase que derive gran parte de su funcionalidad de Page y que reemplace las partes que necesiten ser diferentes. En el sitio de TLA, queremos que la pigina de servicios incluya una segunda barra de navegaci6n. La secuencia de comandos que se muestra en el listado 6.3 realiza esta tarea mediante la creaci6n de una nueva clase llamada S e r v i c e s Page que se deriva de Page. Suministramos una nueva matriz llamada $ r o w 2 b u t t o n s que contiene 10s botones y vinculos que queremos en la segunda fila. Como queremos que esta clase se comporte pricticamente'de la-misma manera, s610 anulamos la parte que queremos modificar: la operacidn D i s p 1a y ( ) . Listado 6.3. services.php. La pagina de servicios se deriva de la clase Page per0 reemplaza Display() para variar el resultado
I var Srow2buttons
=
function Display (
)
array( 'Re-engineering' => 'reengineering.php', 'Standards Compliance' => 'standards.php1, 'Buzzword Compliance' => 'buzzword.phpl, 'Mission Statements' => 'mission.php' 1;
{
echo "\nihead>\nW; DisplayTitlei); Sthis ->
6 . P H P oricntndo n objctos
El sustituto d e D i s p l a y linea m i s
()
es m u y similar con la excepcicin d e q u e contiene una
para llamar a D i s p l a y M e n u ( ) una segunda vez y crear una segunda barra d e menu. Fuera d e la definicicin d e clase, creamos una instancia d e la clase S e r v i c e p a g e , establecemos 10s valores para 10s clue no queremos 10s predeterminados y llamamos a Display ( )
Archm Edtuon Ver F n m t o i Herrm D~remon
I t
A
I
-.x
r I
t
I
Z ~ Lnyvd r 1 i'
At TLA Consulting, we offer a number of services. Perhaps the productivity of your employees would improve if we re-engineered your business. Maybe all your business needs is a fresh mission statement, or a new batch of buzzwords.
Figura 6.2. La pagina de servicios se creo utilizando la herencia para volver a utilizar gran parte de nuestra pagina estandar
Desarrollo Web con P H P y MySQL
Como se ilustra en la figura 6.2, tenemos una nueva variante de la pfigina esttindar. El unico c6digo nuevo que necesitamos escribir es el que hace referencia a las partes diferentes. La creaci6n de pdginas a traves de clases PHP presenta ventajas claras. Con una clase que realice la mayor parte del trabajo por nosotros, necesitaremos realizar menos trabajo para crear una nueva pigina. Podemos actualizar todas las ptiginas de una vez actualizando la clase. La herencia nos permite derivar diferentes versiones de la clase desde el original sin perder sus ventajas. Como ocurre con casi todo en esta vida, estas ventajas tienen un coste. La creaci6n d e paginas desde una secuencia de comandos exige un mayor esfuerzo del procesador que la simple carga de una pdgina HTML estandar desde el disco y su envio a un navegador. En un sitio con trtifico este hecho resultara importante por lo que convendria utilizar ptiginas HTML esttiticas o almacenar en cache el resultado de las secuencias de comandos alli donde resulte posible para cargarlo en el servidor.
La siguiente secci6n aborda el estudio de MySQL. Explicaremos como crear y completar una base de datos de MySQL, y vincularemos lo aprendido a PHP para poder acceder a nuestra base de datos desde la Web.
Ahora que ya se ha familiarizado con 10s fundamentos de PHP, vamos a ver como integrar un base de datos en nuestras secuencias de comandos. En un capitulo anterior comentamos las ventajas de utilizar una base de datos relacional en lugar de un archivo sin procesar:
-
Los RDBMS brindan un acceso mas rapido a 10s datos que 10s archivos sin procesar.
-
Los RDBMS permiten realizar consultas ficilmente para extraer conjuntos de datos que encajen con determinados criterios. Los RDBMS incorporan mecanismos para tratar con accesos simultdneos para no tener que preocuparnos de esta tarea como programadores. Los RDBMS brindan acceso aleatorio a 10s datos. Los RDBMS incorporan un sistema de privilegios. Para ser mas concretos, el uso de una base de datos relacional nos permite responder de forma rapida y sencilla a consultas sobre la procedencia de 10s clientes, 10s productos que se estdn vendiendo mejor o qu6 tip0 de clientes son 10s que mas dinero se dejan. Esta informaci6n puede ayudarle a mejorar el sitio para atraer y fidelizar a 10s clientes. En esta secci6n utilizaremos MySQL como base de datos.
Antes de profundizar en el estudio de las caracteristicas de MySQL en el siguiente capitulo, examinaremos 10s siguientes aspectos: r Conceptos relacionados con las bases de datos relacionales y terminologia r Disefio debases de datos Web r Arquitectura debases de datos Web
Conceptos de base de datos relacionales Las bases de datos relacionales son, con diferencia, el tip0 de base de datos mas utilizado. Estas bases de datos se basan tedricamente en el algebra relacional. No es necesario comprender la teoria para utilizar una base de datos relacional (aunque vendria bien), per0 si conviene comprender algunos conceptos basicos relacionados con las bases de datos.
Tahlas Las bases de datos relacionales se componen de relaciones, conocidas de manera mas comun como tablas. Una tabla es exactamente eso, una tabla de datos. Un ejemplo de tabla relacional es una hoja de calculo electr6nica. Vamos a examinar un ejemplo. En la figura 7.1, puede ver una tabla de ejemplo. Esta tabla contiene 10s nombres y las direcciones de 10s clientes de una libreria, Book-0-Rama.
CustomerlD Name
Address Cily 1 Julie Smith Airport West 25 Oak Street 1147 Haines Avenue Box Hill 2 Alan Wong 3 Michelle Arthur 357 North Road Yarraville
Figura 7.1. Los detalles de 10s clientes de Book-0-Rama se guardan en una tabla
La tabla tiene un nombre (Customers), varias columnas, que hacen referencia a un tip0 diferente de datos, y filas que se corresponden con 10s distintos clientes.
Columnas Cada columna de la tabla tiene un nombre unico y diferentes datos. Cada una de ellas lleva asociado un tip0 de datos. Por ejemplo, en la tabla Customers de la figura 7.1, puede ver que el campo CustomerID es de tip0 entero y las otras tres columnas son cadenas. Las columnas a veces se llaman campos o atributos.
Desarrollo Web con PHP y MySQL
-
--
Cada fila de la tabla representa un cliente distinto. Debido a1 formato tabular, todos tienen 10s mismos atributos. Las filas tambikn se denominan registros.
Cada fila se compone de un conjunto de valores individuales que se corresponden con las columnas. Cada valor debe tener el tip0 de dato especificado por su columna.
Necesitamos disponer de una forma de identificar a cada cliente. Los nombres no son una buena opcion (si tiene un nombre muy utilizado, entenderd por qu6). Tomemos como ejemplo a Julie Smith de la tabla Customers. Si abre una guia de telefonos de 10s EEUU, descubrird una gran cantidad de entradas con ese nombre. Podemos distinguir a Julie de diferentes formas. Es probable que sea la unica Julie Smith que viva en la direcci6n que se indica. Sin embargo, el uso del nombre y la direcci6n en conjunto para distinguir a alguien resulta muy pesado y suena un poco a lenguaje legal. Ademds se necesita utilizar mds de una columna de la tabla. En este ejemplo, lo que hemos hecho, y es probable que se decante por la misma soluci6n en sus aplicaciones, es asignar un numero de identification de cliente exclusivo (CustomerID). Se trata del mismo principio seguido para asignar numeros de cuenta o numero de socios unicos. Esta tecnica facilita el almacenamiento de 10s detalles en una base de datos. Un numero d e identificaci61-1asignado artificialmente garantiza su exclusividad. Existen muy pocos tipos de informaci6n real que dispongan de esta propiedad, aunque se utilicen en una combinaci6n. La columna de identificaci6n de una tabla se denomina clave o clave principal. e el caso si optamos por Las claves pueden constar de varias columnas. ~ s t seria utilizar el nombre y la direccidn de un cliente, per0 su exclusividad no estd garantizada. Las bases de datos suelen constar de varias tablas y utilizan una clave para asociar una tabla a otra. En la figura 7.2, hemos agregado una segunda tabla a la base de datos. En esta tabla se almacenan 10s pedidos realizados por 10s clientes. Cada fila de la tabla Orders representa un unico pedido realizado por un unico cliente. Sabemos quien es el cliente porque almacenamos su CustomerID. Por ejemplo, si examinamos el pedido con OrderID 2, descubriremos que lo ha realizado el cliente con CustomerID 1.A continuaci6n, si examinamos la tabla Customers, veremos que el cliente con CustomerID 1es Julie Smith. El termino utilizado en las bases relacionales para designar esta relaci6n es clave secundaria. La columna CustomerIP es la clave principal de la tabla Customer, per0 cuando aparece en otra tabla, como la tabla Orders, se conoce como clave secundaria. Es posible que se est6 preguntando por qu6 hemos optado por utilizar dos tablas distintas y no almacenar la direccidn de Julie en la tabla Orders. En la siguiente secci6n intentaremos dar respuesta a esta cuesti6n.
7 . Disefio de la base de datos W e b
CUSTOMERS CustomerlD Name 1 Julie Smith 2 Alan Wong 3 Michelle Arthur
ORDERS
Address 25 Oak Street 1147 Haines Avenue 357 North Road
City Airport West Box Hill Yarraville
\
Figura 7.2. Cada pedido de la tabla Orders hace referencia a un cliente de la tabla Customer
Esquemas El conjunto completo de disefios de tabla de un base de datos se conoce como esquema de la base de datos. Es como el esqueleto de la base de datos. Un esquema debe mostrar las tablas con sus columnas, 10s tipos de datos de las columnas e indicar la clave principal de cada tabla y sus claves secundarias. Los esquemas no incluyen datos, per0 se puede incluir un ejemplo para explicar su objetivo. Los esquemas pueden adoptar la forma de diagramas, como 10s que estamos utilizando, diagramas de relaciones de entidad (que no se analizarin en este libro) o pueden tener forma de texto, como Customers(CustomerID, Name, Address, City)
-
Orders(OrderID, CustomerID, Amount, Date)
-
Los t6rminos subrayados con una linea continua en el esquema son las claves principales de la relaci6n. Los terminos subrayados con una linea discontinua son las claves secundarias de la relaci6n en la que aparecen.
Las claves secundarias representan una relaci6n entre 10s datos de dos tablas. Por ejemplo, el vinculo de Orders a Customers representa una relaci6n entre una fila de la tabla Orders y una fila de la tabla Customers. Existen tres tipos bisicos de relaciones en una base de datos relacional. Se clasifican en funci6n del n6mero de elementos que haya a cada lado de la relaci6n. Las relaciones puede ser uno a uno, uno a varios o varios a varios. Una relaci6n uno a uno significa que s610 hay un elemento a cada lado de la relaci6n. Por ejemplo, si hemos colocado direcciones en una tabla distinta a la de clientes, existiria una relaci6n uno a uno entre ambas. Podriamos tener una clave secundaria desde la tabla de direcciones a la tabla de clientes o a1 rev& (no serian obligatorias ambas).
Desarrollo W e b con PHP y MySQL
En una relaci6n uno a varios, una fila de una tabla se vincula a varias filas de otra tabla. En nuestro ejemplo, un cliente podria haber realizado varios pedidos. En estas relaciones, la tabla que contiene varias filas tendrd una clave secundaria hasta la tabla con una sola fila. En este caso, hemos incluido la columna CustomerID dentro de la tabla Order para mostrar la relaci6n. En las relaciones varios a varios, varias filas de una tabla se asocian a varias filas de otra tabla. Por ejemplo, si tememos dos tablas, L i b r o s y A u t o r e s , puede que un libro haya sido escrito por dos autores y que ambos hayan escrito otros libros, en solitario o en colaboraci6n con otros autores. En este tip0 de relaciones se crea una tabla especial para representar las relaciones, con lo que nos tendremos las siguientes: L i b r o s , A u t o r e s , L i b r o s A u t o r e s . La tercera tabla contendrii unicamente las claves de las otras tablas como claves secundarias en pares, para mostrar qu4 autores estdn relacionados con cada libro.
Como diseiiar nuestra base de datos Web La tarea miis dificil consiste en determinar cuiindo se necesita una tabla y cud1 deberia ser la clave. Existe una ingente cantidad de material dedicado a estudiar 10s diagramas de relaci6n de entidad y de normalizaci6n de bases de datos, pero quedan fuera del iimbito de este libro. Sin embargo, en la mayor parte de 10s casos, basta con seguir unos sencillos principios b6sicos de diseiio. Vamos a analizarlos en el context0 de la aplicaci6n Book-0-Rama.
Piense en 10s objetos del mundo real que esta modelando A1 crear una base de datos, lo que hacemos es modelar elementos y relaciones del mundo real, y almacenar la informaci6n sobre dichos objetos y relaciones. Por regla general, cada clase de objeto del mundo real que se modele necesitarii su propia tabla. Piense en ello un momento: queremos almacenar la misma informaci6n sobre todos nuestros clientes. Si existe un conjunto de datos con la misma "forma", podremos crear fiicilmente una tabla que se corresponda con dichos datos. En el ejemplo Book-0-Rama, queremos almacenar la informaci6n sobre nuestros clientes, 10s libros que vendemos y 10s detalles de 10s pedidos. Todos 10s clientes tienen un nombre y una direcci6n. Los pedidos tienen una fecha y una cantidad total, asi como 10s libros pedidos. Los libros constan de ISBN, de un autor, un titulo y un precio. Por lo tanto, parece que necesitamos a1 menos tres tablas en esta base de datos: C u s t o m e r s , O r d e r s y B o o k s . En la figura 7.3 se recoge el esquema inicial. Por el momento, no podemos determinar qu6 libros se incluyen en cada pedido a partir del modelo. Lo veremos en un instante.
7. Disefio de la base de datos Web
Como evitar el almacenamiento de datos redundantes En una secci6n anterior ya nos planteamos por qu6 no almacenar la direcci6n de Julie Smith en la tabla de pedidos. Si Julie realiza varios pedidos a Book-0-Rama, como asi esperamos, acabaremos almacenando sus datos varias veces. Es probable que la tabla de pedidos presente un aspect0 parecido a1 ilustrado en la figura 7.4. CUSTOMERS CustomerlD
Name
Address
1 Julie Smith 2 Alan Wong 3 Michelle Arthur
1 OrderlD
City Airport West Box Hill Yarraville
25 Oak Street 1/47 Haines Avenue 357 North Road
1 CustomerlD
1 Amount
1 Date
I
1 Author
1 Title
1 price Java 2 for Professional Developers 34.99 124.99 Installing Debian GNUILinux Teach Yourself GlMP in 24 Hours 24.99
I
BOOKS
1 ISBN
-
1
Figura 7.3. El esquemahicial consta de las tablas Customers, Orders y Books
ORDERS OrderlD Amount Date 12 13 14 15
199.50 25-Apr-2000 43.00 29-Apr-2000 15.99 30-Apr-2000 23.75 01-May-2000
CustomerlD Name 1 1 1 1
Julie Smith Julie Smith Julie Smith Julie Smith
Address 28 Oak Street 28 Oak Street 28 Oak Street 28 Oak Street
City A~rportWest Airport West Airport West Airport West
Figura 7.4. El diseiio de una base de datos que almacena datos redundantes aumenta el espacio utilizado y puede dar lugar a anomalias en 10s datos
Esto plantea dos problemas bdsicos. El primer0 supone malgastar espacio innecesariamente. iPor qu6 guardar 10s detalles de Julie en tres sitios si s610 necesitamos guardarlos en uno? El segundo problema son las anomalias que pueden surgir a1 actualizar 10s datos, es decir, situaciones en las que a1 cambiar 10s datos se producen inconsistencias. La integridad de 10s datos quedard alterada y ya no sabremos qu6 datos son correctos y
Desarrollo W e b con PHP y MySQL
qu6 datos son incorrectos. Por regla general, esta situaci6n dar6 lugar a la p6rdida de datos. Es necesario evitar tres tipos de anomalias de actualizaci6n: anomalias de modificacibn, de inserci6n y de eliminaci6n. Si Julie se muda de domicilio con pedidos todavia pendientes, tendremos que actualizar su direcci6n en tres lugares en lugar de en uno, lo que equivale a tener que realizar el trabajo tres veces. Resulta sencillo pasar por alto esta tarea y acabar realizando el cambio en un solo lugar, lo que dar6 lugar a la incoherencia de 10s datos de la base de datos (algo muy negativo). Estos problemas se conocen como anomalias de modificaci6n porque tienen lugar cuanto se intenta modificar la base de datos. En este diseiio, necesitamos insertar 10s detalles de Julie cada vez que recibimos un pedido, lo que significa que deberemos comprobar y asegurarnos de que sus datos son correctos en las filas existentes de la tabla. Si pas6ramos por alto la comprobaci6n, podriamos acabar con dos filas de datos desiguales sobre Julie. Por ejemplo, una fila podria indicar que vive en Airport West y otra en Airport. Este tip0 de anomalia se conoce como anomalia de inserci6n porque tiene lugar a1 introducir 10s datos. El tercer tip0 de anomalia se conoce como anomalia de eliminaci6n porque tiene lugar (sorpresa, sorpresa) a1 eliminar filas de la base de datos. Por ejemplo, imagine que tras enviar un pedido, lo eliminamos de la base de datos. Cuando se hayan servido todos 10s pedidos de Julie, se habrin eliminado todos de la tabla Order. Esto significa que no dispondremos de un registro sobre la direcci6n de Julie. Por tanto, no podremos enviarles ninguna oferta especial y necesitaremos tomar sus datos de nuevo cuando vuelva a realizar un pedido. Por regla general, a1 disefiar las bases de datos se intenta evitar estas anomalias.
Uso de valores de columna unicos Cada atributo de una fila debe almacenar un solo valor. Por ejemplo, necesitamos saber qut! libros componen cada pedido. Existen varias formas de hacerlo. Podemos agregar una columna a la tabla Orders en la que se enumeren todos 10s libros que hemos pedido, como se ilustra en la figura 7.5.
ORDERS OrderlD CustomerlD Amount Date 1 2 3 4
3 1 2 3
27.50 12.99 74.00 6.99
02-Apr-2000 15-Apr-2000 19-Apr-2000 01-May-2000
Books Ordered 0-672-31697-8 0-672-31745-1. 0-672-31509-2 0-672-31697-8 0-672-31745-1, 0-672-31 509-2. 0-672-31697-8
Figura 7.5. En este disetio, el atributo Books Ordered de cada fila incluye varios valores
No es una buena idea por varias razones. Lo que en realidad estamos haciendo es anidar una tabla dentro de una columna (una tabla que relaciona pedidos y libros). A1 hacerlo, resulta m6s dificil responder a preguntas como "iCu6ntas copias del libro
7. Diseiio de la base de datos W e b
Java 2 for Professional Developers quiere pedir?" ya que el sistema no puede contar 10s campos coincidentes. En su lugar, debe analizar cada valor de atributo y determinar si contiene una correspondencia en su interior. Como lo que estamos haciendo es crear una tabla dentro de otra, lo que deberiamos hacer es crear una nueva tabla. Esta nueva tabla, se denomina Order -1 tems y se muestra en la figura 7.6.
-ITEMS ISBN 0-672-31697-8 0-672-31745-1 0-672-31509-2 0-672-31697-8 0-672-31745-1 0-672-31509-2 0-672-31697-8
Figura 7.6. Este diseiio facilita la bljsqueda de libros concretos pedidos
Esta tabla proporciona un vinculo entre la tabla O r d e r s y la tabla Books. Es habitual crear este tip0 de tablas en una relaci6n varios a varios entre dos objetos: en este caso, un pedido puede constar de varios libros y varias personas pueden pedir un libro.
Seleccion de claves logicas Asegurese de que las claves seleccionadas son exclusivas. En nuestro caso, hemos creado una clave especial para 10s clientes (CustomerID) y para 10s pedidos (OrderID) porque es posible que estosobjebs del mundo real no dispongan de manera natural de un identificador con garantias de exclusividad. No necesitamos crear un identificador unico para 10s libros porque ya existe en forma de ISBN. EnOrder 1 tem, puede agregar una clave adicional si lo desea, pero la combinaci6n de 10s atributos OrderID (subrayadps???)e ISBN resultarfi exclusiva siempre y cuando se trate a cada copia de un libro dentro de un pedido como una fila. Por resta raz6n, la tabla Order-1t em incluye una columna Quantity.
Reflexiones sobre las preguntas que desea formular a la base de datos Enlazando con la secci6n anterior, piense en las preguntas que desea que responda la base de datos. (Recuerde las preguntas que realizamos a1 principio del capitulo. Por ejemplo, jcufiles son 10s libros que mfis vende Book-0-Rama?). Asegurese de que la base de datos contiene todos 10s datos necesarios y que se han establecido 10s vinculos adecuados entre las tablas para responder a las preguntas deseadas.
Desarrollo W e b con P H P y MySQL
Evite disenos con varios atributos vacios Si desea agregar resefias de libros a la base de datos, dispone a1 menos dos formas de hacerlo. En la figura 7.7 se recogen ambos enfoques. La primera consiste en agregar la columna Review a la tabla Books. En esta solucion se incluye un campo nuevo de resefia para cada libro. Si la base de datos consta de una gran cantidad de libros y el encargado de las resefias no tiene previsto crear una para cada libro, muchas filas quedaran vacias. Es lo que se conoce como valor nulo BOOKS ISBN
1 Author
1 Title
1 Price 1 Review 1
0-672-31687-8 Michael Morgan Java 2 for Professional Developers 34.99 0-672-31745-1 Thomas Down Installing Debian GNUlLinux 24.99 Teach Yourself GlMP in 24 Hours 24.99 0-672-31509-2 Pruitt, et al.
BOOK-REVIEWS ISBN
1 Review I
Figura 7.7. Para agregar reseiias, podemos incorporar una nueva columna a la tabla Books o aiiadir una tabla especifica para almacenar esta informacion
No conviene tener muchos valores nulos en una tabla ya que esta practica contribuye a desperdiciar espacio de almacenamiento y ocasiona problemas a1 calcular totales o a1 aplicar otras funciones a columnas num6ricas. Si un usuario ve un valor nulo en una tabla, no sabra si se debe a que el valor no resulta relevante, a que hay un error en la base de datos o a que no se han introducido 10s datos todavia. Por regla general, para evit3r 10s problemas con la inclusi61-1de demasiados valores nulos se recurre a un disefio alternativo. En este caso, podemos utilizar el segundo diseiio ilustrado en la figura 7.7. En este caso, s610 se enumeran 10s libros con una resefia a la tabla Book Reviews, asi como sus resefias. Fijese en que este disefio se basa en la idea de tener una persona encargada de la revisi6n. Como alternativa podriamos permitir que 10s clientes se encarguen de realizar las resefias. En este caso, podriamos afiadir el campo c u s t o m e r I D a la tabla Book-Reviews.
Resumen de 10s tipos de tablas Como tendr6 la oportunidad de comprobar, las bases de datos suelen componerse de dos tipos de tablas: Tablas sencillas que describen un objeto del mundo real. Tambien podrian contener claves a otros objetos simples en 10s que exista una relaci6n uno a uno o uno a varios. Por ejemplo, nuestro cliente podria contener varios pedidos,
7. Diseiio de la base de datos W e b
per0 cada pedido se asocia a un unico cliente. Por lo tanto, asignamos una referencia a1 cliente en el pedido. Tablas de uni6n que describen una relaci6n varios a varios entre dos objetos reales como la relaci6n entre O r d e r s y B o o k s . Estas tablas suelen asociarse con algun tip0 de transacci6n del mundo real.
Tras comentar la arquitectura interna de nuestra base de datos, vamos a examinar la arquitectura externa de un sistema de base de datos Web y a comentar la metodologia para desarrollar un sistema de base de datos Web.
En la figura 7.8 se ilustra el funcionamiento bdsico de un servidor Web. Este sistema consta de dos objetos: un navegador Web y un servidor Web. Para unirlos se necesita una forma de comunicaci6n. Un navegador Web realiza una solicitud a1 servidor. El servidor devuelve una respuesta. Esta arquitectura resulta apropiada para un servidor que devuelva pdginas estdticas. La arquitectura que devuelve resultados de un sitio Web basado en una base de datos resulta un tanto mds complicada.
Navegador
Servidor Web
Figura 7.8. La relacion clientelservidor entre un navegador Web y un servidor Web requiere comunicacion
Las aplicaciones debase de datos Web que desarrollaremos en este libro siguen la estructura general de base de datos Web que se ilustra en la figura 7.9. Gran parte de esta estructura deberia resultarle familiar a estas alturas. 1 Navegador
-
Servldor Web
6
*
3
2 Motor de PHP
5
Servidor MySQL
4
Figura 7.9. La arquitectura basica de base de datos Web se compone de un navegador Web, un servidor Web, un motor de secuencia de comandos y un servidor de base de datos
Una transacci6n tipica de base de datos Web se compone de las fases siguientes, numeradas en funci6n de la figura 7.9. Examinaremos estas fases en el context0 del ejemplo Book-0-Rama.
Desarrollo Web con PHP y MySQL
1. El navegador Web de un usuario envia una petici6n HTTP a una pigina Web dada. Por ejemplo, puede tratarse de una busqueda para extraer todos 10s libros escritos por Laura Thomson en Book-0-Rama con ayuda de un formulario HTML. La pigina de resultados de busqueda se denomina results.php. 2. El servidor Web recibe la petici6n de results.php, recupera el archivo y lo pasa a1 motor de PHP para su procesamiento.
3. El motor de PHP comienza a analizar la secuencia de comandos. Dentro de la secuencia de comandos hay un comando que establece la conexi6n a la base de datos y ejecuta una consulta (realiza la busqueda de libros). PHP abre una conexi6n a1 servidor MySQL y remite la consulta pertinente. 4. El servidor MySQL recibe la consulta de la base de datos y la procesa. A continuaci611, envia 10s resultados (una lista de libros) a1 motor de PHP. 5. El motor de PHP termina de ejecutar la secuencia de comandos, lo que suele implicar la aplicaci6n de formato a 10s resultados en HTML. Seguidamente, devuelve el c6digo HTML resultante a1 servidor Web.
6. El servidor Web devuelve el c6digo HTML a1 navegador donde el usuario puede ver la lista de 10s libros solicitados.
El proceso es bisicamente el mismo independientemente del motor de secuencia de comandos o del servidor debase de datos que utilicemos. Por regla general, el software del servidor Web, el motor de PHP y el servidor de la base de datos se ejecutan en el mismo equipo. Sin embargo, tambibn es habitual ejecutar el servidor de la base de datos en un equipo diferente, por razones de seguridad, de una mayor capacidad o de reparto de la carga. Desde el punto de vista de desarrollo, el trabajo serd el mismo, per0 puede presentar algunas ventajas significativas de rendimiento.
Lecturas adicionales -
En este capitulo, hemos analizado alguna de las directrices para el diseiio debases de datos. Si quiere profundizar en la teoria sobre la que descansan las bases de datos relacionales, puede leer algunas de las obras escritas por expertos en el tema como C.J. Date. Eso si, tenga en cuenta que el material puede resultar bastante te6rico y poco relevante a corto plazo para un desarrollador Web comercial. Las bases de datos Web mis habituales no suelen alcanzar un nivel tan alto de complejidad.
A continuacion En el siguiente capitulo, comenzaremos a configurar nuestra base de datos MySQL. En primer lugar aprenderd a configurar una base de datos MySQL para la Web y c6mo consultarla y, a continuacih, c6mo consultarla desde PHP.
En este capitulo vamos a comentar c6mo configurar una base MySQL para su uso en un sitio Web. En este capitulo abordaremos 10s siguientes aspectos: Creaci6n de una base de datos Usuarios y privilegios
-
Introducci6n a1 sistemi de privilegios Creaci6n de tablas de base de datos Tipos de colurnna en MySQL En este capitulo, vamos a seguir adelante con la aplicaci6n de la libreria en linea Book-0-Rama comentada en el ~ l t i m capitulo. o A continuaci6n, se recoge el esquema de la aplicaci6n de Book-0-Rama para ayudarle a recordar: Customers(CustomerID, Name, Address, City) Orders(OrderlD, CustomerID, Amount, Date) Books(Author, Title, Price) Order-Items(OrderID, ISBN, Quantity) -Book-Reviews(ISBN, - Reviews)
Recuerde que las claves principales aparecen subrayadas con una linea continua y las claves secundarias con una linea discontinua.
8. Creacidn de la base de datos W e b
Para utilizar el material de esta seccibn, debe disponer de acceso a MySQL, lo cual significa que Ha completado la instalaci6n bhsica de MySQL en su servidor Web. Esto incluye: Instalar 10s archivos Configurar un usuario para ejecutar MySQL Configurar su ruta Ejecutar mysql -i n s t a l l - d b , si resultara necesario Establecer la configuraci6n del usuario raiz Eliminar el usuario an6nimo y la base d e datos d e prueba Iniciar el servidor de MySQL Si ha realizado todas estas operaciones, puede seguir adelante con la lectura del capitulo. Si no lo ha hecho, en el apendice A encontrarh instrucciones sobre c6mo proceder. Si tiene problemas durante este capitulo, puede que se deba a la configuraci6n de su sistema MySQL. En este caso, revise esta lista y el a p h d i c e A para asegurarse de que la configuraci6n es correcta. Dispone de acceso a MySQL en un equipo de cuya administraci6n no se encarga, como u n servicio de alojamiento Web, un equipo en su lugar d e trabajo, etc. Si este fuera el caso, para poder seguir 10s ejemplos o crear su propia base de datos, deberh pedir a su administrador que configure un usuario y la base de datos para permitirle-trabajar con ella y que le indique el nombre de usuario, la contrasefia y el nombre de la base de datos que se le ha asignado. Puede saltarse las secciones de este capitulo dedicadas a explicar c6mo configurar usuarios y bases de datos o leerlas para explicar mejor lo que necesita su administrador del sistema. Como usuario normal, no podrh ejecutar 10s comandos para crear usuarios y bases de datos. Los ejemplos de este capitulo se han elaborado y probado con la versi6n 3.23.52 de MySQL. Las versiones anteriores disponen d e menor funcionalidad. Deberia instalar o actualizar su versi6n a la mhs reciente, que puede descargar del sitio de MySQL en h t t p : / / m y s q l . corn.
Nota sobre el uso del monitor de MySQL En este capitulo y en el siguiente, apreciarh que en 10s ejemplos de MySQL cada comando termina en un punto y coma (;). Este simbolo indica a MySQL que ejecute
Desarrollo Web con PHP y MySQL
el comando. Si olvida utilizar el punto y coma, no se aplicarii ninguna acci6n. Se trata de un problema com6n entre 10s nuevos usuarios. Tambi6n significa que puede utilizar nuevas lineas en mitad de un comando. En el libro, hemos utilizado este recurso para facilitar la lectura de 10s ejemplos. Apreciar6 d6nde lo hemos hecho porque MySQL incluye un simbolo de continuaci6n. Se trata de una flecha como la incluida en este fragmento: mysql> ->
grant
select
Este simbolo indica que MySQL espera miis entradas. Mientras no se escriba un punto y coma, obtendrii estos caracteres a1 pulsar Intro. Tenga en cuenta adem6s que las instrucciones de SQL no discriminan entre mayusculas y min6sculas, per0 que las bases de datos y las tablas si pueden hacerlo (este aspecto se ampliarii miis adelante).
Como registrarse en MySQL Para registrarse, dirijase hasta la interfaz de linea de comandos de su equipo y escriba lo siguiente: mysql -h nombreciehost
-u
r i o m b r e d e u s u a r i o -p
El simbolo de comandos puede presentar un aspecto diferente seg6n el sistema operativo y el n6cleo que est6 utilizando. El comando mys ql invoca a1 monitor de MySQL. Se trata de un cliente de linea de comandos que nos permite comunicarnos con el servidor MySQL. El modificador -h se utiliza para especificar el host a1 que establecer la conexibn, es decir, el equipcren etque se estii ejecutando el servidor MySQL. Si ejecuta este comando en el mismo equipo que el servidor MySQL, no necesitarii utilizar el modificador -h ni el pariimetro n o m b r e d e h o s t. De lo contrario, deberii sustituir dicho pariimetro por el nombre del equipo en el que se este ejecutando el servidor MySQL. El modificador -u se utiliza para especificar el n o m b r e d e u s u a r i o con el que desea conectarse. Si no se especifica, se utilizarii el nombre de usuario predeterminado con el que se inici6 la sesi6n en el sistema operativo. Si ha instalado MySQL en su propio equipo o servidor, deberii registrarse como r o o t y crear la base de datos que utilizaremos en esta secci6n. Si ha realizado una instalaci6n limpia, el usuario raiz serii el 6nico usuario del que dispondrii para iniciar la sesi6n. Si estii utilizando MySQL en un equipo administrado por otra persona, utilice el nombre de usuario que se le haya asignado. El modificador -p indica a1 servidor que se desea establecer la conexi6n utilizando una contrasefia. Puede evitar su uso, si no se ha establecido una contrasefia para el usuario utilizado para iniciar la sesibn.
Si se esti iniciando la sesidn como usuario raiz y no se ha establecido una contraseiia para dicho usuario, le recomendamos que consulte el a p h d i c e A de inmediato. Sin una contrasefia para el usuario raiz , su sistema es inseguro. No es necesario que incluya la contraseiia en esta linea. El servidor MySQL se la pediri. De hecho, es mejor no hacerlo. Si introduce la contraseiia en la linea de comandos, se mostrari en la pantalla y otros usuarios podrian verla. Tras introducir el comando anterior, deberia obtener un resultado parecido a1 siguiente: Enter
password:
+ + + +
(Si no funcionase, verifique que el servidor MySQL se esti ejecutando y el comando my s q l aparece en algun lugar de su ruta.) Deberia introducir la contraseiia. Si todo va bien, se mostrari una respuesta parecida a la siguiente: Welcome t~ the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 5 to server version: 3.23.52-nt Type 'help;' or ' \ h l for help. Type '\c' to clear the buffer mysql>
En su equipo, si no obtiene una respuesta similar, asegurese de haber ejecutado mysql i n s t a l l db, si resultara necesario, de haber establecido la contraseiia del usuarioraiz y de haberla escrito correctamente. Si se trata de otro equipo, asegurese de haber escrito correctamente la contraseiia. Tras ello, deberia aparecer el simbolo de comandos de MySQL listo para crear la base de datos. Si esti utilizando su propio equipo, siga las directrices de la siguiente seccidn. Si esti utilizando el equipo de otra persona, esta fase ya estari completada. Puede saltar a la seccidn ((Us0 de la base de datos corrects,,. Si lo desea, puede leer las secciones intermedias paraampliar sus conocimientos per0 no podri ejecutar 10s comandos indicados en ellas. ( 0 no deberia, a1 menos).
Creacion de bases de datos y usuarios El sistema debase de datos de MySQL admite una gran cantidad debases de datos diferentes. Por regla general, se utilizari una base de datos por cada aplicacidn, En nuestro ejemplo Book-O-Rama, la base de datos se llamari books.
Creaci6n de la base de datos gsta es la parte m i s sencilla. Escriba la siguiente secuencia en el simbolo de comandos de MySQL: mysql>
create
database
nombrebd;
Desarrollo W e b con PHP y MySQL
Sustituya el pariimetro nombrebd por el nombre de la base de datos deseado. Para comenzar a crear el ejemplo Book-0-Rama, puede crear una base d e datos llamada books.
Y eso es todo. Deberia ver aparecer una respuesta como la siguiente: Q u e r y OK,
1 row
affected
(0.06 s e c )
Esta secuencia indica que todo ha funcionado correctamente. Si no la obtiene, asegurese de incluir el punto y coma a1 final de la linea. Este simbolo indica a MySQL que ha terminado y deberia ejecutar el comando.
Usuarios y privilegios Un sistema MySQL puede tener muchos usuarios. Como norma deberia utilizarse el usuario raiz para labores administrativas unicamente, por razones de seguridad. Deber6 configurar una cuenta y una contrasefia para cada usuario del sistema . No es necesario que Sean las mismas utilizadas fuera de MySQL (por ejemplo, 10s nombres de usuario y contrasefias de UNIX o NT). Los mismos principios se aplican a1 usuario raiz. Conviene utilizar contrasefias diferentes para el sistema y para MySQL, en especial en el caso de la contrasefia del usuario raiz. No es obligatorio configurar contrasefias para 10s usuarios, per0 si muy aconsejable. A la hora de configurar una base de datos Web, conviene establecer a1 menos un usuario por aplicaci6n Web. Es probable que se este preguntado por quk. La respuesta reside en 10s privilegios.
lntroduccion al sistema de privilegios de MySQL Una de las mejores funciones de MySQL es su avanzado sistema de privilegios. Un privilegio es el derecho a realizar una acci6n dada sobre u n determinado objeto y se asocia a u n usuario concreto. El concept0 es muy similar a 10s permisos de archivo. A1 crear un usuario dentro de MySQL, se le conceden un conjunto de privilegios en 10s que se especifica lo que puede y no puede hacer dentro del sistema.
Principio de asignacion del privilegio mas bajo Este principio se puede utilizar para mejorar la seguridad de cualquier sistema informAtico. Se trata de un principio elemental per0 muy importante que se suele pasar por alto a menudo.
8. Creacidn de la base de datos Web
Su contenido es el siguiente: Un usuario (o proceso) deberia disponer del nivel m6s bajo de privilegio necesario para realizar la tarea que se le asigne. Su aplicacidn debe ir m6s all6 de MySQL. Por ejemplo, para ejecutar consultas desde la Web, un usuario no necesita disponer de todos 10s privilegios asociados a1 usuario raiz. Por lo tanto, deberiamos crear otro usuario que s610 disponga de 10s privilegios necesarios para acceder a la base de datos que acabamos de crear.
Cdmo configurar usuarios: el comando GRANT Los comandos GRANT y REVOKE se utilizan para conceder y retirar 10s derechos a 10s usuarios de MySQL en cuatro niveles de privilegio. Estos niveles son: Global Base de datos Tabla
En un instante veremos cdmo se aplica cada uno de ellos. El comando GRANT se utiliza para crear usuarios y concederles privilegios. La sintaxis general del comando GRANT es la siguiente: GRANT p r i v i l e g i o s [ col u m n a s ] ON e l e m e n t o T O n o m b r e - u s u a r i o [ I D E N T I F I E D BY [ W I T H GRANT O P T I O N ]
*
'contrasefia']
Las cl6usulas incluidas &tre corchetes son opcionales. La sintaxis de este comando incluye varios marcadores de posicidn. El primer lugar, privilegios, equivale a una lista de privilegios separados por comas. MySQL consta de un conjunto definido de ellos, que se describen en la siguiente seccidn. El marcador de posicidn columnas es opcional. Puede utilizarlo para especificar privilegios a cada columna. Puede utilizar el nombre de una sola columna o una lista de nombres de columna separadas por comas. El marcador de posicidn, elemento es la base de datos o tabla a la que se aplican 10s nuevos privilegios. Puede conceder privilegios a todas las bases de datos especificando * . * como elemento. Es lo que se conoce como conceder privilegios globales. T a m b i h puede hacerlo especificando * cnicamente si no va a utilizar ninguna base de datos en concreto. Por regla general, especificar6 todas las tablas de la base de datos como nombrebd. *, una sola tabla de base de datos como nombrebd. n o m b r e t a b l a o columnas especificas indicando nomb r e b d . nombre t a b l a y las columnas deseadas en el marcador de posicidncolumnas. Si estA utilizando una base de datos especi-
Desarrollo Web con PHP y MySQL
fica a1 remitir este comando y s610 se utiliza nomb retabla, se interpretard como una tabla de la base de datos actual. El marcador de posici6n nombre-usuario serd el nombre del usuario con el que desea registrarse en MySQL. Recuerde que no tiene por qu6 ser el mismo que el nombre de registro del sistema. Este pardmetro tambikn puede contener un nombre de host. Puede utilizarlo para distinguir, por ejemplo, entre Laura (interpretado como laura@hostlocal) y 1 aura @ot r os it i o . com. Esta opci6n resulta bastante util porque 10s usuarios pertenecientes a diferentes dominios suelen utilizar 10s mismos nombres. Tambih permite incrementar la seguridad porque se puede especificar desde ddnde se conectan 10s usuarios e incluso a qu6 tablas y datos pueden acceder desde una ubicaci6n dada. El marcador de posici6n contra sen"^ es la contraseiia que deseamos utilizar para iniciar la sesion. Se aplican las reglas habituales para la selecci6n de contraseiias. En una seccidn posterior ampliaremos el tema de la seguridad, per0 las contrasefias no deben resultar sencillas de adivinar. Es aconsejable que contengan un combinaci6n de caracteres en mayusculas y minusculas y caracteres no alfabkticos. La opcion WITH GRANT OPTION, si se especifica, permite que el usuario indicado delegue sus privilegios en otros usuarios. Los privilegios se almacenan en cuatro tablas del sistema, dentro de la base de datos m y s ql. Estas cuatro tablas se denominan m y s q l user, m y s q l db, mysql.tables p r i v y m y s q l . c o l u m n s privyserelacionandirectamentecon 10s cuatro niveles de privilegio mencionados anteriormente. Como alternativa a GRANT, puede alterar estas tablas directamente, como se analizard en un capitulo posterior.
.
.
Tipos y niveles de privilegio Existen tres tipos b6sicos de privilegios en MySQL: 10s privilegios apropiados para su concesi6n a 10s usuarios habituales, 10s privilegios apropiados para su concesi6n a 10s administradores y dos privilegios especiales. Se puede asignar cualquier privilegio a cualquier usuario, per0 es aconsejable restringir 10s privilegios de administrador a 10s administradores, siguiendo el principio de conceder el nivel mds bajo de privilegios. Deberia restringir 10s privilegios concedidos a 10s usuarios para las bases de datos y tablas que necesiten utilizar. No deberia conceder acceso a la base de datos my s ql a nadie a excepcidn de a un administrador. En esta base de datos se almacenan todos 10s usuarios, contrasefias y otros datos. (En un capitulo posterior analizaremos esta base de datos.) Los privilegios para el resto de 10s usuarios deberian establecerse directamente en funcidn de 10s tipos especificos de comandos SQL y si un usuario puede ejecutarlos. En el siguiente capitulo analizaremos en detalle estos comandos. Por el momento, basta con la descripci6n conceptual indicada. En la tabla 8.1 se recogen estos privilegios. En la columna Se aplica a se enumeran 10s objetos a 10s se pueden conceder cada privilegio.
8. Crcocicin dc lo bnsc de dotos Web Tabla 8.1. Privilegios para usuarios ~.
. - . .
- - - .---*-----.
- -
.-
-
-
Privilegio
Se aplica a
Descripci6n
SELECT
tablas, colurnnas
Perrnite a 10s usuarios seleccionar filas (registros de tablas).
INSERT
tablas, columnas
Permite a 10s usuarios insertar nuevas filas en las tablas
UPDATE
tablas, columnas
Permite a 10s usuarios modificar valores de filas de tablas existentes.
DELETE
tablas
Permite a 10s usuarios eliminar filas de tablas existentes.
INDEX
tablas
Permite a 10s usuarios crear y elirninar indices sobre tablas concretas.
ALTER
tablas
Perrnite a 10s usuarios alternar la estructura de tablas existentes agregando, por ejernplo, colurnnas, cambiando el nombre de las colurnnas o de las tablas y modificando 10s tipos de datos de las columnas.
CREATE
bases de datos y tablas
Permite a 10s usuarios eliminar bases de datos o tablas. Si especifica una base de datos o una tabla dada en el comando GRANT, 10s usuarios solo podran crear dicha base de datos o tabla, lo que significa que tendran que elirninarla prirnero.
DROP
bases de datos y tablas
.
Perrnite a 10s usuarios elirninar bases de datos o tablas.
La mayor parte d e 10s privilegios para 10s usuarios norrnales son relativarnente inofensivos en t4rminos d e la seguridad del sistema. Se puede utilizar el privilegio ALTER para resolver el sistema de privilegios cambiando el nombre d e las tablas, per0 10s usuarios suelen utilizarlo bastante. La bGsqueda de la seguridad consiste en hallar un equilibrio entre la usabilidad y la protection. Debe tomar una decision con respecto a1 privilegio ALTER,per0 debe saber que se suele conceder a 10s usuarios a menudo. A d e m i s d e 10s privilegios enumerados en la tabla 8.1, existe el privilegio REFERENCES que no se utiliza y el privilegio GRANT que se concede con el parAmetro W I T H GRANT O P T I O N e n lugar d e e n la lista d e prizdegios.
Desnrrollo Web con P H P y M y S Q L
La tabla 8.2 muestra 10s privilegios apropiados para su concesi6n a 10s usuarios administrativos. Tabla 8.2. Privilegios para administradores .
- -
-
. -
Privilegio
Descripcion
RELOAD
Permite a un administrador volver a cargar tablas de concesion y elirninacion de privilegios, hosts, registros y tablas.
SHUTDOWN
Permite a un administrador cerrar el servidor MySQL.
PROCESS
Permite a un administrador ver 10s procesos de servidor y cerrarlos.
FILE
Permite la lectura de datos en tablas desde archivos y viceversa.
Estos privilegios se pueden conceder a usuarios que no Sean administradores per0 debe estar muy atento si est.4 considerando dicha posibilidad. El usuario medio no necesita utilizar 10s privilegios RELOAD, SHUTDOPIN y PROCESS. El privilegio FILE es un tanto diferente. La posibilidad de cargar datos desde archivos puede contribuir a ahorrar mucho tiempo a1 volver a introducir 10s datos en la base de datos. Sin embargo, la funci6n de carga de archivos se puede utilizar para cargar cualquier archivo que puede ver el servidor MySQL, ii~cluidaslas bases d e datos pertenecientes a otros usuarios y, potencialmente, 10s archivos de contrasefias. Tenga cuidado a1 conceder este privilegio u ofrezca la posibilidad de realizar la carga de 10s usuarios. Existen otros dos privilegios especiales, que se recogen en la tabla 8.3.
-
Tabla 8.3. Privilegios especiales r
-
-
-- ..
-
-.
-
--.
Privilegio
Descripcion
ALL
Concede todos 10s privilegios enumerados en las tablas 8.1 y 8.2. Tarnbien se puede escribir ALL PRIVILEGES en lugar de ALL.
USAGE
No concede ningun privilegio. Este privilegio crea un usuario y le permite registrarse, per0 no se le concede ningun otro privilegio. Por regla general, la concesion de otros privilegios se suele dejar para un momento posterior.
Se trata del comando opuesto a1 comando GRANT. Se utiliza para retirar p r i d e gios d e un usuario.
8 . Creacidn de la base de d a b s Web
Su sintaxis es muy similar a la sintaxis de GRANT: REVOKE privilegios ON elemento FROM nombre-usuari o
[ (
columnas)]
Si se han concedido privilegios con la clhsula WITH GRANT O P T I O N , puede revocarlos de la siguiente forma: REVOKE GRANT O P T I O N ON elemento FROM nornbre-usuario
Ejemplos de uso de GRANT y REVOKE Para configurar un administrador, puede escribir: rnysql>
grant all
-> on -> to £red identified by 'mnb123' -> with grant option;
Este ejemplo concede todos 10s privilegios sobre todas las bases de datos a un usuario llamado Fred con la contraseiia mnb123 y le permite traspasar dichos privilegios. No le gustarfi tener un usuario asi en su sistema por lo que conviene revocarlo: mysql>
revoke all
-> on - > from fred;
-
Seguidamente vamos a configurar un usuario normal sin privilegios.
-
mysql>
grant usage -> on books. -> to sally identified by 'magic123';
Hablamos con Sally para determinar que desea hacer y le concedemos 10s privilegios adecuados: rnysql>
grant select, insert, update, delete, index, alter, create, drop
-> on books. - > to sally;
Fijese en que no necesitamos especificar la contraseiia de Sally para realizar esta tarea. Si decidimos que Sally ha intentado realizar algo no apropiado en la base de datos, podemos reducir sus privilegios: mysql>
revoke alter, create, drop
-> on books. -> from sally;
Desarrollo Web con PHP y MySQL
Y posteriormente cuando ya no necesite utilizar la base de datos, podemos revocar todos sus privilegios: rnysql>
revoke all on books. -> from sally; -\
Como configurar un usuario para la Web Necesitari configurar un usuario para que sus secuencias de comandos de PHP se conecten a MySQL. Podemos volver a aplicar el principio del privilegio minimo. iQu6 se permitiri a las secuencias de comandos? En la mayor parte de 10s casos, solo se necesita seleccionar, insertar, eliminar y actualizar filas de tablas. Podemos configurar estas tareas de la siguiente forma: rnysql>
grant select, insert, delete, update
-> on books. * - > to bookorama identified by 'bookoramal23';
Por razones de seguridad, deberia seleccionar una contraseiia mejor. Si utilizamos un servicio de alojamiento Web, por regla general obtendremos acceso a1 resto de 10s privilegios de tip0 usuario en una base de datos creada para nosotros. Se nos asignari un nombre de usuario y una contraseiia para el uso de la linea de comandos (desde donde crear tablas y realizar otras tareas por el estilo) y para realizar las conexiones de secuencia de comandos Web (para consultar la base de datos). Este sistema resulta un poco menos seguro. Puede configurar un usuario con este nivel de privilegios de la siguiente forma: rnysql>
-
grant select, insert, update, delete, index, alter, create, drop
-
-> on books. * -> to bookorama identified by 'bookoramal23';
Proceda a configurar esta segunda version del usuario ya que es la que utilizaremos en la siguiente seccion.
C6mo cerrar la sesion como administrador Puede cerrar la sesi6n del monitor de MySQL escribiendo q u i t . Deberia volver a registrarse como usuario Web para comprobar si todo funciona correctamente.
Uso de la base de datos correcta Si ha llegado hasta aqui, deberia estar registrado en una cuenta de MySQL de nivel de usuario lista para probar el ejemplo de codigo, bien porque acaba de configurarla o porque el administrador del servidor Web se ha encargado de ello.
8. Creacidn de la base de datos W e b
Lo primer0 que necesita hacer a1 iniciar una sesidn es especificar que base de datos desea utiliza. Para ello, puede escribir: mysql> use nombrebd;
donde nombrebd es el nombre de la base de datos. Como alternativa, puede evitar el comando use especificando la base de datos a1 iniciar la sesidn, de la siguiente forma: mysql -D nombrebd -h nombrehost - u nombreusuario -p
En este ejemplo, utilizaremos la base de datos de libros: mysql> use books;
A1 escribir este comando, MySQL deberia devolver una respuesta como la siguiente Database changed
Si no selecciona una base de datos antes de empezar a trabajar, MySQL devolvera un mensaje de error como el siguiente: ERROR 1046: No Database Selected
Creacion de tablas de base de datos El siguiente paso en la configuracidn de la base de datos consiste en crear las tablas. Para ello puede utilizar el comando CREATE TABLE de SQL. Esta instruccidn suele presentar esta forma: CREATE
TABLE
nombretabl a
(
col umnas)
Deberia sustituir el marcadorje posicidn nombretabla con el nombre de la tabla que desea crear y el marcador de posicidn columnas con una lista de columnas separadas por comas en la tabla. Cada columna tendrd un nombre seguido por un tip0 de dato. Customers(CustomerID, Name, Address, City) Orders(OrderID, CustomerID, Amount, Date) Books(= Author, Title, Price) Order-Items(OrderID, -ISBN, Quantity) Book-Reviews(ISBN, -Review)
El listado 8.1 muestra el cddigo SQL para crear las tablas, asumiendo que ya hayamos creado la base de datos llarnada books. Encontrara el cddigo necesario en el archivo correspondiendo a este capitulo del CD-ROM. Puede ejecutar un archivo SQL existente, como el cargado desde el CD-ROM a traves de MySQL mediante la siguiente secuencia: > mysql -h host -u bookorama -D books -p < bookorama.sq1
(Recuerde sustituir el host con el nombre de su host.) El uso de la redireccidn de archivos resulta bastante pr6ctico en este caso porque permite editar las secuencias SQL en el editor de texto deseado antes de ejecutarlas.
Desarrollo W e b con PHP y MySQL Listado 8.1. bookorama.sql. Codigo SQL para crear las tablas de Book-0-Rama c r e a t e t a b l e customers ( customerid i n t unsigned not n u l l auto-increment name c h a r ( 3 0 ) n o t n u l l , address char(40) not null, c i t y char(20) not null
p r i m a r y key,
);
create table orders ( o r d e r i d i n t u n s i g n e d n o t n u l l a u t o i n c r e m e n t p r i m a r y key, customerid i n t unsigned not n u l l , amount f l o a t ( 6 , 2 ) , date d a t e not n u l l -
) ;
c r e a t e t a b l e books ( i s b n c h a r ( l 3 ) n o t n u l l primary key, author char(30), t i t l e char(60), price float (4,2) );
c r e a t e t a b l e order-ifems ( orderid i n t unsigned not n u l l , isbn char(l3) not null, q u a n t i t y t i n y i n t unsigned, primary key
(orderid, isbn)
) ;
c r e a t e t a b l e book-reviews (
-
i s b n c h a r ( l 3 ) n o t n u l l p r i m a r y key, review t e x t
i
;
-
Cada tabla se crea con una instruccion CREATE TABLE independiente. Como puede observar hemos creado el esquema con las columnas diseiiadas en el ultimo capitulo. Cada columna tiene un tip0 de dato listado tras su nombre. Algunas columnas tienen otros especificadores.
iCu61 es el significado del resto de las palabras clave? NOT NULL significa que todas las filas de la tabla deben tener un valor en este atributo. Si no se especifica, el campo puede dejarse en blanco (NULL). AUTO INCREMENT es una funcion especial de MySQL que puede utilizar sobre columnas de tip0 entero. Significa que si dejamos el campo en blanco a1 insertar filas en la tabla, MySQL generara automaticamente un valor de identification exclusivo. Este valor sera una unidad mayor que el valor mdximo incluido en la columna. Solo puede tener una columna de este tip0 por tabla. Las columnas que especifiquen AUTO -INCREMENT deben estar indexadas.
El uso de la palabra clave PRIMARY KEY tras el nombre de una columna determina que la columna se tratara como la clave principal de la tabla. Las entradas de esta columna deben ser exclusivas. MySQL indexari automdticamente esta columna. Fijese en que en el listado anterior a1 utilizarlo con c u s t o m e r i d en la tabla customer se ha hecho con AUTO INCREMENT. La indexaci6n automdtica sobre la clave principal se encarga del indice que necesita AUTO INCREMENT. Si especificamos PRIMARY KEY tras el nombre de una columna, s610 se puede utilizar para claves principales formadas por una sola columna. El uso de la cldusula PRIMARY KEY a1 final de la instrucci6n o r d e r i t e m s es una alternativa. Aqui la hemos utilizado porque la clave principal de esG tabla se compone de dos columnas. La palabra clave UNSIGNED utilizada tras un tipo entero significa que s610 puede tener como valor cero o un numero positivo.
Tipos de columna Tomemos la primera tabla como ejemplo create table customers ( c u s t o m e r i d i n t u n s i g n e d n o t n u l l a ~ t o ~ i n c r e m e np tr i m a r y k e y , name c h a r ( 3 0 ) n o t n u l l , address char(40) not null, c i t y char(20) not null
i;
A1 crear una tabla, deberd tomar una decision con respecto a 10s tipos de columnas. En la tabla customers, tenemos cuatro columnas como se especifica en nuestro esquema. La primera, c u s t o m e r i d es a1 clave principal, que hemos especificado directamente. Hemos decidido que sea de tip0 entero (tipo i n t ) y que 10s ID Sean unsigned. Tambibn hemos aprovechado la funci6n a u t o i n c r e m e n t para que MySQL pueda encargarse de ello automiticamente y evitarnos una preocupaci6n. Las otras dos columnas contendrdn datos de tip0 cadena. En este caso hemos seleccionado c h a r como tip0 de dato. Este tip0 especifica campos de achura fija a travbs de corchetes; por ejemplo, name, puede tener hasta 30 caracteres. Este tip0 de datos asignard siempre 30 caracteres de espacio de almacenamiento para el nombre, aunque no se utilicen todos. MySQL rellenard 10s datos con espacios para asignarles el tamaAo exacto. Como alternativa se puede utilizar el tipo v a r c h a r, que s610 utiliza la cantidad de espacio necesario (mds un byte). El tip0 v a r c h a r absorbe menos espacio per0 resulta m i s lento. Para 10s clientes reales con nombres y direcciones reales, las anchuras seleccionadas para estas columnas son demasiado estrechas. Fijese en que hemos declarado todas las columnas como NOT NULL. Se trata de una pequeiia optimizaci6n que puede realizar cuando resulte posible. En un capitulo posterior trataremos el tema de la optimizaci6n.
Desarrollo W e b con PHP y MySQL
Alguna de las instrucciones CREATE presentan variaciones en cuanto a la sintaxis. Examinemos la tabla o r d e r s : create table orders ( orderid int unsigned not null auto- increment primary key, customerid int unsigned not null, amount float (6,2), date date not null i;
La columna amount se especifica como numero de coma flotante de tip0 f l o a t . En la mayor parte de 10s tipos de datos de coma flotante, puede especificar la anchura de visualizaci6n y el numero de decimales. En este caso, la cantidad del pedido se establecerii en dblares, por lo que podemos asignar un tamaiio total razonablemente largo (una anchura de seis espacios) y dos decimales para 10s c6ntimos. La columna d a t e lleva asignado el tipo de dato d a t e . En esta tabla concreta, hemos especificado que las columnas puedan definir la cantidad como NOT NULL. ~ P o quk? r Cuando se introduce un pedido en la base de datos, tendremos que crearlo en o r d e r s , agregarle 10s elementos a o r d e r-i t ems y calcular la cantidad. Puede que no sepamos la cantidad a1 crear el pedido, por lo que permitimos que sea NULL. La tabla books presenta algunas caracteristicas similares. create table books ( isbn char(l3) not null primary key, author char(30), title char(60), price float(4,2) 1;
En este caso, no necesjtamqs generar la clave principal porque 10s ISBN se generan en otra parte. Hemos dejado 10s otros campos como NULL porque una libreria puede conocer el ISBN de un libro antes de conocer su titulo, autor o precio. La tabla o r d e r -i t ems muestra como crear claves principales multicolumna: create table order items ( orderid int unsigned not null, isbn char(l3) not null, quantity tinyint unsigned, -
primary key (orderid, isbn)
i
;
Hemos especificado la cantidad de un libro como T I N Y I N T UNSIGNED, que equivale a un entero entre 0 y 255. Como se mencion6 anteriormente, las claves principales multicolumna necesitan especificarse con una cliiusula de clave principal. Esta es la que se utiliza aqui. Por ultimo, examine la tabla book -r e v i e w s :
8. Creacidn de la base de datos W e b
create
table
book-reviews
(
isbn char(l3) not null primary key, review text 1;
Esta tabla utiliza un nuevo tip0 de dato, t e x t , que todavia no se ha analizado. Este tip0 se utiliza para texto de gran longitud como un articulo. Existen algunas variantes de este tip0 que se cornentarin en una secci6n posterior. Para comprender mejor el proceso de creaci6n de tablas vamos a analizar 10s nombres de las columnas y 10s identificadores en general, y, a continuaci6n,los tipos de datos que podemos seleccionar para las columnas. Pero en primer lugar, examinaremos la base de datos que hemos creado.
Como examinar la base de datos con SHOW y DESCRIBE Inicie la sesi6n en el monitor de MySQL y utilice la base de datos books. Para ver las tablas de la base de datos, escriba mysql>
show
tables;
MySQL mostrar6 una lista de todas las tablas de la base de datos:
I I I
Ibook-reviews 1 books lcustomers lorder l t e m s 1 orders
- -
'I
-
5 rows in set (0.06 sec)
Tambien puede utilizar la instrucci6n show para ver una lista de bases de datos escribiendo mysql>
show
databases;
Puede ver m6s informaci6n sobre una tabla concreta, por ejemplo, libros, utilizando DESCRIBE: mysql>
describe
books;
MySQL mostrar6 la informaci6n suministrada a1 crear la base de datos: l Field
Type
l Null
I
I isbn
Ichar(l3)
I
1 PRI
Key
1 Default
I Extra
I
I
I
I
Desarrollo Web cor, P H P JI MySQL
Estos comandos resultan titiles para recordar un tip0 d e columna o navegar por una base d e datos creada por otra persona.
Identificadores de MySQL MySQL consta d e cuatro tipos d e identificadores: las bases d e datos, las tablas, las columnas (elementos que ya conocemos) y 10s alias, clue examinaremos en el siguiente capitulo. Las bases d e datos d e MySQL se asignan a directorios en la estructura d e archivos subyacente y las tablas lo hacen a archivos. Este hecho afecta directamente a 10s nombres clue se les puede asignar. Tambien afecta a1 uso de may6sculas y minusculas en dichos nombres. Si su sistema operativo discrimina entre mayusculas y minusculas utilizados en 10s nombres d e 10s directorios o archivos, 10s nombres seleccioi~adospara designar las bases de datos y las tablas tambien lo hartin (por ejemplo, en UNIX) o, en caso contrario, no lo hardn (por ejemplo, en Windows). Los nombres d e columnas y 10s alias no discriminan entre mayusculas y minusculas, per0 no puede utilizar versiones diferentes d e 10s nombres en la misma instrucci6n d e SQL. La ubicaci6ii del directorio y 10s archivos que contengan 10s datos se establece en la configuraci6n. Puede comprarlo e n s u sistema utilizando la instrucci6n m y s q l a d m i n d e la siguiente forma: !nysi{l,3dmir1v . ? r l a t r l P S
Estamos buscando la variable d a tadi r. En la tabla 8.4 se recoge u n resumen d e 10s posibles identificadores. La unica excepcion adicional es que no se puede utilizar ASCII(O), ASCII(255) ni el caricter d e comillas en 10s identificadores (que es muy probable clue n o utilice). Tabla 8.4. ldentificadores de MySQL -
Tipo
mdxima
Base de datos
- -
Longitud
64
~Discriminaentre mayusculas y minthculas?
Caracteres permitidos
segun el sisterna operativo
Todos 10s caracteres perrnitidos por el sistema operativo para el nombre de un directorio a excepcion de 10s caracteres /, \, y . .
-Caracteres permitidos
-
7
Tipo
Longitud mexima
~ D i s c r i m i n aentre mayuscwlas y minQsculas?
Tabla
64
segun el sisterna operativo
Todos 10s caracteres permitidos por el sistema operativo en un nombre de archivo a excepcion de 10s caracteres / y . .
Columna
64
no
Todos 10s caracteres.
Alias
255
no
Todos 10s caracteres
Las reglas son muy abiertas. Desde la versi6n MySQL 3.23.6, se pueden utilizar palabras reservadas y caracteres especiales d e todos 10s tipos en identificadores, la unica limitaci6n es colocar entre comillas inclinadas 10s caracteres extrafios. Por ejemplo:
Las reglas de las versiones d e MySQL (anteriores a la 3.23.6) son mas restrictivas y no lo permiten. Obviamente, conviene aplicar sentido comun a toda esta libertad. El hecho d e poder llamar a una base d e datos 'crear base d e datos' no significa que tengamos que hacerlo. Se aplica el mismo principio aplicado en otros tipos d e programaci6n: utilice identificadores descriptivos.
Tipos d e dato d e colurnna En MySQL existen tres tipos bAsicos d e columnas: num6ric0, d e fecha y hora, y d e cadena. Cada categoria incluye un gran numero de tipos. En este capitulo 10s resumiremos. En un capitulo posterior se analizaran sus puntos fuertes y sus puntos d6biles. Cada uno d e 10s tres tipos dispone d e varios tamanbs d e almacenamiento. A1 seleccionar un tip0 d e colurnna, el principio general consiste en escoger el tip0 mas pequefio en el que encajen 10s datos. Muchos d e 10s tipos permiten especificar el tamafio maxim0 d e visualizaci6n a1 crear la colurnna. Esta opcidn se identifica en las siguientes tablas con una m. Si resulta opcional se coloca entre corchetes. El valor maximo que se puede especificar para M es 255. En las siguientes descripciones se utilizan 10s corchetes para indicar valores opcionales.
Desnrrollo Web con P H P y MySQL
Los tipos numericos son nameros enteros o de coma flotante. En el caso de 10s nameros de coma flotante, puede especificar el nfimero de lugares decimales. En este Iibro se utiliza D para indicarlo. El valor m6ximo que se puede especificar para D es d e 30 o M-2 (es decir, la longitud mixima d e visualizaci6n menos dos, es decir, un carActer para el punto decimal y uno para la parte entera del ntimero), segan cual sea la menor. Para 10s tipos enteros tambi6n puede especificar si desea que Sean U N S I G N E D , como se muestra en el listado 8.1. En todos 10s tipos num6ricos, tambien puede especificar el atributo ZEROFILL. Cuando se muestran 10s valores de una columna Z E R O F I LL, se rellenarin con ceros a la derecha. Si especifica una columna como Z E R O F I L L , se le asignari automjtican~enteel atributo U N S I GNED. En la tabla 8.5 se muestran 10s tipos integrales. En la columna de rangos se muestran 10s rangos con firma y sin firma en lineas diferentes. Tabla 8.5. Tipos de datos integrales
Tipo
TINYINT [ (M)]
Rango
Espacio de almacenarniento (bytes)
Descripcion
1
Enteros muy pequefios
BIT
Sinonimo de TINYINT
BOOL
Sinonimo de TINYINT
SMALLINT [ (M)]
Enteros pequeiios
MEDIUMINT [ (M)]
Enteros de tamatio medio
4
Enteros normales
INTEGER [ (M)]
Sinonimo de INT
BIGINT [ (M)]
Enteros grandes
En la tabla 8.6 se recogen 10s tipos d e coma flotante.
.
8. Crcwidn dc In base de dntos Web
Tabla 8.6. Tipos de datos de coma flotante 7
.. .-
-
Rango
Tipo
Descripcidn IlllGllLW
FLOAT ( p r e c i s i o n )
depende de la precision
varia
\&JyLGV/
Se puede utilizar para especificar numeros de coma flotante de precision unica o doble.
FLOAT [
(M,D ) ]
f 1 .I75494351 E-38 f3.402823466E+38
Nurnero de coma flotante de precision unica. Equivale a FLOAT(4), per0 con un ancho de visualizacion y un numero de decimales especificado.
DOUBLE [
(M,D) 1
+I. 7976931 3486231 57E +308 f2.2250738585072OI 4E -308
Equivale a FLOAT(8) per0 con un ancho de visualizacion dado y con un numero concreto de decimales. Sinonimo de D O U B L E [(MtD)I.
DOUBLE
P R E C I S ION [ ( M , D ) ]
como arriba Sinonimo de D O U B L E [ (M, D )
I.
DECIMAL [ ( M [ ,D l ) ]
varia
Numero de coma flotante almacenado corn0 char. El rang0 depende de M, la anchura de visualizacion.
NUMERIC [ (M,D ) ]
corno arriba
Sinonirno de DECIMAL.
corno arriba
Sinonimo de DECIMAL.
DEC [
(M,D )
I
T i p s dc fecha y hora MySQL admite una gran cantidad de tipos de fecha y hora, como se puede observar en la tabla 8.7. Estos tipos permiten recoger datos en formato num4rico o de cadena. Conviene destacar que si se utiliza una colurnna TIMESTAMP se establecera en la fecha y hora correspondiente a la operaci6n mhs reciente realizada sobre la fila si no se establece manualmente. Este comportamiento resulta Otil para el registro de transacciones.
D r s a r r o l l o Web cori P H P y iMySQL -
-
-
-
Tabla 8.7. Tipos de datos de fecha y hora -.
-I
-
.
-
-
-.-.:-
-
.-
-
Tipo
Rango .
DATE
1000-01-01 9999-1 2-3 1
Una fecha. Se mostrara con formato AAAA-MM-DD.
TIME
-838:59:59 838:59:59
Una hora. Se mostrara con formato H H : ~ SS. : Tenga en cuenta que el rango resulta mucho mas amplio de lo que es probable que necesite.
DATETIME
Una fecha y una hora. Se mostraran con el formato YYYY-MM-DD HH:MM: SS.
TIMESTAMP [ (M)1
Una marca de tiernpo, que resulta util para la generacion de informes. El formato de visualizacion depende del valor de M (vease la tabla 8.8 situada a continuacion). Alglin mornento en 2037
La parte superior del rango depende del lirnite de las rnarcas de tiempo de UNIX. Un aiio. Puede especificar un formato de 2 a 4 digitos. Cada uno de estos tiene un rango diferente, como se muestra.
L a tabla 8.8 muestra 10s diferentes tipos de formatos de visualizaci6n T TIMESTAMP. Tabla 8.8. Tipos de formato de visualizacion de TIMESTAMP -...
Tipo especificado
--C-
Formato de visualization
TIMESTAMP
AAAAMMDDHHMMSS
TIMESTAMP (14)
AAAAMMDDHHMMSS
TIMESTAMP (12)
AAMMDDHHMMSS
TIMESTAMP (10)
AAMMDDHHMM
TIMESTAMP (8)
AA44MMDD
TIMESTAMP (6)
AAMMDD
TIMESTAMP (4)
AAMM
TIMESTAMP (2)
PA
-
-.
-=
--.--
8. Crencidti de In bnse d e lintos Web
Los tipos d e cadena se clasifican en tres grupos. En primer lugar, estcin las antiguas cadenas planas, es decir, pequeiios fragmentos de texto. Se trata de 10s tipos CHAR (caracter d e longitud fija) y VARCHAR (cardcter d e longitud variable). Puede especificar la anchura d e cada una. Las columnas d e tipo CHAR se rellenarin con espacios hasta cubrir la anchura mixima, independientemente del tamaiio d e 10s datos. (MySQL elimina 10s espacios que sobran a la derecha d e CHARS a1 recuperarlos y d e VARCHARS a1 almacenarlos.) En un capitulo posterior examinaremos las ventajas y desventajas en t6rminos d e espacio y velocidad d e estos dos tipos. En segrindo lugar, estin 10s tipos TEXT y BLOB. Estos tipos disponen de varios tamaiios. Equivalen a texto largo y datos binarios, respectivamente. Los B L O B son objetos largos binarios. Pueden incluir todo lo que se necesite, por ejemplo, imagenes o sonidos. En la practica, las columnas B L O B y T E X T son iguales con la salvedad d e que TEXT discrimina entre may6sculas y m i n ~ s c u l a s ,y BLOB no lo hace. Como estos tipos de columna pueden contener grandes cantidades de datos, es necesario tener en cuenta una serie d e consideraciones, como se verd en u n capitulo posterior. El tercer grupo consta d e dos tipos especiales, SET y ENUM. El tipo SET se utiliza para especificar que 10s valores d e esta columna deben proceder d e un conjunto d e valores dados. Los valores d e columna pueden contener m i s d e un valor del conjunto. Cada conjunto especificado puede contener un miximo d e 64 elementos. ENUM es una enumeraci6n. Es muy similar a SET, con la excepci6n d e que las columnas d e este tip0 s610 pueden tener uno de 10s valores especificados o NULL y el mdximo n6mero de elementos de la enumeraci6n s e r i de 65.535. En las tablas 8.9 y 8.10 se recogen 10s tipos d e datos de cadena. La tabla 8.9 muestra 10s tipos d e cadena comunes. Tabla 8.4. Tipos de cadena habituales
[NATIONAL] CHAR (M) [BINARY]
De 0 a 255 caracteres
Cadena de longitud fija M, donde M se establece entre 0 y 255. Se trata del tipo predeterminado en MySQL, pero se incluye ya que forma parte del estandar ANSI SQL. La palabra clave BINARY espec~ficaque 10s datos deberian tratase como si no dis criminaran entre mayusculas y minusculas. (De manera predeterminada, discrimina entre mayusculas y minusculas.)
CHAR
I
Sinonimo de CHAR(1)
[NATIONAL] VARCHAR (M) De 1 a 255 [BINARY] caracteres
lgual que el anterior, con la excepcion que la longitud es variable.
Dcsarrollo Web coil PHP y MySQL
La tabla 8.10 describe 10s tipos TEXT y BLOB. La longitud de un campo TEXT en caracteres e s el tamaiio maximo en bytes d e 10s archivos que yodrian almacenarse en dicho campo. Tabla 8.10. Tipos TEXT y BLOB -
Tipo
Longitud mdxima (caracteres)
Descripci6n
TINYBLOB
28 -1 (es decir, 255)
Un campo BLOB pequefio
TINYTEXT
-1 (es decir, 255)
Un campo TEXT pequefio
BLOB
216 -1 (es decir, 65.535)
Un camp0 BLOB de tamatio normal
TEXT
215 -1 (es decir, 65.535)
Un campo TEXT de tamafio normal
MEDIUMBLOB
224-1(es decir, 16.777.215)
Un campo BLOB de tamatio intermedio
MEDIUMTEXT
224-1((es decir, 16.777.215)
U n campo TEXT d e tamatio intermedio
LONGBLOB
232-1(es decir, 4.294.967.295) Un campo BLOB de tamatio grande
LONGTEXT
232-1(es decir, 4.294.967.295) Un campo TEXT de tamafio grande
La tabla 8.11 muestra 10s tiyos ENUM y SET. Tabla 8.1 1. Tipos SET y ENUM
Tipo
Valores mdximos del conjunto
Descripci6n
Las columnas de este tip0 solo pueden contener uno de 10s valores listados o NULL. Las columnas de este tip0 pueden contener un conjunto de valores especificados o NULL.
Si desea obtener miis informaci6n, puede consultar el manual en linea de MySQL para configurar una base de datos e n http: //www .mysql corn/.
.
8. Creacidn de la base de datos W e b
A continuacion Ahora que ha aprendido a crear usuarios, bases de datos y tablas, puede concentrarse en interactuar con la base de datos. En el siguiente capitulo, veremos cdmo introducir datos en tablas, c6mo actualizarlos y eliminarlos, y c6mo consultar la base de datos.
En este capitulo vamos a analizar el lenguaje de consulta estructurado (SQL) y su uso para consultar bases de datos. Continuaremos con la base de datos Book-ORama. En concreto, veremos c6mo insertar, eliminar y actualizar datos y c6mo realizar preguntas a la base de datos. En este capitulo se abordar6n 10s siguientes aspectos: Concepto de SQL
-
-
Inserci6n de datos en la base de datos Recuperaci6n de datos de la base de datos Combinaci6n de tablas Actualizaci6n de registros desde tablas Modificaci6n de tablas tras su creaci6n Eliminaci6n de registros desde la base de datos Eliminaci6n de tablas Comenzaremos por explicar el significado de SQL y por qu4 resulta titi1 entender el concept0 en el que se basa este lenguaje. Si no ha creado la base de datos de Book-0-Rama, necesitard hacerlo para poder ejecutar las consultas SQL de este capitulo. En un capitulo anterior encontrard las instrucciones.
9. Cdmo trabajar con la base de datos de MySQL
iQuC es SQL? SQL equivale a lenguaje de consulta estructurado. Se trata del lenguaje estdndar para acceder a 10s sistemas de administraci61-1de base de datos (RDBMS). SQL se utiliza para almacenar y consultar datos desde y hasta una base de datos. Se utiliza en sistemas de base de datos como MySQL, Oracle, PostgreSQL, Sybase y Microsoft SQL Server entre otros. Existe un estdndar ANSI de SQL, y 10s sistemas de bases de datos como MySQL suelen implementarlo. Sin embargo, existen diferencias sutiles entre el SQL estdndar y el SQL de MySQL, que en algunos casos estd previsto integrar en el estdndar y en otros resultan deliberadas. A medida que avancemos, iremos indicando 10s casos mds importantes. En el manual en linea de MySQL se recoge una lista completa de las diferencias entre el SQL de MySQL y el SQL ANSI de cada versibn. Esta pigina se puede encontrar en el siguiente URL asi como en otras muchas direcciones:
Puede que haya oido hablar de 10s lenguajes de definici6n de datos (DDL), utilizados para definir bases de datos, y de 10s lenguajes de manipulaci6n de datos (DML), utilizados para consultar bases de datos. SQL trata estos tipos de bases. En un capitulo anterior, vimos la definici6n de datos (DDL) en SQL, por lo que ya la hemos utilizado. Este lenguaje se utiliza a1 configurar inicialmente una base de datos. Utilizaremos 10s aspectos DML de SQL con mucha mayor frecuencia porque nos servirdn para almacenar y recuperar datos reales de una base de datos.
Insertion de datos en la base de datos -
-
Para poder trabajar con la base de datos, es necesario almacenar datos en ella. La forma mds habitual de llevar a cab0 esta operaci6n consiste en utilizar la instrucci6n I N S E R T de SQL. Recuerde que 10s RDBMS contienen tablas, que a su vez contienen filas de datos organizados en columnas. Cada fila de una tabla suele describir un objeto o relaci6n del mundo real y 10s valores de las columnas para dichas filas almacenan informacidn sobre el mundo real. Podemos utilizar la instrucci6n I N S E R T para colocar filas de datos dentro de la base de datos. A continuaci611, se recoge la sintaxis habitual de una instrucci6n INSERT: INSERT [INTO] t a b 1a [ ( col umna 1 , ( valorl, valor2, v a l o r 3 , . .. ) ;
col u m n a 2 ,
col u m n a 3 ,
...) 1
VALUES
Por ejemplo, para insertar un registro dentro de la tabla c u s t o m e r s de Book-0Rama, puede escribir insert i n t o customers values "25 (NULL, "Julie Smith",
Oak
Street",
"Airport
West") ;
Desarrollo Web con P H P y MySQL
Como puede observar, hemos sustituido tabla por el nombre de la tabla en la que queremos colocar 10s datos y 10s valores con valores especificos. Los valores de este ejemplo se encierran enfre comillas dobles. En MySQL, las cadenas deberian encerrarse siempre entre comillas simples o dobles. (En este libro utilizaremos ambas.) Los numeros y las fechas no necesitan comillas. Existen ciertas cosas interesantes en 10s que fijarse en relaci6n a la instrucci6n INSERT.
Los valores que especificamos se utilizarin para rellenar las columnas de la tabla en orden. Si desea rellenar s610 algunas columnas o si quiere especificarlas en un orden diferente, puede enumerar las deseadas en la parte reservada para las columnas de la instrucci6n. Por ejemplo: insert into customers (name, city) values ("Melissa Jor~es", "Nar Nar Goon North");
Este enfoque resulta util si s610 se dispone de datos parciales sobre un registro dado o si algunos campos del registro son opcionales. Puede obtener el mismo efecto con la siguiente sintaxis: insert into customers set narne="Michael Archer", address="12 Adderley Avenue", city="Leeton";
Como puede observar, especificamos un valor NULL para la columna personalizada a1 agregar a Julie Smith e ignoramos dicha columna a1 agregar el resto de 10s clientes. Puede que recuerde que a1 configurar la base de datos, creamos la columna c u s t o m e r i d como clave principal de la tabla c u s t o m e r s por lo que puede que le resulte extraiio. Sin embargo, especificamos el campo como AUTO INCREMENT, lo que significa que si insertamos una fila con un valor NULL o sin niigun valor en este campb, MySQL generarti el siguiente numero en la secuencia de increment0 automatica y la insertarA sin nuestra intervenci61-1,lo cual resulta bastante util. Tambikn puede insertar varias filas dentro de una tabla de una sola vez. Cada fila deberia incluirse en su propio conjunto de corchetes y cada conjunto de corchetes deberia separarse por medio de una coma. Hemos reunido algunos datos de ejemplo para rellenar la base de datos. Se trata de una serie de simples instrucciones I N S E R T que utilizan el enfoque de inserci6n multifila comentado. La secuencia de comandos que realiza esta tarea podrri encontrarla en el CD que se adjunta a1 libro, en el archivo correspondiente a esta carpeta. Tambikn se recoge en el listado 9.1. Listado 9.1. book-insert.sql. SQL para rellenar las tablas de Book-0-Rarna use
books;
insert into customers values (NULL, "Julie Smith", "25 Oak
Street",
"Airport
West"),
(NULL, "Alan Wong", "1/47 Haines Avenue", "Box Hill"), (NULL, "Michelle Arthur", "357 North Road", "Yarraville"); insert into orders values (NULL, 3, 69.98, "2000-04-02"), (NULL, 1, 49.99, "2000-04-15"), (NULL, 2, 74.98, "2000-04-19"), (NULL, 3, 24.99, "2000-05-01"); insert into books values ("0-672-31697-En, "Michael Morgan", "Java 2 for Professional Developers", 34. 99), ("0-672-31745-I", "Thomas Down", "Installing Debian GNU/Linuxn, 24.991, ("0-672-31509-2", "Pruitt, et al.", "Teach Yourself GIMP in 24 Hours", 24.991, ("0-672-31769-9", "Thomas Schenk", "Caldera OpenLinux System Administration Unleashed", 49.99); insert (1, (2, (3, (3, (4,
into order-items "0-672-31697-8", "0-672-31769-9", "0-672-31769-9", "0-67'2-31509-2", "0-672-31745-I",
values 2), I), I), I), 3);
insert into book reviews values ("0-672-31697-a", "Morqan's book is clearly written and goes well beyond most of the basic Java books out there."); -
Puede ejecutar esta secuencia de comandos a travks de MySQL de la siguiente forma: >mysql -h host -u bookorama -p < book insert.sq1 -
Recuperaci6n de datos de la base de dato La mula de carga de SQL es la instrucci6n SELECT. Se utiliza para recuperar datos de una base de datos seleccionando las filas que coinciden con 10s criterios especificados de una tabla. La instrucci6n S E L E C T consta de una gran cantidad de opciones y formas de uso. La forma bfisica de una instrucci6n S E L E C T es 'la siguiente: SELECT elementos FROM tablas [ WHERE condici6n ] [ GROUP BY tipo-grupo ] [ HAVING definici6n-de-d6nde [ ORDER BY tipo-orden ] [ LIMIT criterios limite ] ;
]
-
Comentaremos cada una de estas clfiusulas de la instrucci6n. En primer lugar, vamos a examinar una consulta sin ningtin parfimetro opcional que selecciona algu-
Desarrollo W e b con PHP y M y S Q L
nos elementos de una tabla dada. Por regla general, se trata de columnas de la tabla. (Tambien pueden ser 10s resultados de cualquier expresi6n de MySQL. Analizaremos algunos de 10s mds utiles en una secci6n posterior.) La siguiente consulta enumera 10s contenidos de la columna name y c i t y de la tabla c u s t o m e r s : s e l e c t name, c i t y from c u s t o m e r s ;
Esta consulta devuelve el siguiente resultado, siempre y cuando haya introducido 10s datos de ejemplo del listado 9.1 y las dos instrucciones INSERT de ejemplo:
Como puede observar, tenemos una tabla que contiene 10s elementos seleccionados (name y c i t y ) de la tabla especificada, c u s t o m e r s . Los datos se muestran para todas las filas de la tabla c u s t o m e r s . Puede especificar tantas columnas como desee de una tabla enumerdndolas tras la palabra clave s e l e c t . Tambien puede especificar algunos otros elementos. Uno util es el operador comodin, *, que selecciona todas las columnas de la tabla o tablas especificadas. Por ejemplo, para recuperar todas las columnas y todas las filas de la tabla o r d e r -i t ems, utilizariamos select * from o r d e r i t e m s ; -
-
-
que devolverd el siguiente resultado:
Recuperacion de datos con criterios especificos Para poder acceder a un subconjunto de filas de una tabla, necesitamos especificar algunos criterios de selecci6n. Para ello se puede utilizar la c l h s u l a WHERE. Por ejemplo, select
*
9. Cdrrio trabajar corr la bose de ifatos de MySQL
seleccionarci todas las columnas d e la tabla d e pedidos pero s61o las filas con c u s tomerid d e 3.
La cliiusula WHERE especifica 10s criterios utilizados para seleccionar filas concretas. En este caso, henlos seleccionado las filas con un Id. d e cliente d e 3. El signo igual se utiliza para probar la igualdad (tenga en cuenta que es diferente con respecto a PHP y que resulta sencillo confundirlos cuando se utilizan juntos). Adernds d e la igualdad, MySQL adrnite un conjunto completo d e operadores d e comparaci6n y d e expresiones regulares. En la tabla 9.1 se recogen las mas comunes. Tenga en cuenta que n o se trata d e una lista completa (si necesita algun operador no enurnerado, consulte el manual d e MySQL). Tabla 9.1. Operadores de comparacion utiles para las clausulas WHERE -
-
Operador
Nombre (si resulta de aplicacion)
-
igualdad
customerld
>
mayor que
importe
> 60.00
Comprueba si u n valor es mayor que otro
menor que
importe
< 60.00
Comprueba si u n valor es menor que otro
mayor o igual que
i m p o r t e >= 6 0 . 0 0
Comprueba si u n valor es mayor o igual que otro
<=
menor o igual que
i m p o r t e <= 6 0 . 0 0
Comprueba si u n valor es menor o igual que otro
!=O<>
diferente
cantidad
<
>=
Descripcion
=
3
!= 0
Comprueba si dos valores son iguales
Comprueba si dos valores no son iguales
I S NOT N U L L
d i r e c c i o n is not n u l l
C o m p r u e b a si el campo contiene un valor
I S NULL
d i r e c c i o n es n u l l
C o m p r u e b a si el campo no contiene un valor
Desnrrollo Web corr P H P y MySQL ---.
--.. - -- - .
*
-
Operador
Nornbre (si resulta d e aplicacion)
Ejemplo
Descripci6n
BETWEEN
nI d
importe between
Comprueba si un valor es mayor o igual que un valor minimo o menor o igual que un valor rnaximo
ciudad in ("Carlton", "Moe")
Comprueba si u n valor s e i n c l u y e dentro de un conjunto dado
ciudad in ("Carlton", "Moe")
Cornprueba si u n valor no se incluye en un conjunto
NOT IN
LIKE
correspondencia de patron
nombre like
Comprueba si un valor coincide con un patron utilizando simples patrones d e correspondencia de SQL
NOT LIKE
correspondencia d e patrones
nombre not like ("Fred :" )
Comprueba si u n valor n o coincide con un patron
REGEXP
expresion regular
nombre regexp
Comprueba si un valor coincide con una expresion regular
..
,
Las illtimas tres entradas de la tabla hacen referencia a L I K E y REGEXP. Se trata d e operadores para la blisqueda d e correspondencias en forma d e patr6n. L I K E utiliza correspondencias d e patrcin simples d e SQL. Los patrones pueden consistir en texto normal rnds el carcicter (porcentaje) para indicar una coincidencia con cualquier numero d e caracteres y el carcicter - (gui6n bajo) para sustituir a u n solo car5cter e n la bilsqueda d e correspondencias. La palabra clave R E G E X P se utiliza para las bilsquedas d e correspondencias con expresiones regulares. MySQL utiliza expresiones regulares d e POSIX. En lugar d e REGEXP, puede utilizar R L I K E ya clue son equivalentes. Las expresiones regulares d e POSIX tambikn se utilizan en PHP. Puede leer mds a1 respecto e n u n capitulo anterior. Puede probar una gran cantidad d e criterios d e esta forma y combinar 10s operadores con AND y O R . Por ejemplo:
from orders where customerid
=
3
or
customerid=4;
Recuperacih de datos desde varias tablas A menudo, para responder a una pregunta desde la base de datos, es necesario utilizar datos incluidos en mas de una tabla. Por ejemplo, si quiere saber 10s clientes que realizaron pedidos durante el presente mes, necesitara buscar en la tabla customers y en la tabla Orders. Si ademas quiere saber quk articulos pidieron, necesitara consultar la tabla Order Items. Estos datos se encuentran distribuidos en varias tablas porque hacen referencia a objetos independientes del mundo real. 6ste es uno de 10s principios del buen diseiio de bases de datos comentado en un capitulo anterior. Para reunir esta informaci6n en SQL, debe aplicar una operaci6n denominada combinaci6n. Esta operaci6n consiste en unir dos o mas tablas para seguir la relaci6n entre 10s datos. Por ejemplo, si deseamos ver 10s pedidos realizados por Julie Smith, necesitaremos examinar la tabla us tomers para buscar el identificador de Julie y, a continuaci611, mirar en la tabla Orders para buscar 10s pedidos que tengan dicho identificador. Aunque las combinaciones resultan conceptualmente sencillas, son una de las partes mds sutiles y complejas de SQL. En MySQL se implementan varios tipos diferentes de combinaci6n y cada uno de ellos se utiliza para una finalidad diferente.
Combinaciones sencillas de dos tablas Comenzaremos por examinar algunas instancias de SQL para consultar la informaci6n sobre Julie Smith de la que acabamos de hablar:
-
-
select orders.orderld, orders.amount, orders.date from customers, orders where customers.name = 'Julie Smith' and custarners.customerid = orders.customerid;
El resultado de esta consulta es
Tenemos que fijarnos en varios elementos. En primer lugar, como es necesario obtener informaci6n de las dos tablas para contestar a esta consulta, se han listado ambas. Tambikn se ha especificado el tip0 de combinaci6n, posiblemente sin ser consciente de ello. La coma situada entre 10s nombres de las tablas equivale a escribir INNER JOIN o CROSS JOIN.h e es un tipo de combinaci6n a1 que a veces tambikn
Desarrollo W e b con PHP y MySQL
se hace referencia como combinacibn completa o el product0 cartesiano de tablas. Significa "toma las tablas indicadas y crea otra con ellas; esta tabla deberia constar de una fila para cada combinaci6n posible de filas de cada una de las tablas indicadas, ya tenga sentido o no". En otras palabras, obtenemos otra tabla, que incluye todas las filas de la tabla Customers que se correspondan con cada fila de la tabla Orders, independientemente de si un cliente realiz6 un pedido concreto. En muchas ocasiones el resultado no tiene mucho sentido. Por regla general, lo que queremos es ver las filas coincidentes, es decir, 10s pedidos realizados por un cliente dado y la informacibn correspondiente del cliente. Para lograrlo se utiliza una condicio'n de cornbinacidn en la clausula WHERE.Se trata de un tip0 especial de instrucci6n condicional que explica qu6 atributos muestran la relaci6n entre dos tablas. En este caso, la condicibn de combinaci6n es la siguiente:
que indica a MySQL que ponga filas en la tabla de resultados si el customerId de la tabla customers coincide con el Cus tomerId de la tabla Orders. A1 agregar esta condici6n de combinacidn en la consulta, hemos creado otro tip0 de combinaci6n llamada cornbinacidn de igualdad. La notaci6n de punto utilizada deja claro a qu6 tabla pertenece una columna dada, es decir, customers customerid hace referencia a la columna cus tome rid de la tabla Customers y order. customerid hace referencia a la columna customerid de la tabla orders. Esta notaci6n es obligatoria si el nombre de una columna resulta ambiguo, es decir, si aparece en mas de una tabla. Tambi6n se puede utilizar para distinguir 10s nombres de columnas utilizados en diferentes bases de datos. En este ejemplo, se ha utilizado la notacibn tabla.columna. Puede especificar la base de datos con una notaci6n basededatos.tabla. columna, por ejemplo, para p r ~ b a una r condicidn como
.
books.orders.customerid
=
o t h e r db.orders. customerid
Sin embargo, puede utilizar la notaci6n de punto para todas las referencias de columna de una consulta. Esta opcion es una buena idea, en especial cuando las consultas comienzan a complicarse. Su uso no es obligatorio en MySQL per0 las consultas resultaran mucho mas legibles y sencillas de mantener. Como puede apreciar, hemos utilizado esta convenci6n en el resto de la consulta anterior, por ejemplo, a1 utilizar la condition customers.name
=
'Julie
Smith'
El nombre de columna s610 tiene lugar en la tabla de clientes por lo que no necesitaremos especificarlo, aunque resultar6 mas claro.
Combinaci6n de varias tablas Cuando se combinan m6s de dos tablas la operacidn se complica. Como regla general, en las condiciones de combinaci6n se combinan las tablas de dos en dos.
9. Cdmo trabajar con la base de datos de MySQL
Es como seguir las relaciones entre 10s datos de una tabla a otra tabla a otra tabla, etc. Por ejemplo, si queremos saber qu6 clientes han pedido libros sobre Java (por ejemplo, para poder enviarles informaci6n sobre un nuevo libro), necesitaremos rastrear dichas relaciones a trav6s de bastantes tablas. Tendremos que buscar clientes que hayan realizado a1 menos un pedido que incluya un libro de Java. Para acceder a la tabla Order s desde la tabla c u s tome r s podemos utilizar la columna cus tome r i d como hicimos anteriormente. Para acceder a la tabla Order I tems desde la tabla Orders, podemos utilizar la columna o r d e r i d . Para acceder a un libro especifico de la tabla Books desde la tabla Order 1 t e m s , podemos utilizar el ISBN. Tras establecer estos enlaces, podemos buscaribros que incluyan el termino Java en el titulo y recuperar 10s nombres de 10s clientes que hayan comprado alguno de ellos. Examinemos la consulta que realiza estas operaciones. select customers.name from customers, orders, order items, books where customers.customerid = orders.custornerid and orders.orderid = order items.orderid and order items.isbn = books.isbn and books.title like '%Java%'; -
-
-
Esta consulta devuelve el siguiente resultado:
Fijese en que seguimos 10s datos a trav6s de cuatro tablas diferentes y, para hacerlo con una combinaci6n de igyaldad, necesitamos tres condiciones de combinaci6n diferentes. Por regla general, se necesita una condici6n de combination para cada par de tablas que se desee combinar, por lo que el total de condiciones de combinaci6n sera igual a1 n6mero de tablas que se desean combinar menos uno. Esta regla puede resultar 6til para consultas de depuraci6n que no funcionen. Compruebe las condiciones de combinaci6n y asegurese de haber seguido la ruta desde lo que sabe a lo que desea saber.
Busqueda de filas que no coincidan El segundo tip0 principal de consultas que utilizaremos en MySQL son las combinaciones por la izquierda. En 10s ejemplos anteriores, s610 se han incluido las filas coincidentes entre las tablas. En ocasiones, se necesita recuperar las filas que no coincidan. Por ejemplo, 10s clientes que no hayan realizado nunca un pedido o 10s libros que no se hayan pedido nunca. La forma m i s sencilla de responder a este tip0 de cuesti6n en MySQL es utilizar una combinaci6n por la izquierda. En estas combinaciones se comparan filas a partir
Desarrollo Web con PHP y MySQL
de una condici6n de combinaci6n dada entre dos tablas. Si no existen filas coincidentes en la tabla de la derecha, se agregari una fila a1 resultado que contenga valores N U L L en las columnas de la derecha. Veamos un ejemplo: select customers.customerid, customers.name, from customers left join orders on custorners.customerid = orders.customerid:
orders.orderid
La consulta SQL utiliza una combinaci6n por la izquierda para combinar combination por la izquierda utiliza una sintaxis un tanto diferente en la condici6n de combinaci6n. En este caso, dicha combinaci6n va en una cliiusula O N especial de la instruccidn SQL. El resultado de la consulta es el siguiente: C u s t o m e r s con O r d e r s . La
1 orderid I
l r~ame +---------------+---------+
Smith I \ A l a n Wong I 1 Michelle Arthurl 1 Michelle Arthurl IMelissa Jones I [ M i c h a e l Archer I
l Julie
2 3 1 4 NULL NULL
1 1
I 1
I I
Este resultado muestra que no existen Id. de pedido coincidentes para Melissa Jones y Michael Archer porque dichos Id. son N U L L . Si s610 deseamos ver 10s clientes que no hayan realizado ningun pedido, podemos recuperarlos utilizando dichos valores N U L L en el campo de clave principal de la tabla de la derecha (en este caso o r d e r i d ) .
-
-
select customers. customerid, customers. name from customers left join orders using (customerid) where orders. orderid is null;
El resultado serh:
Como observari, hemos utilizado una sintaxis diferente para la condicidn de combinacion en este ejemplo. Las combinaciones por la izquierda admiten la sintaxis O N utilizada en el primer ejemplo o la sintaxis U S I N G del segundo. Tenga en cuenta que la sintaxis U S I N G no especifica la tabla de la que procede el atributo de combinaci6n. Por esta razdn, las columnas de las tablas deben tener el mismo nombre si queremos utilizar U S I N G .
9. Cdmo trnbnjnr con In bnse de dntos de MySQL
A menudo resulta prActico, y a veces necesario, poder utilizar otros nombres para hacer referencia a las tablas. Es lo que se conoce como alias. Los alias se pueden crear a1 principio d e u n a colurnna y utilizarlos a lo largo d e todas ellas. Suelen resultar przicticos por cuestiones d e brevedad. Por ejemplo, examine la consulta q u e escribimos anteriormente pero escrita con alias:
A1 declarar las tablas que vamos a utilizar, agregamos una clziusula AS para establecer el alias asociado a dicha tabla. Tambikn podemos utilizar alias para columnas. Volveremos sobre este tema a1 analizar las funciones d e agregacion. El uso d e alias es obligatorio cuando se trata d e combinar una tabla consigo misma. Suena m i s complicado y extraiio d e lo q u e parece. Resulta Gtil, por ejemplo, si queremos buscar filas d e la misma tabla con valores comunes. Si queremos buscar clientes q u e vivan e n la misma ciudad (por ejemplo, para establecer u n sitio d e lectura) podemos asignar a la tabla ( C U St o m e r s ) d o s alias diferentes.
Lo q u e estamos haciendo bzisicamente es simular la existencia d e d o s tablas C u s t o m e r s diferentes, cl y c2,y realizar la combinacicin sobre la colurnna c i t y . Como observari tambien necesitamos la segunda condicicin, cl . name ! = c2 . name, para no recuperar todos los clientes por tener el mismo nombre. Rckr~rncnclc lo\ tipo\
dc comhinacicin -
En la tabla 9.2 se recogen 10s diferentes tipos d e combinaciones vistos. Existen otros, pero 10s incluidos en la tabla son 10s mfis importantes para nuestros propcisitos. Tabla 9.2. Tipos de combinacion en MySQL v -
-11111
Nombre
Descripcion
Producto cartesiano
Se combinan todas las filas de todas las tablas. Se utiliza incluyendo una coma entre 10s nombres de las tablas y sin una clausula WHERE.
combinacion total
lgual a la anterior
Desnrrollo Web corr PHP
MySQL
Nombre
Descripcion
Combinacion cruzada
lgual que las anteriores. Tambien se puede utilizar especificando las palabras clave CROSS JOIN entre 10s nombres de las tablas combinadas.
Combinacion interna
Semanticamente, resulta equivalente a la coma. Tambien se puede especificar utilizando las palabras clave INNER JOIN Sin una condicion WHERE resulta equivalente a una combinacion total. Por regla general, se especifica una condicion WHERE para obtener una autentica combinacion interna.
combinacion de igualdad Utiliza una expresion condicional con un signo = para buscar filas coincidentes entre las diferentes tablas de la combinacion. En SQL, equivale a una combinacion con una clausula WHERE. combinacion por la izquierda
Busca filas coincidentes entre tablas y rellena las filas no coincidentes con valores NULL. En SQL, se utiliza con las palabras clave LEFT JOIN. Se utiliza para buscar valores que falten. Tambien se puede utilizar la combinacion RIGHT JOIN de manera equivalente.
Secilperacirjn de clatos con un orden dado Si desea m o s t r a r e n un o r d e n concreto las filas recuperadas e n u n a consulta, p u e d e u t i l i z a r l a cl6usula ORDER B Y d e l a instruction S E L E C T . Esta f u n c i 6 n resulta prActic3 p a r a presentar 10s resultados e n un f o r m a t o l e g i b l e para humanos. L a c l 6 u s u l a ORDER B Y se u t i l i z a p a r a o r d e n a r las filas d e u n a o varias c o l u m n a s listadas e n l a clausula S E L E C T . P o r ejemplo,
Esta consulta d e v u e l v e 10s n o m b r e s y las direcciones e n o r d e n alfab6tico p o r e l nombre:
9. Cn'iizo trnbr.rjnr corz ln base d e dntos de MySQL
(A1 utilizar el formato d e nombre y apellido, 10s registros se ordenan por el nombre. Si desea ordenarlos por el apellido, necesitar6 utilizar dos campos diferentes.) El orden predeterminado es ascendente (de la a a la z o numgricamente hacia arriba). Puede especificar este orden mediante la palabra c l a v e ~ s c :
Tambien puede utilizar la palabra clave DESC (descendente) para aplicar el orden inverso:
Puede ordenar 10s registros por m6s d e una columna. Ademss, puede utilizar alias d e columna o incluso sus ndmeros d e posici6n (por ejemplo, 3 es la tercera colurnna d e la tabla) en lugar d e nombres.
Agrupacicin
y agregaci6n cle datos
A menudo nos interesa saber cuintas filas contiene un conjunto dado o el valor promedio d e una colurnna (por ejemplo, el promedio en mettilico por pedido). MySQL incorpora un conjunto d e funciones d e agregaci6n que resultan dtiles para responder a una consulta. Estas funciones d e agregaci6n se pueden aplicar a una tabla en su conjunto o a grupos d e datos dentro d e una tabla. Lo normal es utilizar las listadas en la tabla 9.3.
.
Tabla 9.3. Funciones de agregacion de MySQL -. -
-
.
I p -
,-
--.-
Nornbre
Description
AVG (columns)
Promedio de 10svalores de la columna especificada
COUNT ( e l e m e n t o s )
Si especifica una colurnna, devolvera el nljrnero de valores que no Sean N U L L de la colurnna. Si agrega la palabra D I S T I N C delante del nombre de la columna, obtendra u n contador de 10s valores diferentes de dicha columna unicamente. Si especifica C O U N T ( * ) , obtendra u n recuento de fila independienternente de 10svalores NULL.
MIN ( c o l u r n n a )
Minimo de 10svalores de la columna especificada.
MAX ( c o l u r n n a )
Maximo de 10s valores de la columna especificada
STD
(columna)
Desviacion estandar de 10svalores de la colurnna especificada.
Desnrrollo W e b con P H P y MySQL
Nombre
Descripcidn
STDDEV (colurnna)
lgual que STD (colurnna).
SUM (colurnna)
Suma de 10s valores de la columna especificada.
Vamos a examinar algunos ejemplos, comenzando por el mencionado anteriormente. Podemos calcular la media total de un pedido de la siguiente forma:
El resultado serA el siguiente:
BY. Esta Para obtener informacion detallada, podemos utilizar la c l ~ u s u l GROUP a cliusula nos permite ver la media de pedidos por grupos (por ejemplo, por el numero d e cliente). De esta forma sabremos qu6 clientes realizan 10s mayores pedidos.
A1 utilizar una cl.5usula G R O U P BY con una funci6n de agregacibn, se modifica el comportamiento d e la funcion. En lugar d e obtener la media de las cantidades d e pedidos de toda la tabla, esta consulta recupera la media de las cantidades de pedidos d e cada cliente (0, paw ser mas especifico, para cada customerid):
Antes utilizar la agrupacion y agregacion d e funciones, tenga en cuenta que en ANSI SQL, si utiliza una funci6n de agregacion o la cl6usula G R O U P BY, lo Gnico que puede aparecer en la clausula S E L E C T son las funciones d e agregaci6n y las columnas designadas en la clAusula G R O U P BY. Asi mismo, si quiere utilizar una colurnna en una clausula GROUP BY, debe listarla en la cl6usula SELECT. MySQL brinda una mayor libertad en este sentido ya que admite sintaxis extendida, lo que nos permite dejar elementos fuera d e la clausula SELECT si no 10s deseamos. Ademas d e agrupar y agregar datos, podemos probar 10s resultados d e una operaa coloca directamente detras ci6n de agregaci6n utilizando la c l ~ u s u l aHAVING. ~ s t se
9. Cdmo trabajar con la base de datos de MySQL
de la cliusula GROUP BY y es como una cliusula WHERE aplicada unicamente a grupos y agregados. En nuestro ejemplo anterior, si queremos saber qu6 clientes tienen pedidos cuyo importe medio supere 10s 50 ddlares, podemos utilizar la siguiente consulta: s e l e c t customerid, avg(amount) from o r d e r s g r o u p by c u s t o m e r i d h a v i n g a v g ( a m o u n t ) > 50;
Fijese en que la cliusula HAVING se aplica a 10s grupos. Esta consulta devolveri el siguiente resultado:
C6mo escoger las filas que recuperar Una cldusula de la instruccidn SELECT que puede resultar especialmente util en aplicaciones Web es la cliusula LIMIT. Esta cliusula se utiliza para especificar qu6 filas deberian devolverse desde el resultado. Toma dos pardmetros: el numero de fila desde la que empezar y el numero de filas que devolver. La siguiente consulta ilustra el uso de L I M I T : s e l e c t name from c u s torners l i m i t 2 , 3;
Esta consulta se puede leer cbmo "seleccionar nombre de clientes y devolver tres filas en el resultado, comenzando en la fila numero 2". Fijese en que 10s numeros de fila estdn indexados en cero, es decir, que la primera fila del resultado es la fila n6mero cero. Esto resulta muy util en aplicaciones Web. Por ejemplo, cuando el cliente esti examinando 10s productos de un catilogo y quiere ver 10 por pdgina.
Actualization de registros en la base de datos Ademds de recuperar datos desde una base de datos, tambi6n resulta normal modificarlos. Por ejemplo, podemos aumentar 10s precios de 10s libros incluidos en la base datos. Para ello, podemos utilizar una instruccidn UPDATE. La forma habitual de una instruccidn UPDATE es la siguiente: UPDATE n o r n b r e t a h l a SET c o l u r n n a l = e x p r e s i 6 n l , c o l umnaZ=expresidn2,.
Desarrollo Web con P H P y M y S Q L
La idea consiste en actualizar la tabla llamada nombretabla, estableciendo cada columna mencionada a la expresi6.n apropiada. Puede limitar la aplicaci6n de la operaci6n UPDATE a filas concretas mediante una cliiusula WHERE y restringir el nLimero total de filas con una clausula L I M I T . Vamos a examinar algunos ejeinplos. Si desea incrementar 10s precios de todos 10s libros u n 10% puede utilizar una instruccion UPDATE con una clAusula WHERE:
Si quiere cambiar una sola fila (por ejemplo, para actualizar una direccion d e cliente), puede hacerlo d e la siguiente forma:
Alkracion de tablas tras su creaci6n AdemAs de actualizar filas, podemos alterar la estructura d e las tablas dentro d e una base de datos. Para ello, se puede utilizar la instruccioi~ALTER TABLE. La forma bssica d e esta instrucci6n es la siguiente:
Fijese en que en ANSI,SQls61o puede realizar una alteracidn por cada instrucc ~ ~ ~ A L TTABLE, E R pero MySQL permite realizar todas las que desee. Cada clausu-
la de alteraci6n se puede utilizar para cambiar diferentes aspectos d e la tabla. En la tabla 9.4 se recogen 10s diferentes tipos de alteraci6n que se puede realizar con esta instruccion. Tabla 9.4. Cambios posibles con la instruccion ALTER TABLE
A D D [COLUMN] d e s c r i p c l o n - c o l umna [FIRST I AFTER colurnna ]
Agrega una nueva columna en la ubicacion especificada. Si no se especifica, la columna ira al final. Fijese en q u e d e s c r i p c i o n columna necesita un nombre y un tipo, como en una instruccion CREATE.
[COLUMN] (description-columna, description-columna, . . . )
Agrega una o varias columnas nuevas a1 final de la tabla.
ADD
9 . C h o trabajar con la base de datos de MySQL
sintaxis
Descrlpcidn
ADD
INDEX
[indice]
ADD
PRIMARY
ADD
UNIQUE
KEY
(columna,
(columa,
[indice]
...)
. ..)
(columna,
. ..)
Agrega un indice a la tabla en la colurnna o columnas especificadas. Convierte la colurnna o columnas especificadas en la clave principal de la tabla. Agrega un indice unico a la tabla en una colurnna o columnas especificadas.
A L T E R [COLUMN] c o l u m n a ( S E T DEFAULT v a l o r I DROP D E F A U L T )
Agrega o elimina un valor predeterminado de una colurnna dada.
CHANGE [ C O L U M N ] c o l u m n a d e s c r l p c i o n n u e v a - c o l umna
Cambia la colurnna llamada columna para que incluya la descripcion. Observe que se puede utilizar para cambiar el nombre de la columns porque descr ipclon-columna incluye un nombre.
MODIFY [COLUMN] d e s c r l p c i o n - c o l umna
Similar a C H A N G E . Se puede util~zarpara cambiar tipos de colurnna, no nombres.
DROP
[COLUMN]
DROP
PRIMARY
DROP
INDEX
RENAME
[AS]
Elimina columnas con nombre
col unma
Elimina el indice principal (pero no la columna).
KEY
Elimina el indice con nombre
indlce nombre-nueva-
tabla
Cambia el nombre de una tabla
Vamos a examinar algunos usos comunes de ALTER TABLE.Algo que suele ocurrir con frecuencia es darse cuenta de que no se ha asignado el ancho suficiente a una colurnna para albergar 10s datos. Por ejempke, en la tabla c u s t o m e r s , hemos asignado30 caracteres de longitud a 10s nombres. A1 recibir datos, puede que descubramos que algunos nombres son demasiado largos y quedan cortados. Podemos solucionar este problema cambiando 10s tipos de datos de las columnas para aumentar su tamafio a 45 caracteres de largo.
Otra cosa que suele ocurrir de manera habitual es la necesidad de agregar una columna. Imagine que se ha introducido un impuesto local y que Book-O-Rama necesita agregarlo a1 total del pedido y realizar su seguimiento por separado. Podemos agregar una columna para el impuesto en la tabla O r d e r s de la siguiente forma: a l t e r tah1.e o r d e r s add t a x f h a t (6,>) a f t e r
amaunt;
Otra necesidad que suele surgir de forma habitual es la de eliminar una columna. Podemos suprimir la columna que acabamos de agregar de la siguiente forma: alter drap
table
tax;
ordcr.~,
Desarrollo Web con P H P y MySQL
Eliminaci6n de registros de la base de datos La operaci6n de eliminar filas de la base de datos resulta sencilla. Para ello, puede utilizar la instrucci6n DELETE,que suele presentar este aspecto: D E L E T E FROM t a b l a [WHERE c o n d i c i b n ]
[ L I M I T niirnero]
Si escribe DELETE
FROM t a b l a ;
en solitario, se eliminardn todas las filas de una tabla, por lo que conviene tener cuidado. Lo normal es eliminar filas concretas, para lo cual se pueden especificar en una cliusula WHERE. Por ejemplo, podemos eliminar filas si un libro no estuviera disponible o un cliente concreto llevara mucho tiempo si realizar pedidos y quisiera limpiar un poco la base de datos. delete from customers where customerid=5;
La cldusula LIMIT se puede utilizar para limitar el numero miximo de filas que se eliminan.
Eliminacicin de tablas En ocasiones se necesita eliminar una tabla entera. Para ello se puede utilizar la instrucci6n DROP TABLE.Esta operaci6n resulta muy sencilla y presenta este aspecto. DROP
TABLE
tabla:
Esta instrucci6n eliminari todas las filas de la tabla y la propia tabla, por lo que es necesario tener cuidado.
Eliminacicin de una base de datos entera Podemos ir incluso mis all6 y eliminar una base de datos completa con una instrucci6n DROP DATABASE,que presenta un aspecto parecido a1 siguiente: DROP
DATABASE
base
de
datos;
Esta instrucci6n elimina todas las filas, todos 10s indices y la propia base de datos, por lo no es necesario indicar el cuidado que hay que poner a1 utilizarla.
9. Co'mo trabajar con la base de datos de MySQL
Lecturas adicionales En este capitulo, hemos pasado revista a 10s elementos mds comunes de SQL que se utilizan a1 interactuar con una base de datos MySQL. En 10s siguientes dos capitulos, examinaremos como conectar MySQL y PHP para poder acceder a su base de datos desde la Web. Tambih exploraremos algunas tecnicas avanzadas de MySQL. Si desea saber mds sobre SQL, puede consultar el estdndar ANSI SQL. Lo encontrard en:
Si desea obtener mds detalles sobre las extensiones de MySQL para ANSI SQL puede consultar el sitio Web MySQL:
A continuacion En el siguiente capitulo veremos c6mo permitir el acceso a Book-0-Rama desde la Web.
En un capitulo anterior, a1 trabajar con PHP, utilizamos un archivo sin procesar para almacenar y recuperar datos. En dicho capitulo, indicamos que 10s sistemas de base de datos relacionales facilitan enormemente las tareas de almacenamiento y recuperation de datos y resultan mucho m i s eficientes en una aplicaci6n Web. A continuaci6n, tras trabajar con MySQL, podemos comenzar a conectar esta base de datos a una interfaz de usuario basada en la Web. En este capitulo, explicwemos cdmo acceder a la base de datos Book-0-Rama desde la Web utilizando PHP. Aprender6 a leer una base de datos y a escribir en ella, y a filtrar datos de entrada potencialmente peligrosos. A continuacGn, se recogen 10s aspectos b6sicos que se abordarh: Funcionamiento de las arquitecturas de base de datos Pasos b6sicos para consultar una base de datos desde la Web C6mo configurar una conexi6n C6mo obtener informaci6n sobre bases de datos disponibles Selecci6n de una base de datos que utilizar Cdmo consultar una base de datos Recuperaci6n de 10s resultados de consulta Desconexi6n de la base de datos C6mo colocar nueva informaci6n en la base de datos
10. Acceso a la base de datos de MySQL desde la W e b con PHP
Otras funciones utiles de PHP y MySQL Uso de una interfaz generica debase de datos: PEAR DB Otras interfaces debase de datos de PHP
Funcionamiento de las arquitecturas de base de datos En un capitulo anterior se indicaron las lineas bdsicas del funcionamiento de las arquitecturas de bases de datos Web. A continuaci6n se repiten dichos pasos para ayudarle a recordar: 1. Un usuario de navegador Web envia una petici6n HTTP solicitando una p6gina Web dada. Por ejemplo, el usuario podria solicitar todos 10s libros escritos por Michael Morgan que tenga Book-0-Rama, utilizando un formulario HTML. Los resultados de la b&quedas se almacenan en results.php. 2. El servidor Web recibe la petici6n de results.php, recupera el archivo y lo pasa a1 motor de PHP para su procesamiento.
3. El motor de PHP comienza a analizar la secuencia de comandos. Dentro de la secuencia de comandos hay un comando que establece la conexi6n a la base de datos y ejecuta una consulta (realiza la busqueda de libros). PHP abre una conexi6n a1 servidor MySQL y remite la consulta pertinente. 4. El servidor MySQL recibe la consulta de la base de datos y la procesa. A continuaci611, envia 10s resultados (una lista de libros) a1 motor de PHP.
-
-
5. El motor de PHP termina de ejecutar la secuencia de comandos, lo que suele implicar la aplicaci6n de formato a 10s resultados en HTML. Seguidamente, devuelve el c6digo HTML resultante a1 servidor Web. 6. El servidor Web devuelve el c6digo HTML a1 navegador donde el usuario puede ver la lista de 10s libros solicitados.
Ahora tenemos una base de datos MySQL, por lo que podemos escribir el c6digo PHP para realizar 10s pasos anteriores. Comenzaremos por el formulario de busqueda. Se trata de un sencillo formulario escrito en HTML. En el listado 10.1 se recoge su c6digo: Listado 10.1. search.html. Pagina de b h q u e d a de base de datos de Book-0-Rama Book-0-Rama Catalog Search
Desnrrollo Web con P H P y MySQL
El c6digo de este forrnulario resulta bastante claro. En la figura 10.1 se muestra el resultado.
I/ Book-0-Rama Catalog Search Choose Search Type:
IAu(hor_Zl Enler Search Term:..
I
!!El
Figura 10.1. El forrnulario de busqueda resulta bastante general por lo que se puede buscar un libro a partir de su titulo, autor o ISBN
La secuencia d e comandos que se invocarfi a1 pulsar el b o t h Search es results.php. En el listado 10.2 se incluye el c6digo completo. En este capitulo veremos qu6 realiza esta secuencia de comandos y su funcionamiento. Listado 10.2. result.php. Esta secuencia de cornandos recupera 10s resultados de nuestra base de datos MySQL y les aplica forrnato para su visualization
10. Acceso a la base de datos de MySQL desde la W e b con P H P
Book-0-Rama Search Results Book-0-Rama Search Results
echo 'You have not entered search details.Please g o back and try again. ' ; exit;
@ Sdb = mysql~pconnect('localhost', 'bookorama', 'bookorarnal23');
,if
( !
Sdb)
(
echo 'Error: Could not connect t o database. exit;
Please try again later.';
I
1 9 "
rnysql_select~db('books'); $query = "select * from books where ".$searchtype." like .$searchterm."%'";
$result
=
rnysql-query($query);
$nurn-results
=
mysql nbm r ~ w s ( $ r e s u l t ) ; -
-
echo 'Number of books found: '.Snum-results.' ';
{
$row echo echo echo echo echo echo echo echo echo
I ?>
rnysql-fetch-array($result); ''.($i+l).'. Title: ' ; htrnlspecialchars(stripslashes($row['title'])); ' Author: ' ; stripslashes ($row[ 'author'I ) ; ' ISBN: ' ; stripslashes($row['isbn'l); ' Price: ' ; stripslashes($row['price']); ' ';
=
D r w r r o l l o Wcb corl PHP y MySQL
k h m Edwon Vsr Favonlm Herramenlas Awda
IL
Book-0-Rama Search Results Number of books found: 1
1. 'l'ille: Java 2 lor Professional Develupe~s Author: Michael Mega ISBN: 0-672-31697-8 Price: 34.99
Figura 10.2. Los resultados de la busqueda de la base de datos sobre libros de Java se presentan en la pagina Web utilizando la secuencia de comandos results.php
En cualquier secuencia d e comandos utilizada para acceder a una base d e datos desde la Web, se siguen algunos pasos bcisicos:
1. Comprobar y filtrar 10s datos procedentes del usuario. 2. Configurar una conexi6n a la base d e datos pertinente. 3. Consultar la base d e datos.
-
4. Recuperar 10sresultados.
5. Presentar 10s resultados a1 usuario. Estos son 10s pasos seguidos en la secuencia d e comandos results.php y vamos a revisar cada uno de ellos por separado.
En primer lugar vamos a eliminar todos 10s espacios en blanco que pudiera haber introducido el usuario d e manera involuntaria a1 principio o a1 final del termino d e bGsqueda. Para ello, aplicamos la funci6n t r i m ( ) a $ s earchterm.
El siguiente paso consiste en verificar que el usuario ha introducido un termino d e btisqueda y un tip0 d e b&.queda. Tenga en cuenta que este paso se realiza tras eliminar 10s espacios en blanco a1 final del termino d e b6squeda. Si hubieramos ordenado
10. Acceso a la base de datos de MySQL desde la W e b con P H P
estas lineas en orden inverso, podria darse el caso de que el usuario hubiera introducido un tdrmino de busqueda formado por espacios en blanco y de esta forma no se generaria un mensaje de error. Por ello, se utiliza la instrucci6n trim ( ) : if
(!$searchtype
I
I
!$searchterm)
t echo 'You have not entered search details. exit;
Please go back and try again.';
I
Como observar6 hemos comprobado la variable $ sea rchtype aunque en este caso procede de una instrucci6n SELECT de HTML. Se estar6 preguntando por qud preocuparse de comprobar datos que tienen que introducirse. Es importante recordar que puede que exista m6s de una interfaz hasta la base de datos. Por ejemplo, Amazon incluye una gran cantidad de afiliados que utilizan su propia interfaz de busqueda. Ademis, resulta aconsejable filtrar 10s datos para evitar 10s problemas de seguridad que pueden surgir debido a usuarios procedentes de diferentes puntos de entrada. Ademis, cuando se van a utilizar datos introducidos por un usuario, es importante filtrarlos adecuadamente para detectar cualquier car6cter de control. En un capitulo anterior, hablamos de las funciones adds lashes ( ) y stripslashes ( ) . La funci6n adds lashes ( ) se utiliza a1 enviar 10s datos introducidos por el usuario a una base de datos como MySQL y stripslashes ( ) a1 devolver el resultado a1 usuario que ha utilizado caracteres de control. En este caso hemos utilizado addslashes ( ) en 10s tdrminos de busqueda: Ssearchterm
=
addslashes($searchterm);
Tambidn hemos utilizado sm i p s1as he s ( ) sobre 10s datos procedentes de la base de datos. Ninguno de 10s datos introducidos a mano en la base de datos tenia barras ni caracteres de control. La llamada a la funci6n stripslashes ( ) no tendr6 ningun efecto. A1 desarrollar una interfaz Web para la base de datos, es probable que necesitemos introducir nuevos libros y es posible que alguno de 10s detalles introducidos por 10s usuarios contenga estos caracteres. A1 introducirlos en la base de datos, llamaremos a la funci6n addslashes ( ) ,lo que significa que debemos llamar a la instrucci6n strips1 ashes ( ) a1 extraer 10s datos. Se trata de una costumbre que resulta bastante aconsejable adoptar. Estamos utilizando la funci6n html special chars ( ) para codificar caracteres que tengan significados especiales en HTML. Nuestros datos de prueba actuales no incluyen ningun simbolo ampersand (&), menor que (<), mayor que (>) ni comillas dobles ("), pero hay titulos de libros en 10s que podrian aparecer. Esta funci6n nos permite evitar errores futuros.
Desarrollo W e b con P H P y MySQL
Como configurar de una conexi6n Utilizaremos la siguiente linea en nuestra secuencia de comandos para establecer una conexi6n a1 servidor de MySQL: @
$db
=
mysql~pconnect('loca1host', 'bookorama',
'bookorarnal23');
Hemos utilizado la funci6n m y s q l p c o n n e c t ( ) para establecer una conexi6n a la base de datos. La sintaxis de esta funci6n es la siguiente: resource mysql -pconnecti [string host [:puertol [:irutasocketl string usuario [ , string contraseAa1 I] ) ;
[,
Por regla general, se le pasa el nombre del host en el que se ejecuta el servidor MySQL, el nombre de usuario utilizado para iniciar la sesi6n y la contrasefia de dicho usuario. Todos estos parfimetros son opcionales y si no se especifican la funci6n utilizarfi 10s predeterminados: el host local para host, el nombre de usuario con el que se procese PHP y una contrasefia en blanco. La funci6n devuelve un identificador de vinculo a la base de datos MySQL en caso de que el intento de conexi6n resulte satisfactorio (que deberia guardar para otras ocasiones) o f a l s e en caso contrario. Es conveniente comprobar el resultado ya que el resto del c6digo no funcionari sin una conexi6n vilida a la base de datos. Para ello, hemos utilizado el siguiente c6digo: if
I !$db)
t echo 'Errnr: Could not connect t o database. exit;
Please try again later.';
1
Una funci6n a1ternativ.a qua realiza la misma labor que my s q l -p c o n n e c t ( ) es m y s q l c o n n e c t ( ) . La diferencia esti en que la primera devuelve una conexi6n permaiente a la base de datos. Una conexi6n normal a la base de datos se cerrari cuando la secuencia de comandos termine su ejecuci6n o cuando se llame a la funci6n m y s q l - c l o s e ( ) . Las conexiones permanentes siguen abiertas cuando la secuencia de comandos termina la ejecuci6n y no se pueden cerrar utilizando la funci6n m y s q l - c l o s e ( ) . Es probable que se est6 preguntado para qu6 comprobar si existe una conexi6n permanente. La respuesta esti en que el establecimiento de una conexi6n a una base de datos implica una determinada carga y por lo tanto lleva cierto tiempo. A1 llamar a m y s q l p c o n n e c t ( ) , antes de intentar establecer la conexi6n a la base de datos, se comprieba automiticamente si existe una conexi6n permanente abierta. Si asi fuera, se utilizari dicha conexi6n en lugar de abrir una nueva, con el consiguiente ahorro de tiempo y carga del servidor. Tambikn conviene sefialar que las conexiones permanentes no resultan permanentes si se esti ejecutando PHP como un CGI. (Cada llamada a una secuencia de comandos de PHP inicia una nueva instancia de PHP y la cierra cuando la secuencia
10. Acceso a la base de datos de M y S Q L desde la W e b con PHP
de comandos termina la ejecuci6n. T a m b i h se cierran todas las conexiones permanentes.) Hay que tener en cuenta que el numero de conexiones simultiineas a MySQL es limitado y viene determinado por el pariimetro max c o n n e c t i o n s . El objetivo de este pariimetro y del par6metro MaxClients de Apache es indicarle a1 servidor que rechace las solicitudes de nueva conexi6n en lugar de permitir el uso de todos 10s recursos del equipo en momentos de mucho triifico o cuando se haya producido un error en el software. Los valores predeterminados de estos pariimetros se pueden modificar editando 10s archivos de configuraci6n. Para establecer el pariimetro M a x C l i e n t s de Apache, modifique el archivo h t t p d . conf de su sistema. Para establecer el pariimetro max -c o n n e c t i o n s de MySQL, edite el archivomy. c o n f . Si utiliza conexiones permanentes y priicticamente todas las piiginas del sitio necesitan acceder a la base de datos, es probable que abra una conexi6n permanente para cada proceso de Apache. Esta situaci6n puede dar lugar a un problema si se mantienen 10s valores predeterminados. De manera predeterminada, Apache permite 150 conexiones, per0 MySQL s610 permite 100. En fases de mucho triifico, el numero de conexiones puede resultar insuficiente. Es aconsejable ajustar estos pariimetros en funci6n del hardware de manera que cada proceso de servidor Web disponga de una conexi6n.
Seleccion de una base de datos Como recordark a1 utilizar MySQL desde un interfaz de linea de comandos, necesitamos indicarle qu6 base de datos tenemos pensado utilizar con la ayuda de un comando como el siguiente:
-
iuse
books;
Tambi6n necesitamos realizar esta tarea a1 establecer la conexion desde la Web. Desde PHP lo hacemos con una llamada a la funci6n mys q l -s e l e c t -db ( ) , como hemos en el siguiente caso:
La funci6n mys q l -s e 1e c t -db ( ) tiene la siguiente sintaxis: b o o 1 m y s q l -s e l e c t - d b i s t r i n g
basededatos,
[resource conexidn-basedtdatss]
1;
Este c6digo intentar6 utilizar la base de datos llamada basededatos. Tambien se puede incluir el vinculo de base de datos sobre el que nos gustaria realizar esta operaci6n (en este caso Sdb), per0 si no se especifica, se utilizarii el ultimo vinculo abierto. Si no dispone de un vinculo abierto, se abririi el predeterminado como si hubiera llamada a mysql -c o n n e c t ( ) .
Desnrrollo Web con P H P y M!jSQL
C6mo consulfar la base d e datos Para realizar una consulta, podemos utilizar la funci6n mysql -q u e r y ( j . Sin embargo, antes de realizar esta tarea, conviene configurar la consulta que se desea ejecutar:
En este caso, buscamos el valor introducido por el usuario ( $ s e a r c h t e r m ) en el campo especificado por el usuario ( S s e a r c h t y p e ) . Como observar5, hemos utilizado el operador l i k e en lugar del signo igual para establecer la busqueda (por regla general, conviene ser tolerante en las busquedas sobre bases de datos).
Tenga en cuenta que no es necesario incluir un punto y coma al final de una consulta enviada a MySQL, a diferencia de las consultas realizadas a traves del monitor de MySQL.
Ahora podemos ejecutar la consulta: S r e s u l t = roysql .-q u e r y ( S q l ~ e r y;)
La funci6n mysql -q u e r y
()
tiene la siguiente sintaxis:
Se le pasa la consulta que sedesea ejecutar y, opcionalmente, el vinculo a la base d e datos (nuevamente, $db).Si no se especifica, la funcion utilizar6 el ultimo vinculo abierto. Si no existiese ninguno, la funcion abriria el predeterminado como si hubiera llamado a mys q l c o n n e c t ( ) . Esta funcibn devuelve i n identificador de resultados (que permite recuperar 10s resultados d e la consulta) en caso d e exit0 y f a l s e en caso d e contrario. Deberia almacenarlo (como hemos hecho en este caso en $ r e s u l t ) para poder hacer algo util.
Rccuperacih de resultados
d e consulta
Existe un conjunto de funciones para dividir 10s resultados del identificador de resultados de varias formas. El identificador de resultados es la clave para acceder a las filas devueltas por la consulta. En nuestro ejemplo, hemos utilizado dos funciones d e este tipo: mysql -numrows ( ) y m y s q l - f e t c h - a r r a y 0 .
10. Acceso a la base de datos de MySQL desde la W e b con P H P
La funci6n m y s q l n u m r o w s ( ) indica el nlimero de filas devueltas por la consulta. Deberia pas6rseio a1 identificador de resultados, de la siguiente forma:
Resulta litil saber hacerlo. Si tenemos previsto procesar o mostrar 10s resultados, sabremos cufintos hay y podemos procesarlos en un bucle: for ($i=O; $i <$nun -results; $it+)
I / / procese 10s resultados
En cada iteraci6n de este bucle, llamamos a m y s q l -f e t c h-a r r a y ( ) . El bucle no se ejecutarfi si no se devuelve ninguna fila. Esta funci6n toma cada fila del conjunto de resultados y devuelve la fila como una matriz asociativa, con cada clave en forma de nombre de atributo y cada valor con su valor correspondiente en la matriz:
Dada la matriz asociativa $ r o w , podemos recorrer cada campo y mostrarlos adecuadamente, por ejemplo: echo ' ISBN: ' ; echo stripslashes($row['isbn'l
);
Como se indic6 previamente, hemos llamado a s t r i p s 1a s h e s ( ) para limpiar el valor antes de mostrarlo. Existe una serie de variaciones a la hora de obtener 10s resultados desde un identificador de resultados. En lugar de utilizar una matriz asociativa, podemos recuperar 10s resultados en unamatriz enumerada con m y s q l -f e t c h-r o w ( ) , de la siguiente forma: $row
=
mysql - fetch-row($result);
Los valores de atributo se enumerarfin en cada uno de 10s valores de matriz $ r o w [ O ] , $ r o w [ l ] etc.
Tambi6n puede acceder a cada uno de 10s atributos mediante $ r o w - > t i t l e , $ r o w - > a u t h o r , etc.
Cada uno de estas opciones recupera una fila por vez. Para ello, debe especificar el nlimero de fila (desde cero a1 numero r o w s [ m s 1 1)asi como el nombre del campo. Por ejemplo:
Puede especificar el nombre del campo como una cadena (en forma de "titulo" o "1ibros.titulo")o en forma de nlimero (como e n m y s q l f e t c h-r o w ( ) ). No deberia usar m y s q l - r e s u l t ( ) con otras funciones de recupe~aci6n.
Desarrollo W e b con PHP y MySQL
Las funciones de recuperaci6n orientadas a filas resultan mucho m6s eficientes que la funci6n m y s q l -f e t c h -r o w ( ) ,por lo que en general deberia utilizar una de aqu6llas.
Desconexion de una base de datos Puede utilizar rnysql-close(conexi6n basededatos);
para cerrar una conexi6n debase de datos no permanente. Esta opci6n no resulta estrictamente necesaria porque se cerrar6n de todos modos cuando una secuencia de comandos finalice su ejecuci6n.
C6mo colocar nueva information en la base de datos La inserci6n de nuevos elementos en la base de datos resulta bastante similar a la obtenci6n de elementos de la base de datos. Los pasos son pr6cticamente iguales: se establece una conexibn, se envia una consulta y se comprueban 10s resultados. En este caso, la consulta enviada serd I N S E R T en lugar de SELECT. Aunque el proceso es similar, a veces resulta util examinar un ejemplo. En la figura 10.3, se ilustra un formulario HMTL sencillo para introducir nuevos libros dentro de la base de datos. El c6digo HMTL de esta p a i n a se incluye en el listado 10.3. Listado 10.3. newbook.htrnl. Codigo HTML de la pagina de entrada de libros Book-0-Kama </head><br />
<br />
-<br />
<br />
New<br />
<br />
Book<br />
<br />
Entry
Book-0-Rama - New Book Entry
l o . Acceso n In bnse d e datos de iMySQL desde la W e b corl P H P
k c h r w Edlodn Vsr Farams Herrm-ri3
Lhremdn
Id hyp i ~ o r r 1 b a n ~ ~ -. . l ' k ~p
Apda
*a I F p
Book-0-Rama - New Book
81
J?
I'
-
ISBN Author Isfeve L m T~tle l~amba~nleaslled
$149
Pr~ce
99
Figura 10.3. El personal de Book-0-Rama puede utilizar esta interfaz para la introduccion de nuevos libros en la base de datos
Los resultados d e este formulario se pasan a i n s e r t b o o k . p h p , una secuencia de comandos clue toma 10s detalles, realiza algunas opeGciones d e validaci6n e intenta escribir 10s datos dentro d e la base d e datos. El c6digo correspondiente a esta secuencia d e comandos se incluye en el listado 10.4. Listado 10.4. insert-book.php. Esta secuencia de comandos escribe nuevos libros en la base de datos
k l k ~ E i ~ n h n Ver Fawnlor Hsrrmoenlas Apda
~ir-n
1
1%
~ ~ ~ ~ r ~ h c l - m r j c b c t ~ bz+rrmo ~ l ' n ; . +
Book-0-Rama Book Entry Results
-1
2
I,
-
I book inserted into database
Figura 10.4. La secuencia de comandos se completa satisfactoriamente e indica que el libro se ha agregado a la base de datos
En la figura 10.4 se muestra el resultado cuando se inserta un libro satisfactoriamente. Si examina el codigo de i n s e r t book php, verfi que en gran parte resulta similar a la secuencia d e comandos queescribimos para recuperar datos d e la base de datos. Hemos comprobado que todos 10s campos del formulario se han rellenado y que se les ha aplicado formato correctamente para su inserci6n en la base d e datos conaddslashes ( ) :
.
Como el precio se ha almacenado en la base d e datos como una variable d e tip0 flotante, no queremos colocar barras en su interior. Para filtrar todos 10s caracteres extraiios que se puedan introducir en este campo numbrico, se puede llamar a la funci6n d o u b l e v a l ( ) , comentada en un capitulo anterior. Tambien se encargarfi d e filtrar 10s simbolos de moneda que pueda haber introducido el usuario en el formulario. Hemos vuelto a establecer la conexion a la base d e datos por medio de mysql p c o n n e c t ( ) ,y hemos configurado una consulta para enviarla a la base de datos. En este caso, la consulta es una instruccion I N S E R T de SQL: $query = "insert into books values ('".$isbn."', '".$author."', $result = rnysql-queryisquery);
'".$title."',
'".$price."')";
Gsta se ejecuta sobre la base d e datos d e la forma habitual llamando a mysql-query ( ) . Una diferencia significativa entre utilizar I N S E R T y SELECT estB en el uso de
-
mysql-affected-rows(): echo mysql-affected-rows()."
* book inserted into database.";
En la secuencia de comandos anterior, utilizamos mysql num rows ( ) para escribir consultas determinar cuBntas filas devolvia una instruccion SELECT. que cambien la base de datos como INSERT, DELETE y UPDATE, deberia utilizar en su lugarmysql a f f e c t e d rows 0 . Con esto, quedan vistos l& elementos bfisicos del uso de bases de datos MySQL desde PHP. A continuation, examinaremos brevemente algunas otras funciones titiles de las que no hemos hablado todavia.
A1
Otras funciones dtiles P H P y MySQL Existen algunas otras funciones de PHP y MySQL utiles, que comentaremos brevemente.
Desarrollo Web con PHP y M y S Q L
Li beracion de recursos Si tiene problemas de memoria a1 ejecutar una secuencia de comandos, puede utilizar my s q l -f r e e-r e s u l t ( ) , cuya sintaxis es la siguiente: boo1 rnysql-free result(resnurce r e s u l t a d o ) ; --
Se llama con un identificador de resultados, como el siguiente:
Este c6digo libera la memoria utilizada para almacenar el resultado. Obviamente no se invoca hasta terminar de trabajar con un conjunto de resultados.
Creaci6n y elirninacion de bases de datos Para crear una nueva base de datos MySQL desde una secuencia de comandos de PHP, puede utilizar m y s q l c r e a t e d b ( ) y para eliminar una base de datos MySQL existente, puede utilizar m y s q l d r o p d b ( ) . Estas funciones constan de las siguiekes sintaxis: bool rnysql-create-dbistring b a s e d e d a t o s , [resource c ~ n e x i h n ~ b a s e d e d a t o s )]; bool rnysql_droppdb (string basededa tos, [resource c o n e x i h n - b a s e d e d a t o s ] ) ;
Ambas funciones toman un nombre de base de datos y una conexi6n opcional. Si no se suministra ninguna conexi6n, se abrir6 la ultima. Intentaran crear o eliminar la base de datos cuyo nombre se haya indicado. Ambas funciones devuelven t r u e si el resultado es satisfactorio y f a 1 s e en caso contrario.
-
-
Otras interfaces de base de datos y PHP PHP admite bibliotecas para establecer conexiones a una gran cantidad debases de datos, incluidas Oracle, Microsoft SQL Server, mSQL y PostgreSQL. Por regla general, 10s principios para establecer la conexi6n y consultar cualquiera de las bases de datos son pricticamente 10s mismos. Varian 10s nombres de las funciones individuales y las distintas bases de datos tienen funcionalidades ligeramente diferentes, per0 si puede establecer una conexi6n a MySQL, no le costar6 adaptar esos conocimientos a cualquier situaci6n. Si desea utilizar una base de datos que no tenga una biblioteca especifica disponible en PHP, puede utilizar las funciones ODBC genericas. ODBC equivale a Conectividad de base de datos abierta y es un esthndar para las conexiones a bases de datos. Su funcionalidad es la m6s restrictiva de cualquier conjunto, por razones bastante obvias. Si se necesita una compatibilidad completa, no se pueden explotar funciones especiales.
10. Acceso a la base de datos de MySQL desde la W e b con PHP
Ademhs de las bibliotecas incluidas en PHP, tambidn esthn disponibles clases de abstracci6n debase de datos como Metabase o PEAR::DB, que permiten utilizar 10s mismos nombres de funci6n para cada tip0 de base de datos.
so de una interfaz de base de datos generica: PEAR DB Vamos a examinar un breve ejemplo del uso de la capa de abstracci6n PEAR DB. Se trata de uno de 10s componentes fundamentales de PEAR y probablemente el mhs utilizado de todos. Si tiene instalado PEAR, ya deberia tener el componente DB. De lo contrario, consulte la secci6n correspondiente del apdndice A. Para permitirle comparar, vamos a ver c6mo hubidramos escrito la secuencia de comandos de resultados de busqueda utilizando DB. Listado 10.5. results-generic.php. Recupera resultados de bllsqueda desde la base de datos MySQL y les aplica formato para su visualizacion Book-0-Rarna Search Results Book-0-Rarna Search Results ] ;
if
(
!$searchtype I I
!$searchterm)
I echo 'You have not entered search details.Please go back and try again.'; exit; 1
/ / configuracihn para utilizar PEAR DB require('DB.php1); $user = 'bookorarna'; $pass = 'bookorarnal23'; $host = 'localhost'; $db-name = 'books'; / / configure la cadena d e conexi6n universal o DSN
Desarrollo W e b con PHP y MySQL
/ / establezca una conexidn a la base d e datos Sdb = DB::connecr($dsn, true); / / compruebe s i funciona la conexitn if (DB::isError($db) )
I echo Sdb->getMessage(); exit; I
t
e
/ / realice ?a consulta $query = "select * from books where ".$searchtype." like rr . Ssearchterm. " % ' " ;
$result = Sdb->query($query); / / compruebe que el resultado es correct0 if (DB::isError($result))
t echo $db->getMessage(); exit;
I / / obtenga el nhrnero de filas devuelto Snurn-results = $result->numRows( 1 ; / / rnuestre cada fila devuelta for ($i=O; $i <$nurn-results; $it+)
I $row echo echo echo echo echo echo echo echo echo
$result->fetchRow(DB-FETCHMODEEASSOC); ''.($i+l).'. Title: ' ; htrnlspecialchars(stripslashes($row['title'])); ' Author: ' ; stripslashes(Srow['author']); ' ISBN: ' ; stripslashes ($rowrlisbn' ] ) ; '
=
' ';
/ / desconecte d e la base d e datos $db->disconnect ( ) ; ?>
Vamos a examinar 10s elementos nuevos de esta secuencia de comandos. Para establecer la conexion utilizamos la linea $db
=
DB: :connect (Sdsn, true) ;
Esta funci6n acepta una cadena de conexi6n universal con todos 10s parametros necesarios parar establecer la conexi6n a la base de datos.
10. Acceso a la base de datos de MySQL desde la W e b con PHP
Puede apreciarlo si examina el formato de la cadena de conexi6n:
El segundo partimetro de c o n n e c t ( ) determina si la conexi6n serti permanente o no. El valor t r u e la convertirti en permanente. Tras ello, comprobamos si la conexi6n fa116 con ayuda del metodo i s E r r o r ( ) y, en caso afirmativo, devolvemos un mensaje de error y salimos:
echo $db->getMessage(); exit;
I
Asumiendo que todo haya salido bien, establecemos una consulta y la ejecutamos de la siguiente forma:
Podemos comprobar el n6mero de filas devueltas:
Recuperamos cada fila de la siguiente forma:
El metodo generic0 fe t c h R o w ( ) permite recuperar una fila con muchos formatos diferentes. El partimetro DB FETCHMODE A S S O C le indica que queremos recuperar la fila en una matriz asociatka. Tras mostrar las filas devueltas, terminamos cerrando la conexi6n a la base de datos:
Como puede apreciar, este ejemplo generic0 resulta muy similar a la primera secuencia de comandos. Las ventajas de usar DB son que s610 necesitamos recordar un conjunto de funciones de base de datos y que el c6digo requerir6 minimos cambios si decidimos modificar el software de nuestra base de datos. Como este libro trata de MySQL, utilizaremos las bibliotecas nativas de MySQL para obtener una mayor velocidad y flexibilidad, per0 si lo desea puede utilizar el paquete DB en sus proyectos dado lo extremadamente titi1 que resulta acudir a el en determinadas ocasiones.
Lecturas adicionales Si desea obtener m6s informaci6n sobre c6mo combinar MySQL y PHP, puede leer las secciones pertinentes de manuales sobre PHP y MySQL.
Desarrollo W e b con PHP y MySQL
Si desea obtener mas informaci6n sobre ODBC, visite http://www.webopedia.com/TERM/O/ODBC.html
Metabase esta disponible en http://phpclasses.upperdesign.com/browse.html/package/2O
En el siguiente capitulo, profundizaremos en el estudio de la administracih de MySQL y veremos formas de optimizar las bases de datos.
En este capitulo, vamos a examinar algunos aspectos avanzados de MySQL como 10s privilegios, la seguridad y la optimizaci6n. En concreto abordaremos 10s siguientes temas: Andlisis detallado del sistema de privilegios Protecci6n de una base de datos MySQL
-
*
C6mo obtener mds informaci6n sobre la base de datos Agilizaci6n de 10s procesos por medio de indices Sugerencias de optimizaci6n Tipos diferentes de tablas Copias de seguridad y recuperaci6n
Andlisis detallado del sistema de privilegios En un capitulo anterior vimos c6mo configurar usuarios y concederles privilegios. Para ello, utilizamos el comando GRANT. Si va a administrar una base de datos MySQL, debe entender la funci6n de este comando y su funcionamiento. El uso de la instrucci6n GRANT afecta a las tablas de una base de datos especial llamada mysql. La informaci6n sobre privilegios se almacena en cinco tablas de
11. MySQL Avanzado
esta base de datos. Por lo tanto, a1 conceder privilegios sobre bases de datos, debe tener cuidado a1 otorgar permisos de acceso a la base de datos mys q l . El comando GRANT s610 esta disponible a partir de la versidn 3.22.11 de MySQL. Si desea examinar 10s contenidos de la base de datos mysql, registrese como administrador y escriba use
mysql;
Tras hacerlo, podrA ver las tablas de la base de datos con la instrucci6n show
tables;
como de costumbre. Los resultados presentaran un aspect0 semejante a1 siguiente:
I I I 1 I I
columns priv db func host tables-priv user -
I I
I I I
I
+-----------------+
Cada una de estas tablas, a excepci6n de la tabla func, almacenan informaci6n sobre privilegios. (La tabla f u n c almacena funciones definidas por el usuario.) Tambien se conocen como tablas de permisos. Las funciones especificas de estas tablas varian per0 todas ellas tiene un mismo objetivo general: determinar lo que 10s usuarios pueden y no pueden hacer. Estas tablas contienen dos tipos de campos: 10s campos de Ambito, que-ideaifican a1 usuario, a1 host y a parte de una base de datos; y 10s campos de privilegio, que identifican las acciones que puede realizar el usuario en dicho Ambito. La tabla u s e r se utiliza para decidir si un usuario puede conectarse a1 servidor MySQL y si dispone de privilegios administrativos. Las tablas db y h o s t determinan a qud bases de datos puede acceder el usuario. La tabla t a b l e s p r i v determina qud tablas de una base de datos puede utilizar un usuario y la tabla columns -p r i v establece a qud columnas de la tabla dispone de acceso.
La tabla
de usuario
Esta tabla contiene 10s detalles de 10s privilegios globales de usuario. Determina si un usuario puede conectarse a1 servidor MySQL y si dispone de privilegios globales, es decir, de privilegios que se aplican a toda las bases de datos del sistema. Para ver la estructura de esta tabla, puede utilizar la instrucci6n des c r i b e u s e r ; . En la tabla 11 .I se recoge el esquema de la tabla us e r .
Desarrollo Web COY/ P H P y M y S Q L
Tabla 11.1. Esquema de la tabla user de la base de datos mysql -
Campo
Tipo
Host
char(60)
User
char(l6)
Password
char(l6)
Reload-priv
enum('N1,'Y')
S hutdown-priv
enum('N','Y1)
Cada fila d e esta tabla se corresponde con un conjunto de privilegios para un usuario procedente de un host y registrado con la contraseiia P a s sword. Se trata d e 10s campos de timbito d e esta tabla, ya que describen el dmbito del resto de los campos, llamados campos d e privilegio. Los privilegios enumerados en esta tabla (y en las siguientes) se corresponden con 10s concedidos por medio de la instrucci6n GRANT en un capitulo anterior. Por ejemplo, select p r i v se corresyonde con el privilegio necesario para ejecutar un comando s ELECT Si un usuario tiene un privilegio concreto, el valor d e dicha columna ser6 Y. Por el contrario, si a un usuario no se le ha concedido dicho privilegio, el valor serfi N. Los privilegios listados en la tabla d e usuarios son globales, lo que quiere decir que se aplican a todas las bases de datos del sistema (incluida la base de datosmysql). Los administradores tendr6n varios valores Y per0 la mayoria de 10s usuarios deberian tener todos N. Los usuarios normales deberian disponer de derechos para acceder a determinadas bases d e dates, per0 no a todas las tablas.
Las tahlas dh y host La mayor parte d e 10s privilegios d e 10s usuarios se almacenan en las tablas d b y host.
La tabla db determina qu6 usuarios pueden acceder, a qu6 bases de datos y desde que hosts. Los privilegios listados en esta tabla se aplican a cualquier base d e datos designada en una fila dada. La tabla h o s t cornplementa a la tabla db. Si un usuario va a conectarse a una base de datos desde varios hosts, no se enumerari ningun host para dicho usuario en la tabla. En su lugar, se incluir6 un conjunto d e entradas en la tabla h o s t para especificar 10s privilegios correspondientes a cada combinaci6n de usuario y host. En las tablas 11.2 y 11.3se recogen 10s esquemas d e estas dos tablas, respectivamente. Tabla 11.2. Esquema de la tabla db de la base de datos mysql -
-.7
-
-
--
-
.-
.-
-
.
.. ..
-
- .-
Tipo Host Db User Select-priv Insert-priv Update-priv Delete-priv Create-priv Drop-priv Grant-priv
Tabla 11.3. Esquema de la tabla host de la base de datos mysql
Campo Host Db
Tipo
Desnrrollo Web con PUP y MySQL -
Campo
Tipo
Select-priv
enum('N1,'Y')
Insert-priv
enum('N','Y')
Update-priv
enum('Nt,'Y')
Delete-pr~v
enum('Nt,'Y')
Create-priv
enum('N','Y1)
Drop-priv
enum('N','Yt)
Grant-priv
enum('N','Y1)
References-priv
enum('N','Y1)
Index-priv
enum('N','Y1)
Alter-priv
enum ('N','Y')
-
Estas dos tablas se u t i l i z a n para almacenar privilegios d e n i v e l d e tabla y d e n i v e l de columna, respectivamente. Funcionan como l a tabla db, con la diferencia de que suministran privilegios para las tablas d e u n a base d e datos dada y p a r a las columnas d e u n a tabla concreta, respectivamente. Estas tablas constan d e u n a estructura ligeramente diferente a las tablas u s e r , db y h o s t . E n l a tabla 11.4 y 11.5 se incluyen 10s esquemas de las tablas t a b l e s -p r i v y columns-priv, respectivamente.
-
Tabla 11.4. ~ s ~ u e h deala tabla tables-priv de la base de datos mysql
Host Db User Table-name Grantor
char(77)
Timestamp
timestamp(l4)
Table-priv
set('Selectl, 'Insert', 'Update', 'Delete', 'Create', 'Drop', 'Grant', 'References', 'Index', 'Alter')
Column-priv
set ('Select', 'Insert', 'Update', 'References')
11. MySQL Avanzado
Tabla 11.5. Esquema de la tabla columns-priv de la base de datos mysql
Campo Host
char(60)
Db
char(64)
User
char(l6)
Table-name
char(64)
Column-name
char(64)
Timestamp
timestamp(l4)
Column-priv
set('Selectl, 'Insert', 'Update', 'References')
La columna Grantor de la tabla tables p r i v almacena el usuario que concedi6 el privilegio a este usuario. La columna Times tarnp d e ambas tablas almacena la fecha y la hora en la que se concedi6 el privilegio.
Control de acceso: icomo utiliza MvSQL las tablas cle concesi6n de privilegios? MySQL utiliza las tablas grant para determinar qu6 puede hacer un usuario en un proceso d e dos fases: 1. Verificaci6n de conexi6n. En esta fase, MySQL comprueba si disponemos de permiso para establecer una conexi6n en funci6n de la informaci6n de la tabla d e usuario, como se indic6 anteriormente. Para realizar esta operaci6n, se utiliza el nombre d e usuario, el nombre d e host y la contraseiia. Si se deja en blanco un nombre d e usuario, equivaldrfi a todos 10s usuarios. Los nombres d e host se pueden especificar mediante el uso d e u n carficter comodin ( G ) . Se puede utilizar en forma de campo completo (es decir, que '1; equivalga a todos 10s hosts) o como parte d e un nombre d e host, por ejemplo, B tangledweb. corn.au, que equivale a todos 10s hosts que terminen en tangledweb. corn.au . Si se deja en blanco el campo de contraseiia, no s e r i necesario utilizar una contraseiia. Sin embargo, no conviene utilizar usuarios en blanco, comodines en hosts ni usuarios sin contrasefias por cuestiones d e seguridad.
.
.
2. Verificaci6n de la solicitud. Cada vez que se introduce una solicitud, tras establecer una conexi6n, MySQL comprueba si disponemos del nivel necesario de privilegios para realizar dicha petici6n. En primer lugar, el sistema comprueba 10s privilegios globales (en la tabla u s e r ) y si no resultan suficientes, comprueba las tablas db y host. Si no se dispone d e 10s privilegios
Desarrollo Web con P H P y MySQL
necesarios en dicho nivel, MySQL examinard la tabla t a b l e s -p r i v y, si no son bastan, examinard la tabla colums-p r i v .
Actualization de privilegios: icuando surten efecto 10s cambios? El servidor MySQL lee automdticamente las tablas de privilegios a1 iniciarse y a1 aplicar las instrucciones GRANT y REVOKE. Sin embargo, ahora que ya sabemos d6nde y c6mo se almacenan dichos privilegios, podemos alterarlos manualmente. A1 actualizarlos manualmente, el servidor MySQL no notarg que han cambiado. Es necesario indicarle a1 servidor que se ha producido un cambio y existen tres formas de hacerlo. Puede escribir FLUSH P R I V I L E G E S ;
en la linea de comandos de MySQL (necesitard haber iniciado la sesi6n como administrador). gsta es la forma mds habitual de actualizar 10s privilegios. Tambikn puede ejecutar rnysqladrnin f l u s h - p r i v i l e g e s
rnysqladrnin
reload
desde el sistema operativo. Tras ello, se comprobardn 10s privilegios globales cuando un usuario se conecte, 10s privilegios de base de datos en la siguiente instrucci6n de uso y 10s privilegios de tabla y columna en la 5igui;nte petici6n de usuario.
Como proteger la bases de datos MySQL La seguridad es importante, en especial a1 establecer la conexi6n entre la base de datos MySQL y el sitio Web. En esta seccibn, vamos a repasar las precauciones que se deberian adoptar para proteger una base de datos.
MySQL desde el punto de vista del sistema operativo Noes aconsejable ejecutar el servidor MySQL (mysqld) como usuario raiz si estd utilizando un sistema operativo de tip0 UNIX ya que permitiria a un usuario de MySQL con un conjunto completo de privilegios leery escribir archivos en cualquier
11. MySQL Avanzado
parte del sistema operativo. Es importante tener en cuenta esta circunstancia ya que se suele pasar ficilmente por alto y ya ha sido utilizada para piratear sitios Web basados en Apache. (Afortunadamente, se trataba de piratas buenos y lo unico que hicieron fue reforzar la seguridad). Es aconsejable configurar un usuario de MySQL de manera especifica para ejecutar mysqld. AdemBs puede configurar 10s directorios (donde se almacenan 10s datos fisicamente) para limitar el acceso a dicho usuario. En muchas instalaciones, el servidor se configura para ejecutarse como userid mysql, en el grupo mysql. Tambien deberia colocar su servidor MySQL tras un cortafuegos. De esta forma podrB evitar conexiones procedentes de equipos no autorizados. Compruebe si puede conectarse desde el exterior a su servidor a traves del puerto numero 3306; se trata del puerto predeterminado en el que se ejecuta MySQL y deberia estar cerrado en el cortafuegos.
Contrasenas Asegurese de que todos 10s usuarios tienen contrasefias (en especial el usuario raiz) y que estBn bien elegidas y se cambian peribdicamente, como en el caso de las contrasefias de sistemas operativos. Recuerde que no conviene utilizar contrasefias que contengan palabras o estBn formadas por palabras de un diccionario. Lo mejor es utilizar combinaciones de letras y numeros. Si va a almacenar contrasefias en archivos de secuencias de comandos, asegurese de que s610 el usuario cuya contrasefia este almacenada puede verlos. Los dos lugares principales en 10s puede suceder son: 1. En la secuencia de comandos m y s q l . s e r v e r , es probable que necesite utilizar la contrasefia raiz de UNIX. Si asi fuera, asegurese de que s610 el usuario raiz puede leer esta secuencia de comandos. 2. En las secuencias decomandos de PHP que se utilizan para establecer una conexi6n a la base de datos, necesitar6 almacenar la contrasefia para dicho usuario. Esta operaci6n se puede realizar de forma segura colocando el nombre de usuario y la contrasefia en un archivo llamado, por ejemplo, d b c o n n e c t . php, que puede situar donde lo necesite. Esta secuencia de comandos se puede almacenar fuera de Brbol de documentos Web y configurarla para que s610 resulte accesible a1 usuario adecuado. Recuerde que si coloca estos detalles en un archivo i n c o en cualquier otra extensi6n de archivo en el Brbol Web, tend14 que asegurese de comprobar que el servidor Web sabe que dichos archivos deben interpretarse como PHP, para que 10s detalles no puedan verse en un navegador Web. No almacene contrasefias en forma de texto dentro de la base de datos. Las contrasefias de MySQL no se almacenan de esa forma, per0 resulta habitual en aplicaciones Web en las que se desea almacenar 10s nombres de usuario y contrasefias de 10s miembros del sitio. Puede cifrar las contrasefias utilizando las funciones PASSWORD ( ) o MD5 de MySQL. Recuerde que si inserta una contrasefia con el comando INSERT utilizando una de estas funciones, a1
.
Desarrollo W e b con PHP y MySQL
ejecutar una selecci6n (para registrar un usuario), tendrd que utilizar la misma funci6n de nuevo para comprobar la contraseiia utilizada por el usuario. En la parte dedicada a la implementaci6n de proyectos utilizaremos esta funcionalidad.
Privilegios de usuario Asegurese de tener claro el sistema de privilegios de MySQL y las consecuencias de la concesi6n de 10s distintos privilegios. No conceda mas privilegios a un usuario de 10s necesarios. Para verificarlos, examine las tablas de concesidn de privilegios. En concreto, no conceda 10s privilegios PROCESS, FILE, SHUTDOWN y RELOAD a ningun usuario que no sea un administrador a menos que resulte completamente necesario. El privilegio PROCESS se puede utilizar para ver qu6 estdn haciendo o escribiendo otros usuarios, incluidas sus contrasefias. El privilegio F I L E se puede utilizar para leer y escribir archivos desde y hasta el sistema operativo (incluyendo, por ejemplo, el archivo / et c/pas sword en un sistema UNIX). El privilegio GRANT deberia concederse con precauci6n ya que permite a 10s usuarios compartir sus privilegios con otros usuarios. Asegurese de que a1 configurar 10s usuarios, s61o les concede acceso desde 10s hosts que utilizan para conectarse. El usuario j ane @localhos t es correct0 per0 el usuario j ane es bastante comun y podria registrarse desde cualquier lugar (y puede que no se trate de la persona que esta pensando). Evite utilizar comodines en 10s nombres de host por razones similares. Puede'aumentar mds la seguridad utilizando direcciones IP en lugar de nombres de dominio en la tabla host.Esta medida evita errores o intrusos en su DNS. Para ello, inicie el demonio de MySQL con la opcidn -s kip-name-resolve,que exige que todos 10s valores de columna de host Sean una direcci6n IP o un host local. Como alternativa puede iniciar mysqld con la opci6n -secure. Esta opci6n comprueba las IP resueltas para determinar si se corresponden con 10s nombres de host suministrados. (Esta opcion s61o estd activada de manera predeterminada desde la versi6n 3.22 en adelante). No deberia permitir que 10s usuarios no administrativos dispongan de acceso a1 programa mysqladmin en el servidor Web. Este programa se ejecuta desde la linea de comandos por lo que su acceso se convierte en una aspect0 relacionado con 10s privilegios del sistema operativo.
Aspectos relacionados con la Web A1 conectar la base de datos MySQL a la Web, surgen una serie de temas de seguridad especiales. Conviene, en primer lugar, configurar un usuario especial para las operaciones relacionadas con las conexiones Web. Puede concederle 10s privilegios minimos necesario excluyendo, DROP, ALTER o CREATE. Puede concederle el privilegio SELECT so10 sobre las tablas de catdlogos y el privilegio I N S E R T sobre las tablas de pedidos.
Se trata de un nuevo ejemplo de la aplicaci6n del principio de concesicin de la menor cantidad posible de privilegios. _
_
C
I
C
.
_
_
-
-
- .
Advertencia En el ultimo capitulo hablamos del uso de las funciones a d d s l a s h e s ( ) y s t r i p s l a s h e s ( ) para eliminar caracteres problematicos en cadenas. Es importante no olvidarse de aplicar estas funciones y de limpiar 10s datos antes de enviar nada a MySQL. Como recordara, utilizamos la funciondoubleval ( ) para comprobarque losdatos numericos eran numericos. Resulta habitual pasar por alto esta comprobacion. Deberia comprobar siempre todos 10s datos procedentes de un usuario. Aunque el formulario HTML est6 formado de cuadros de selecci6n y botones de option, alguien podria haber modificado el URL para piratear la secuencia de comandos. Tambien conviene comprobar el tamafio d e 10s datos entrantes. Si 10s usuarios escriben contrasefias o datos confidenciales para su almacenamiento en la base de datos, recuerde que se transmitirhn como texto sin procesar desde el navegador a1 servidor a menos que utilice SSL (del ingl6s Secure Sockets Layer, Nivel d e sockets seguro). En una secci6n posterior se ampliar5 este tema.
Por el momento, hemos utilisado SHOW y DESCRIBE para determinar las tablas que incluye la base d e datos y las columnas de las tablas. A continuaci6n, vamos a analizar otras formas d e utilizar estas instrucciones asi como la instrucci6n EXPLAIN para obtener m5s informaci6n sobre c6mo se realiza una operaci6n d e selection.
C6mo obtener inforrnacibn con SHOW Antes hemos utilizado
para obtener una lista de tablas d e la base de datos La instruccion
muestra una lista d e bases d e datos disponibles.
D e s n r r o l l o W e b coil PHP y MySQL
A continuaci6n puede utilizar la instrucci6n SHOW TABLES para ver la lista de tablas d e una d e esas bases d e datos:
Si se aplica la instrucci6n SHOW TABLES sin especificar una base d e datos, se utilizari la base d e datos actual d e manera predeterminada. Si sabe cuiles son las tablas, puede obtener una lista d e las columnas:
Si no activa el parimetro correspondiente a la base d e datos, la instrucci6n SHOb7 COLUMNS utilizari la base d e datos actual. Tambien puede utilizar la notacicin tabla.columna:
Existe una variaci6n d e la instrucci6n SHOb7 para ver 10s privilegios que tiene un usuario. Por ejemplo, si ejecutamos la siguiente instrucci6n, obtendremos el resultad o ilustrado en la figura 11.1.
Las instrucciones GRANT que se muestran no son necesariamente las que se ejecutaron para conceder privilegios a un usuario dado, sin0 mAs bien instrucciones d e resumen equivalentes que generan el nivel actual d e privilegios del usuario. *.......................................................................................... ; Grants f o r bookorana8%
+.. .......................................................................................... :GRAMT U S A G E O H ' : TO ' b o o k o r a m a ' @ ' % ' I D E N T I F I E D B Y PASSia;DRD ' 6 a 8 7 b 6 8 1 0 c b 0 7 3 d e ' i G R A H T S E L E C T , I R S E R T , U P D A T E , D E L E T E , C R E A T E , D R O P , I N D E X , A L T E R OH b o o k s . ' TO ' b o o k o r a r a ' P ' % '
+ +
+
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Figura 11.1: El rkultado de la instruccion SHOW GRANTS -
Nota La instruccion SHOW GRANTS se agrego en la version 3.23.4 de MySQL. Si su version es inferior no funcionara. Existen muchas variantes d e la instrucci6n SHOW. En la tabla 11.6 se recoge un resumen d e todas ellas. Tabla 11.6. Sintaxis de la instruccion SHOW r.- -
~
Variante
Descripci6n
SHOW DATABASES [LIKE base-de-datos]
Enumera todas las bases de datos. Puede sustituir el parametro base-de-datos por sus nombres.
Variante
Descripcibn
SHOW TABLES [FROM base-deda tos] [LIKE tabla]
Enumera las tablas de la base de datos utilizada actualmente o de la base de datos llamada base-de-datos si se especifica. Puede sustituir tabla por el nombre de tablas.
SHOW COLUMNS FROM Enurnera todas las columnas de una tabla de la base de tabla [FROM base-de- datos actualmente en uso o de una base de datos especida tos] [LIKE colunula] ficada. Puede sustituir colurnna por nombres de colurnna. Puede utilizar SHOW FIELDS en lugar de SHOW COLUMNS. SHOW INDEX FROM tabla Muestra 10s detalles de todos 10s indices de una tabla dada [FROM base-de-da tos] de la base de datos actualmente en uso o de otra base de datos llamada base-de-datos si se especifica. Tambien puede utilizar SHOW KEYS en su lugar. SHOW STATUS [LIKE es tado-elemento]
Devuelve inforrnacion sobre una serie de elementos del sistema, como el numero de subprocesos que se estan ejecutando. La clausula LIKE se utiliza para buscar coincidencias en 10s nombres de estos elementos; por ejemplo, '~hread%'recupera 10s elementos 'Threads-cached ' , 'Threads-connected' Y ' T h r e a d ~ ~ r u n n i n g ' .
SHOW VARIABLES [LIKE nombre-de-variabl el
Muestra 10s nombres y 10s valores de las variables del sistema MySQL, como el numero de version. La clausula LIKE se puede utilizar para buscar correspondencias de forma similar a SHOW STATUS.
SHOW [FULL] PROCESSLIST
Muestra todos 10s procesos que se estan ejecutando en el sistema. L a mayor parte d e 10s usuarios veran sus subprocesos per0 si disponen del privilegio PROCESS tambien veran 10s procesos de todos 10s demas usuarios, incluigas sus contrasetias si aparecen en las consultas. Las consultas se dividen en secciones de 100 caracteres de manera predeterminada. La palabra clave FULL muestra las consultas completas.
SHOW TABLE STATUS [FROM base-de-da tos] [LIKE base-de-da tos]
Muestra inforrnacion sobre cada una de las tablas de la base de datos actualmente en uso o de la base de datos llarnada base-de-datos si se especifica, con la posibilidad de buscar coincidencias con cornodines. Entre la inforrnacion se incluye el tip0 de tabla y cuando se actualize por ultima vez.
SHOW GRANTS FOR usudrio
Muestra la instruccion GRANT requerida para recuperar el nivel actual de privilegio asociado al usuario.
Como alternativa a la instrucci6n SHOW COLUMNS, se puede utilizar la instrucci6n D E S C R I B E , que es similar a la instrucci6n D E S C R I B E de Oracle (otro RDBMS).
Desarrollo W e b con PHP y MySQL
Su sintaxis bdsica es DESCRIBE tabla [columna];
Esta instrucci6n devolverd informacidn sobre todas las columnas de la tabla o sobre una columna dada. Puede utilizar comodines en el nombre de la columna.
Compresion del funcionamiento de las consultas con EXPLAIN La instrucci6n EXPLAIN se puede utilizar de dos formas. En primer lugar, puede utilizar EXPLAIN
tabla;
El resultado de esta instruccion es bastante similar a1 devuelto por las instruccionesDESCRIBE tablaoSHOW COLUMNS FROM t a b l a . La segunda forma de utilizar EXPLAIN es mucho mds interesante ya que permite ver c6mo evalua MySQL una consulta SELECT. Para utilizarla de esta forma, basta con poner la palabra e x p l a i n delante de una instrucci6n SELECT. Puede utilizar la instrucci6n EXPLAIN cuando est6 intentando probar una consulta compleja y el resultado no es el esperado o si tarda mds de lo esperado en completarse. Si estd escribiendo una consulta compleja, puede probarla antes ejecutando el comando EXPLAIN. Con el resultado obtenido, puede modificar la consulta para optimizarla si resultara necesario. Se trata tambi6n de una prdctica herramienta de aprendizaje. Por ejemplo, intente ejecutar la siguiente consulta sobre la base de datos Book-ORama. El resultado se rec-oge an la figura 11.2. explain select customers.name from customers, orders, order items, books where customers.customerid = orders.customerid and orders.orderid = order items.orderid and order-items.isbn = books.isbn and books.title like '%Java%'; + .............+........+...............+.........
: type t .............+........ : orders I ALL 1 order-items I ref : c u s t o m e r s I ALL I
I
table
books
1
eq-ref
I
possible-keys
1
PRIMARY PRIMARY PRIMARY PRIMARY
t.
key
........+..................+......+............. key-len
1
ref
:rows
I
NULL orders.orderid NULL order_items.isbn
1
1
Extra
+...............+.........+.........+..................+......+.............
I I
I I
NULL PRIMARY ) NULL I PRIMARY
+ ............. + ........+...............+.........
, 1
NULL I 4 j NULL I 13 1
1
:
4 1 3 1
1
: ;
Using index where used I where used j
+.........+..................+......+.............
+ +
+
Figura 11.2. El resultado de la instruccion EXPLAIN
El resultado puede parecer confuso a1 principio per0 resulta muy util. Vamos a examinar las columnas de esta tabla por separado.
La primera columna, t a b l e , enumera simplemente las tablas utilizadas para responder a la consulta. Cada fila del resultado ofrece informacidn sobre c6mo se ha utilizado dicha tabla en la consulta. En este caso, las tablas utilizadas son o r d e r s , o r d e r items, customers y books. La columna t y p e explica como se est6 utilizando la tabla en las combinaciones de
la consulta. En la tabla 11.7 se recogen 10s distintos valores que puede tener esta colurnna. Estos valores se enumeran del m6s ra'pido a1 ma's lento en terminos d e ejecucidn d e la consulta y proporciona una idea d e la cantidad d e filas que es necesario leer d e cada tabla para ejecutar una consulta. Tabla 11.7. Posibles tipos de combinaciones mostradas por EXPLAIN 1
- -
Tipo
-
-
-
-7
-
Descripcibn
const Osystem
La tabla se lee una sola vez. Esto ocurre cuando la tabla consta d e una sola fila. El tip0 s y s t e m s e utiliza cuando se trata de una tabla del sistema y el tipo c o n s t en el resto de 10s casos.
eq-ref
Para cada conjunto de filas del resto de tablas de la combinacion, leemos una fila de esta tabla. Este tipo se utiliza cuando la combinacion usa todas las partes del indice d e la tabla y el indice es exclusivo o es la clave principal.
ref
Para cada conjunto de filas del resto d e tablas d e la combinacion, leemos un conjunto de filas de esta tabla que coinciden en su totalidad. Este tip0 se utiliza cuando la combinacion no puede seleccionar una unica fila en funcion de la condicion de combinacion, es decir, si solo se utiliza parte d e la clave en la combinacion o si no es exclusiva o una clavebrincipal
range
Para cada conjunto completo d e filas del resto de las tablas de la combinacion, se lee un conjunto de filas de esta tabla , incluidas en un rango dado.
index
Se examina el indice completo
ALL
Se examinan todas las filas de la tabla.
En el ejemplo anterior, puede ver que una d e las tablas se combina con e q r e f ( b o o k s ) ,que otra utiliza el tip0 r e f ( o r d e r i tems 1 y que las otras dos ( o r d e r s y c u s t o m e r s ) se combinan con ALL; es d e z r , examinando todas las filas d e la tablas. La columna rows confirina estas combinaciones: lista aproximadamente el numero de filas d e cada tabla que deben examinarse para realizar la combinacion. Si multiplica estos valores, obtendrh el numero total d e H a s que se examinan a1 llevar a cabo una consulta. Estos numeros se multiplican porque una combinaci6n es como el product0 d e las filas d e diferentes tablas (si desea obtener m6s detalles a1
Desavrollo W e b con P H P y MySQL
respecto, consulte un capitulo anterior). Recuerde que se trata del n6mero de filas examinado, no el numero d e filas devuelto y es una estimaci6n. MySQL no puede saber el n6mero exacto sin llevar a cabo la consulta. Obviamente, cuanto m6s pequel'io sea este numero mejor. En estos momentos el conjunto d e datos d e nuestra base d e datos resulta insignificante, per0 cuando empiece a crecer, el tiempo d e ejecuci6n se disparard. Volveremos sobre este tema en un instante. La columna p o s s i b l e k e y s recoge las claves que MySQL podria utilizar para combinar la tabla. En estecaso, se trata d e las claves principales. La columna k e y es la clave desde la que se utiliza la tabla MySQL o N U L L si no se ha utilizado ninguna clave. Como observari, aunque las tablas o r d e r s y c u s t o m e r s incluyen claves principales, no se utilizan en esta consulta. Veremos c6mo resolver este problema en un instante. La columna k e y l e n indica la longitud de la clave utilizada. Puede utilizarla para determinar si s610 se est6 utilizando parte de una clave, lo cual resulta pertinente cuando s e tienen claves compuestas d e varias columnas. En este caso, se utilizan las claves completas alli donde se utilizan claves ( o r d e r i t e m s y b o o k s ) . La columna r e f muestra las columnas utilizadas con la claveal seleccionar filas d e la tabla. Por ultimo, la columna E x t r a indica cualquier otra informaci6n sobre c6mo se establece la combinaci6n. En la tabla 11.8 se recogen 10s valores posibles que pueden aparecer en esta columna. Tabla 11.8. Los valores posibles de la colurnna devueltos por la instruccion EXPLAIN r=.
Valor
~ -. Significado
-
--.
--
Not exists
L a ~ o n s u l t ase ha optirnizado para utilizar LEFT
Range checked for each record
lntenta buscar el rnejor indice, si existiese, para cada fila del conjunto de filas del resto de las tablas de la cornbinacion.
Using filesort
Seran necesarias dos barridos para ordenar 10s datos. (Por lo tanto, la operacion resultara el doble de larga).
Using index
Toda la inforrnacion de la tabla procede del indice, es decir, no se examinan las filas.
Using temporary WHERE used
JOIN.
Se utiliza una clausula WHERE para seleccionar las filas.
Existen varias formas d e solucionar 10s problemas descubiertos por E X P L A I N . En primer lugar, compruebe 10s tipos de columnas y aseg6rese de que son iguales. En concreto, fijese en el ancho de las columnas. Los ind.ices no se pueden utilizar para comparar columnas si tienen diferentes anchos. Para resolver este problema, cambie 10s tipos de columna de forma que coincidan o integrelos en su diseiio desde el principio.
11. MySQL Avanzado
En segundo lugar, puede pedirle a1 optimizador de combinaciones que examine las distribuciones de clave y que optimice las combinaciones de forma miis eficaz por medio de la utilidad my i s amchk. Para invocarla, escriba rnyisarnchk
-analyze
ruta-a-1
a-base-de-da
tos-mysql/tabla
Puede comprobar varias tablas si las incluye todjls en la linea de comandos o si utiliza rnyisarnchk
-analyze
ruts-a-la-base-de-da t o s - ~ m y s q l / *. M Y I
Puede comprobar todas las tablas de todas las bases de datos ejecutando la siguiente linea, lo que generarii el resultado ilustrado en la figura 11.3: rnyisamchk
+
I +
I I I I
+
analyze
r u ta-al-la
-
directorio-de-da
.............+........+...............+.........+......... table
I
books arder-ltems arders c~stamsrs
I
type
:
possible_keys
key
:
key-len
t
:
tos-mysql
/*,I*
.>lYI
........ .............+......+......................... ref ________________: r a w s Extra
+
.............+........+...............+.........+.........+.....................+......+.........................
.............
I
:
I t
+ I NULL 1 NULL ALL I PRIMARY 4 1 where used NULL lndex I PRIMARY 5 1 where used; Uslng index I 1 7 1 NULL I PRIMARY eq-ref I PRIMARY 4 1 ordsr_ltem~.~rderld I PRIMARY 1 eq-ref PRIMARY 4 1 0rders.customerld I PAIMARY 1 ........+...............+.........+.........+.....................+......+......................... +
:
: : :
: : : :
:
Figura 11.3. Resultado devuelto por EXPLAIN tras ejecutar myisamchk
Como observar6, la forma en la que se evalua la consulta ha variado bastante. Ahora s610 utilizamos todas las filas de una de las tablas (books). En concreto, utilizamos e q r e f para dos de las tablas e i n d e x para las otras. MySQL tambien utiliza ahora 1; clave completa para o r d e r -i t e m s (17 caracteres en lugar de 10s 4 que utilizaba antes). Tambien ha aumentado el numero de filas utilizado, lo que probablemente se debe a que la base de datos incluye pocos datos. Recuerde que el numero de filas indicado no es miis que una estimacidn. Pu'ede realizar la consulta y comprobar si coinciden. Si 10s ntimeros varian mucho, el manual de ' M ~ S Q Lsugiere utilizar una combinaci6n directa y enumerar las tablas en la cliiusula FROM en orden diferente. En tercer lugar, podemos considerar la posibilidad de agregar un nuevo indice a la tabla, si la consulta es a) lenta y b) comun. Si se trata de una consulta especial que es probable que no vuelva a utilizar, no merecerii la pena el esfuerzo ya que ralentizarii otros procesos. En la siguiente secci6n veremos c6mo agilizar las consultas.
Como agilizar consultas con indices Si se encuentra en una situaci6n como la descrita anteriormente, en la que la columna p o s s i b l e k e y s devuelta por una instrucci6n EXPLAIN contiene valores NULL,podria mejorar su rendimiento si agrega un indice a la tabla en cuesti6n. Si la columna que estd utilizando en la c l i i u s u l a w resulta ~ ~ ~ ~ id6nea para su indexacibn,
Desarrollo Web con P H P y MySQL
puede crear un nuevo indice para ella con ayuda de la i n s t r u c c i 6 n ~TABLE ~ ~ ~ de ~ la siguiente forma: ALTER
TABLE
tabla
ADD
INDEX
( c o l u r n n a );
Trucos de optimizaci6n general Ademis de 10s trucos vistos antes para la optimizaci6n de consultas, existen otros que permiten incrementar el rendimiento de las bases de datos MySQL.
Optimizacion del diseno Es aconsejable que todos 10s elementos de la base de datos tengan el menor tamaiio posible. Para ello, se debe minimizar la redundancia en la fase de diseiio. Tambikn se puede lograr el mismo objetivo asignando 10s tipos de datos mis pequeiios a las columnas. Tambikn deberia reducir a1 minimo 10s valores NULL y seleccionar una clave principal que sea lo m6s corta posible. Evite el uso de columnas de longitud variable siempre que pueda (como VARCHAR, TEXT Y BLOB). Si sus tablas tienen campos de longitud fija, resultarin m6s ripidas de utilizar aunque absorban un poco m i s de espacio.
Permisos Ademis de aplicar las sugerencias propuestas en la secci6n dedicada a EXPLAIN, puede mejorar la velocidad delas consultas simplificando 10s permisos. Ya indicamos anteriormente la forma en la que se comprueban las consultas con el sistema de permisos antes de su ejecuci6n. Cuanto m6s sencillo resulte este proceso, mis ripido se ejecutard la consulta.
Optimizacicin de tablas Si lleva utilizando una tabla durante un period0 largo de tiempo, 10s datos pueden fragmentarse a1 procesar las actualizaciones y las eliminaciones. Como consecuencia, el proceso de busqueda puede alargarse. Para solucionar este problema puede utilizar la instrucci6n O P T l M I Z E T A B L E nombre-de-tabla;
o escribir myisarnchk
-r
table
en la linea de comandos.
11. MySQL Avanzado
Tambikn puede recurrir a la utilidadmyisamch k para ordenar un indice de tabla y 10s datos en funci6n de dicho indice, de la siguiente forma: myisamchk sort-index sort-records=l r u t a - a 1 - l a - d i r e c t o r i o - d e - d a t o s -m y s q l / * / * . M Y I
Uso de indices Utilice indices siempre que lo necesite para aumentar la velocidad de las consultas. Intente que resulten sencillos y no Cree indices que sus consultas no vayan a utilizar. Para comprobar 10s indices que se est6n utilizando ejecute la instrucci6n EXPLAIN como se indic6 anteriormente.
Uso de valores predeterminados Siempre que le resulte posible, utilice valores predeterminados e inserte unicamente 10s datos si difieren de 10s predeterminados. De esta forma, se reducir6 el tiempo que tarda la instrucci6n I N S E R T en ejecutarse.
Uso de conexione permanentes Este consejo resulta especialmente de aplicaci6n para las bases de datos Web. Nuestra intenci6n aqui es recod6rselo ya que se coment6 en una secci6n anterior
Otras suplerencias Existen muchos otros trucos que puede aplicar para mejorar el rendimiento en situaciones concretas y paEa rezolver necesidades particulares. En el sitio Web de MySQL encontrar6 una gran cantidad de ellos. Dirijase a
Tipos diferentes de tabla Antes de terminar con el estudio de MySQL, es necesario analizar 10s distintos tipos de tablas. Para seleccionar el tip0 de tabla a1 crearla utilice CREATE TABLE t a b l a T Y P E = t l p o
. . ..
Los posibles tipos de tabla son MY I SAM. Cste es el tip0 predeterminado y el que hemos estado utilizando hasta ahora. Se basa en I SAM,que equivale en inglks a Mktodo de acceso secuencial
indexado, un mktodo estAndar para almacenar 10s registros y 10s archivos.
Desarrollo W e b con PHP y MySQL 1S A M . Descrito arriba. HEAP. Las tablas de este tipo se almacenan en memoria y sus indices se cifran. Como resultado las tablas HEAP son extremadamente rfipidas per0 presentan el inconveniente de que si tiene lugar un fa110 en el sistema, 10s datos se perderfin. Las tablas HEAP resultan ideales para almacenar datos temporales. Es aconsejable especificar el numero mfiximo de filas en la instrucci6n CREATE TABLE o las tablas pueden absorber toda la memoria. Por ultimo, las tablas HEAP no pueden incluir columnas de tipo BLOB, TEXT o AUTO INCREMENT. BDB. Estas tablas garantizan la seguridad de las transacciones, es decir, incluyen las funciones COMMIT y ROLLBACK. Son mfis lentas que las tablas MyISAM, per0 proporcionan todas las ventajas del uso de transacciones. Estas tablas se basan en Berkeley DB.
InnoBD. Estas tablas tambien garantizan la seguridad de las transacciones y se les aplican 10s mismos comentarios de las tabas BDB. Estos tipos de tablas pueden resultar utiles cuando se necesita una mayor velocidad o garantizar la seguridad de las transacciones. Si desea utilizar 10s tipos BDB o InnoDB, deberia seleccionar el tip0 binario MySQL-Max que se incluye en la distribuci6n de MySQL, en lugar del tip0 binario MySQL normal.
Carga de atos desde un archivo Una funci6n util de MySQL de la que todavia no hemos hablado es la instrucci6n LOAD DATA INFILE.
-
a
Esta instruccih se puede utilizar para cargar datos en la tabla procedentes de un archivo. Se ejecuta de forma muy riipida. Se trata de un comando flexible con muchas opciones, per0 se suele utilizar de la siguiente forma: LOAD DATA I N F I L E "newbooks.txt" I N T O T A B L E b o o k s ;
Esta instrucci6n lee las filas del archivo newbooks.txt dentro de la tabla books. De manera predeterminada, 10s campos de datos del archivo deben separarse mediante tabuladores y encerrarse en comillas simples y cada fila debe separarse mediante un carficter de nueva linea (\n). Los caracteres especiales deben marcarse con la barra inclinada (\). Todas estas caracteristicas se puede configurar mediante varias opciones de la instrucci6n LOAD (si desea obtener mfis detalles consulte el manual de MySQL). Para usar la instrucci6n LOAD DATA INFI LE, es necesario disponer del privilegio F I L E comentado anteriormente.
11. MySQL Avanzado
Como realizar una copia de seguridad de la base de datos MySQL MySQL incorpora dos formas de realizar una copia de seguridad. La primera consiste en bloquear las tablas mientras se copian 10s archivos fisicos, utilizando el comando LOCK TABLES. Su sintaxis es la siguiente. LOCK TABLES tabl a tipo-de-bl oqueo
[
,
tabl a tipo-de-bl oqueo . . . ]
El parametro tabla deberia sustituirse por el nombre de una tabla y el tipo-de-bloqueo deberia ser READ o WRITE. Para realizar una copia de seguridad s610 se necesita un bloqueo READ. Los usuarios y las secuencias de comandos pueden ejecutar consultas de s610 lectura durante el volcado. Si tiene un conjunto razonable de consultas que alteren la base de datos, como pedidos de cliente, esta soluci6n no resulta prtictica. El segundo metodo es mtis avanzado y utiliza el comando m y s q l -dump. Se suele utilizar de la siguiente forma: rnysqldump
o p t
>
all-databases
all.sql
Este comando volcarti un conjunto de todo el SQL necesario para volver a construir la base de datos en el archivo a l l . s q l . A continuation, deberia detener el proceso my s q l d durante un instante y volver areiniciarlo con la o p c i 6 n - l o g - u p d a t e [ = a r c h i v o -d e-r e g i s t r o ] . Las actualizaciones almacenadas en el archivo de registro indicartin 10s cambios realizados desde la realizaci6n del volcado. (Obviamente, deberia volcar 10s archivos de registros en un archivo de copia de seguridad normal.)
Restablecimiento de la base de datos MySQL Si necesita restablecer una base de datos MySQL, dispondri nuevamente de dos opciones. Si el problema es una tabla de datos daiiada, puede ejecutar myi s amchk con la opci6n - r (reparar). Si ha utilizado el primer metodo de volcado de seguridad, puede copiar 10s archivos de datos en la misma ubicaci6n dentro de una nueva instalacidn de MySQL. Si ha utilizado el segundo metodo de volcado, el proceso de restablecimiento constarti de dos fases. En primer lugar, tendrti que ejecutar las consultas en el archivo de volcado para reconstruir la base de datos hasta el punto de volcado del archivo. En segundo lugar, deberti actualizar la base de datos desde el punto almacenado en 10s archivos de registro. En UNIX puede ejecutar un comando como el siguiente: 1s -1 -t -r hostname.[O-Ql*
1
xargs
cat
I
mysql
para procesar 10s archivos de registro en el orden correcto.
Desarrollo Web con PHP y M y S Q L
Si desea obtener mds informacidn sobre el proceso de volcado y recuperaci6n de MySQL, consulte el sitio Web de MySQL en: http://www.mysql.org
Lecturas adicionales En estos capitulos sobre MySQL, nos hemos centrado en 10s usos y las partes del sistema mds relevantes para el desarrollo Web y en la combinacidn de MySQL con PHP. Si desea saber mds a1 respecto, en especial en relaci6n a aplicaciones que no Sean Web, o sobre la administraci6n de MySQL, puede visitar el sitio Web de MySQL en
A continuacion Ya hemos analizado 10s conceptos bdsicos de PHP y MySQL. En el siguiente capitulo examinaremos 10s aspectos de seguridad y comercio electrdnico relacionados con la configuracidn de sitios Web basados en bases de datos.
En este capitulo se presentan algunos aspectos relacionados con la especificaci6n, diseiio, construcci6n y mantenimiento de un sitio Web de comercio electr6nico de manera eficaz. Examinaremos el plan, 10s posibles riesgos y varias formas de lograr que un sitio Web resulte autosuficiente. Examinaremos 10s siguientes aspectos: 0
Que se puede consegqir c m un sitio de comercio electr6nico
0
Tipos de sitios Web comerciales Riesgos y amenazas Por qu6 estrategia optar
iCudl es nuestro objetivo? Antes analizar 10s detalles de implementaci6n de su sitio Web, deberia tener claro sus objetivos y disponer de un plan razonablemente pormenorizado para alcanzarlos. En este libro, partimos del supuesto de que est6 desarrollando un sitio Web comercial y que, por lo tanto, uno de sus objetivos es ganar dinero. Existen muchos enfoques comerciales aplicables a Internet. Puede que desee anunciar sus servicios tradicionales o vender en linea un product0 del mundo real.
12. Creacidn de u n sitio Web de comercio electrdnico
QuizAs tenga un product0 que se puede vender y distribuir por la red. 0 puede que no tenga intention de utilizar el sitio Web para generar ingresos, sin0 como medio para fomentar las actividades fuera de linea o como una alternativa menos costosa a las actividades presentes.
Tipos de sitios Web comerciales Los sitios Web comerciales realizan una o varias de las actividades siguientes: Publicar informaci6n sobre la compafiia a trav6s de folletos en linea Recoger pedidos de articulos o servicios Suministrar servicios o articulos digitales Afiadir valor a 10s articulos o servicios Reducir costes Las secciones de muchos sitios Web encajan en varias categorias. A continuaci6n, se incluye una descripci6n de cada una de ellas y la forma habitual en la que generan ingresos u obtienen otros beneficios para una organizaci6n. La intenci6n de esta secci6n del libro es ayudarle a formular sus objetos. iPor qu6 quiere un sitio Web? ~ C O va~ aOcontribuir cada funci6n de su sitio Web a1 negocio?
Medios publicitarios en Iinea PrActicamente todos 10s sitios Web comerciales de principios de 10s afios 90 no eran m6s que una folleto ek linTa o una herramienta de venta. Este tip0 de sitios sigue siendo la forma mAs habitual adoptada por 10s sitios Web comerciales. Ya sea como incursi6n en la Web o como ejercicio de publicidad de bajo coste, este tip0 de sitios siguen teniendo su 16gica para muchos negocios. La presencia publicitaria en Internet puede adoptar distintas formas, desde una tarjeta de visita convertida en pAgina Web a una colecci6n de informaci6n publicitaria. En cualquier caso, el objetivo del sitio y la raz6n financiera de su existencia es atraer a 10s clientes para que entren en contact0 con nuestro negocio. Este tip0 de sitios no genera ningun ingreso directamente, per0 puede contribuir a 10s beneficios obtenidos a trav6s de 10s medios tradicionales. El desarrollo de un sitio de este tip0 presenta pocos retos t6cnicos. Los aspectos sobre 10s que centrarse son similares a 10s de otros ejercicios de publicidad. Entre 10s errores mds habituales que se suelen cometer a1 desarrollar este tip0 de sitios se incluyen 10s siguientes: No suministrar informaci6n importante
Desarrollo W e b con PHP y MySQL
No responder a la informaci6n generada por el sitio No actualizar el sitio No rastrear el 4xito del sitio
N o suministrar informacidn importante iQu4 es lo que buscan 10s visitantes que acuden a su sitio? Todo depende de lo que ya sepan. Puede que busquen informaci6n t4cnica detallada sobre el product0 o informaci6n muy b6sica como datos de contacto. La informaci6n que suministran muchos sitios Web no resulta util o no incluyen 10s datos m6s importantes. Como minimo, el sitio debe indicar a 10s visitantes a qu4 nos dedicamos, en qu4 Areas geogr6ficas del mundo se proporcionan nuestros servicios y c6mo pueden ponerse en contacto con nosotros.
Mala presentacidn En Internet, una empresa pequeiia puede parecer de mayor tamaiio y resultar muy llamativa y, a1 contrario, una empresa de gran tamafio puede parecer pequeiia, poco profesional y poco llamativa si el sitio Web no est6 bien diseiiado. Con independencia del tamaiio que tenga su empresa, asegurese de que su sitio Web sea de calidad. El texto debe estar escrito y revisado por alguien con un buen conocimiento del lenguaje correcto. Los grtificos deben estar limpios, deben ser claros y deben tardar poco tiempo en descargarse. En un sitio comercial, deberia tener cuidado a1 elegir 10s gr6ficos y 10s colores de manera que encajen con la imagen que se desea transmitir. Si utiliza efectos de animaci6n y sonido procure hacerlo con cuidado. Aunque no lograrti que su sitio se genere de la misma forma en todos 10s equipos, sistemas operativos y navggadores, asegurese de que se visualiza y de que no produzca errores generalczados.
N o responder a la informacidn generada por el sitio Web En la Web, un buen servicio de asistencia a1 cliente resulta tan importante para atraer y mantener clientes como en el mundo exterior. Las compafiias, ya Sean pequeiias o grandes, son responsables de colocar una direcci6n de correo electr6nico en una p6gina Web y de no examinar o responder a 10s mensajes de correo riipidamente. La gente suele tener diferentes expectativas sobrelos tiempos de respuesta a 10s mensajes de correo electr6nico con respecto a1 correo postal. Si no examina y responde a1 correo diariamente, 10s usuarios creer6n que no se concede la importancia necesaria a sus consultas. Las direcciones que se incluyen en piginas Web deberian ser genericas e ir dirigidas a un puesto o departamento en lugar de a una persona concreta. iQue ocurrir6 con el correo enviado a fred.smith@ejemplo . com cuando se vaya su titular? Es mas probable que el correo dirigido a ventas @ej empl o .com pase a su
12. Creacidn de u n sitio Web de cornercio electrdnico
sucesor. Tambikn podria distribuirse a un grupo de personas, lo que contribuiria a garantizar su pronta contestaci6n.
No actualizar el sitio Debe procurar que su sitio Web estk actualizado. Para ello, es necesario cambiar 10s contenidos peribdicamente. Los cambios en la organizaci6n deben reflejarse en el sitio. Un sitio Web con telaraiias desanimar6 a 10s visitantes a volver y contribuir6 a hacerles creer que gran parte de la informaci6n podria ser incorrecta. Una forma de evitar que un sitio parezca obsoleto consiste en actualizar sus piginas manualmente. Tambien puede utilizar un lenguaje de secuencia de comandos como PHP para crear piginas dinimicas. Si su secuencia de comandos dispone de acceso a informaci6n actualizada, podrh generar p6ginas que esten a1 dia de manera constante.
No realirar el seguimiento del exito del sitio Crear un sitio Web es muy buena idea, per0 jc6m0 justificar el esfuerzo y el gasto? Llegar6 un momento, en especial si se trata del sitio de una gran compafiia, en el que se le pedir6 que demuestre o cuantifique su valor para la organizacibn. En las campafias de marketing tradicionales, las grandes organizaciones invierten mucho dinero en estudios de mercado, antes y despuks de lanzar la campafia, para comprobar su eficacia. En funci6n de la escala y del presupuesto asignado a la iniciativa Web, estos indicadores podrian resultar igualmente apropiados para el disefio del sitio o para cuantificar su valor. Entre las opciones disponibles, m6s caras o m6s baratas, se incluyen las siguientes:
Examinar 10s registros del servidor: 10s servidores Web almacenan una gran cantidad de datos sobre cada petici6n realizada a1 servidor. Gran parte de estos datos resultande pika utilidad y su formato sin procesar tampoco es de gran ayuda. Para destilar 10s archivos de registros y obtener un resumen significativo de 10s datos, es necesario utilizar un analizador de archivos de registros. Dos de 10s m6s conocidos y gratuitos son Analog, disponible en la h t t p : / / w w w . s t a t s l a b . cam. a c . u k / - s r e t l / a n a l o g , y Webalizer, disponible en h t t p : //www.mrunix. n e t / w e b a l i z e r / . Tambikn existen programas comerciales como summary, disponible en h t t p : / / summary n e t , que podrian resultar m6s completos. Los analizadores muestran c6mo varia el tr6fico de un sitio Web con el tiempo y quk paginas se ven.
.
Monitorizaci6n de las ventas: el objetivo de 10s sitios Web con funciones publicitarias es generar ventas. Deberia poder estimar el efecto sobre las ventas compar6ndolo con 10s niveles de ventas antes del lanzamiento del sitio. Esta operaci6n se complica si se han aplicado otras acciones de marketing en el mismo periodo. Solicitar informacidn a 10s usuarios: si pregunta a sus usuarios, kstos le dir6n lo que piensan del sitio. Puede obtener informaci6n 6til mediante un formula-
Desarrollo Web con PHP y MySQL
rio o una direcci6n de correo electr6nico con la que recoger 10s comentarios de 10s usuarios. Para animar a 10s usuarios a enviar informaci6n puede incluir un incentivo, como la participaci6n en un sorteo. Analisis de usuarios representativos: la creaci6n de grupos de opinion puede convertirse en una t6cnica eficaz para evaluar un sitio o incluso en un prototipo del sitio previsto. Para dirigir un grupo de opini6n s610 necesitarii reunir algunos voluntarios, animarles a valorar el sitio y entrevistarles para obtener y registrar sus opiniones. Los grupos de opini6n pueden resultar caros si su direcci6n se delega en moderadores profesionales encargados d e valorar y filtrar a 10s participantes con el objetivo de garantizar una representaci6n demogriifica y de personalidad exacta dentro de una comunidad amplia y , a continuac%n, entrevistar hiibilmente a 10s participantes. Pero el coste d e 10s grupos de opini6n tambi6n puede ser nulo, si su direcci6n se deja en manos d e un amateur y si se utiliza u n conjunto de personas cuya relevancia con respecto a1 mercado d e destino sea desconocida. Una forma de obtener u n grupo de opini6n bien dirigido consiste en recurrir a 10s servicios de una compaiiia especializada en investigaciones de mercado, per0 no es la 6nica. Si dirige su propio grupo d e opinibn, procure seleccionar un moderador hiibil. Se deben valorar especialmente sus cualidades de comunicaci6n e imparcialidad ante 10s resultados. Limite el tamaiio d e 10s grupos a conjuntos d e entre seis y diez personas. El moderador deberia estar apoyado por una persona encargada de registrar 10s datos o por una secretaria que le permita centrarse en la entrevista. La validez de 10s resultados obtenidos de 10s grupos se corresponderii con a1 muestra de gente utilizada. Si utiliza a amigos o a 10s familiares de sus empleados para valorar el producto, es poco probable que representen a la comunidad general.
Recogida de pedjdos de articulos y servicios Si la publicidad del sitio resulta atrayente, el siguiente paso 16gico consistira en permitir que sus clientes realicen el pedido por Internet. Los profesionales de las ventas saben que es importante lograr que 10s clientes tomen una decisi6n de manera inmediata. Cuanto miis tiempo se conceda a1 cliente para reconsiderar la decisi6n de compra, mayor serii la probabilidad de que mire otras ofertas y cambie de opini6n. Si un cliente quiere su producto, la mejor estrategia es permitirle realizar la compra de la forma miis fiicil y riipida posible. Si obligamos a la gente a desconectar el m6dem para llamar por tel6fono y realizar un pedido o a acudir a una tienda, lo que estaremos haciendo es poner obstiiculos a la compra. Si la publicidad en linea ha convencido a un visitante a comprar un producto, permitale que realice la compra de inmediato sin abandonar el sitio Web. La recogida de pedidos a travds de un sitio Web es una buena idea para muchas iniciativas comerciales. Todos 10s negocios quieren pedidos. La posibilidad de realizar pedidos en linea permite aumentar las ventas o reducir la carga sobre el personal de ventas. Obviamente, tambi6n se incurririi en unos costes. La construcci6n de un
12. Creacidn de u n sitio Web de comercio electrdnico
sitio Web dinfimico, la organizaci6n de la infraestructura de pago y el suministro de un servicio de atenci6n a1 cliente suponen gastos. Intente determinar si sus productos resultan adecuados para su comercializaci6n a trav& de un sitio de comercio electrbnico. Entre 10s productos que se suelen comprar a traves de Internet se incluyen libros y revistas, programas y equipos informhticos, musica, ropa, viajes y entradas a eventos de entretenimiento. Si su producto no se incluye en ninguna de estas categorias, no desespere. Estas categorias estfin atestadas de marcas establecidas. Sin embargo, resulta aconsejable considerar alguno de 10s factores que explican por qu6 estos productos se venden tan bien por Internet. De manera ideal, 10s productos que se venden en un comercio electr6nico son imperecederos, sencillos de transportar y lo suficientemente caros como para que 10s gastos de envios resultan razonables aunque no demasiado caros como para que el comprador sienta la necesidad de examinarlos fisicamente antes de comprarlos. Los mejores productos para su comercializaci6n a traves de un comercio electr6nico son 10s bienes de consumo. Si quiere comprar un aguacate, es probable que desee examinarlo visualmente antes e incluso tocarlo. No todos 10s aguacates son iguales. La copia de un libro, de un CD o de un programa informhtico suele ser idhtica a otras copias con el mismo titulo. Los compradores no necesitan ver el articulo concreto antes de comprarlo. Ademfis, 10s productos comercializados a traves de comercios electr6nicos deben atraer a la gente que utiliza Internet. En el momento de escribir este libro, esta audiencia se compone fundamentalmente de adultos con empleo, j6venes, con ingresos medios altos y asentados en zonas urbanas. Con el tiempo, sin embargo, 10s usuarios de Internet abarcarhn a toda la poblaci6n. Algunos productos nunca aparecerhn reflejados en 10s estudios sobre ventas por Internet, per0 son un 6xito. Si tiene un producto que atrae unicamente a un nicho del mercado, Internet puede se? un medio fantfistico para obtener comparadores. Algunos productos tienen pocas probabilidades de convertirse en categorias de comercio electr6nico. Los articulos baratos y perecederos, como 10s comestibles, son una mala opci6n, aunque esto no ha disuadido a las compafiias a intentarlo, aunque sin mucho exito. Existen categorias que encajan perfectamente en sitios publicitarios per0 que resultan dptimas para su venta en linea. Por ejemplo, articu10s grandes y caros, como vehiculos o propiedades inmobiliarias que requieren mucha investigaci6n antes de su compra, per0 que resultan demasiado caros para servirlos en forma de pedidos y dificiles de transportar. Existen varios obstficulos para convencer a un comprador potencial de que rellene un pedido. A saber: Preguntas sin respuesta Confianza Facilidad de uso Compatibilidad
Desarrollo W e b con PHP y MySQL
Si un usuario se ve frustrado por cualquiera de estos obstdculos, es probable que abandone el sitio sin comprar.
Preguntas sin respuesta Si un usuario potencial no encuentra una respuesta inmediata a una pregunta, es probable que abandone el sitio. Este hecho trae consigo una serie de implicaciones. AsegGrese de que el sitio estd bien organizado. ~Resultasencillo buscar lo que se desea cuando se visita el sitio por primera vez? Asegtirese de que el sitio resulta completo per0 sin abrumar a 10s visitantes. En la Web, 10s usuarios suelen examinar rdpidamente el contenido en lugar de leerlo atentamente, por lo que es aconsejable ser conciso. En la mayor parte de 10s medios publicitarios, existen limites priicticos en cuanto a la cantidad de informaci6n que se puede incluir. No ocurre asi en el caso de un sitio Web. En este caso, 10s dos limites principales son el coste de crear y actualizar la informaci6n y las restricciones impuestas por la capacidad para organizar, distribuir y conectar la informaci6n sin abrumar a 10s visitantes. Resulta tentador imaginar un sitio Web como un comercial que recoge 10s pedidos automdticamente, que nunca duerme y que no reciben ningGn salario. Sin embargo, el servicio de asistencia a1 cliente sigue siendo importante. Anime a 10s visitantes a formular preguntas. Intente suministrar respuestas inmediatas o prdcticamente inmediatas por tel6fon0, por correo electr6nico o a trav6s de cualquier otro medio oportuno.
Confianra Si un visitante no estd familiarizado con una marca, ipor qu6 deberia fiarse de nosotros? Todo el mundo puede crear un sitio Web. La gente no tiene por qu6 fiarse de lo escrito en el sitio Web y la realizaci6n de un pedido requiere una determinada confianza. iC6m0 distingue eLvisitante entre una organizaci6n con buena reputaci6n o una empresa sin eskipulos? A la gente le preocupa una serie de cosas a1 comprar en la red: i Q ~ se 6 va a hacer con su informaci6n personal? iSe va a vender a otros, se va a utilizar para enviar enormes cantidades de publicidad o se va almacenar en un lugar poco seguro para que otros puedan acceder a ella? Es importante indicar a la gente qu6 es lo que se va a hacer con sus datos. Es lo que se conoce como politica de privacidad y deberia resultar fdcil de acceder a ella. ~ S negocio U es respetable? Si su empresa estd registrada en una entidad con autoridad relevante, tiene una direcci6n fisica y un nGmero de tel6fon0, y lleva varios afios funcionando, es menos probable que se trate de un engafio que un negocio compuesto tinicamente por un sitio Web y quizds una direccidn postal. Asegtirese de mostrar estos detalles. iQu6 ocurre si un comprador no estd satisfecho con su compra? iEn qu6 circunstancias se procederd a realizar un reembolso? iQui6n se hace cargo de 10s gastos de envio? Tradicionalmente, las empresas dedicadas a la venta por
12. Creacidn de u n sitio W e b de comercio electrdnico
correo aplican politicas de reembolso rnis liberales que 10s establecimientos tradicionales. Muchos ofrecen una garantia de satisfacci6n sin condiciones. Tenga en cuenta 10s costes de las devoluciones con respecto a1 aumento de las ventas que generari una politica general de devoluci6n. En cualquier caso, asegurese de indicar la politica aplicada en el sitio. ~Deberian10s clientes confiarle la informaci6n de sus tarjetas de credito? El aspect0 rnis importante relacionado con la confianza de 10s compradores de Internet es el temor a enviar 10s datos de su tarjeta de credit0 por la red. Por esta raz6n, debe administrar la informaci6n sobre tarjetas de credit0 de manera segura y recalcar su preocupaci6n a1 respecto. Esto significa que, como minimo, deberia aplicar el sistema SSL (Secure Sockets Layer) para transmitir 10s detalles desde el navegador del usuario a1 servidor Web y asegurarse de que su servidor Web esti administrado de manera competente y segura. En una secci6n posterior ampliaremos estos temas.
Facilidad de uso Los consumidores varian enormemente en cuanto a su experiencia con 10s ordenadores, idioma, nivel de alfabetizacibn, memoria y visi6n. Debe intentar que su sitio resulte lo rnis sencillo posible de utilizar. Aunque existe una gran cantidad de libros dedicados a1 disefio de la interfaz de usuario, a continuaci6n se recogen varias directrices:
Intente mantener la sencillez del sitio a1 mdximo. Cuantas m i s opciones, anuncios o elementos de distracci6n se incluyan en la pantalla, mds probable seri confundir a1 usuario. Intente que el texto resulte claro. Utilice fuentes claras y sencillas. No utilice tamafios demasiado ~ e d w i d o ys tenga en cuenta que en cada equipo se representari con tamafios diferentes. Aseglirese de simplificar a1 mdximo el proceso de realizacih de pedidos. La intuici6n y las pruebas disponibles avalan la idea de que cuantos rnis clics del rat6n tenga que aplicar el usuario para realizar un pedido mayor seri la posibilidad de que no complete el proceso. Intente reducir a1 minimo lo pasos, per0 tenga en cuenta que Amazon.com tiene la patente en EEUU sobre un proceso que utiliza un unico clic, denominado 1-Click. Esta patente es impugnada energicamente por muchos propietarios de sitios Web. Procure que 10s usuarios no se pierdan. Incluya puntos de referencia y pistas de navegaci6n para indicar a 10s usuarios d6nde se encuentran. Por ejemplo, si un usuario se encuentra dentro de una subsecci6n del sitio, resalte la seiial de navegaci6n correspondiente a dicho sitio. Si esti utilizando la metifora del carro de la compra en la que se suministra un contenedor en el que 10s clientes pueden acumular sus compras antes de finalizar la venta, mantenga un vinculo visible a1 carro en la pantalla constantemente.
Desarroilo W e b con PHP y MySQL
Compatibilidad Asegurese de probar su sitio en varios navegadores y sistemas operativos. Si el sitio no funciona en un navegador o sistema operativo extendido, el sitio pareceri poco profesional y perderi un porcentaje importante del mercado. Si su sitio ya es operativo, 10s registros de su servidor Web pueden indicar quk navegadores utilizan sus visitantes. Como regla general, si prueba su sitio en las dos ultimas versiones de Microsoft Internet Explorer y Netscape / Mozilla en un PC que ejecute Microsoft Windows, en las dos tiltimas versiones de Netscape/Mozilla en un Apple Mac, la versi6n actual de Netscape / Mozilla de Linux y un navegador de s610 texto como Lynx, su sitio resultara visible para la mayor parte de 10s usuarios. Intente evitar funciones y mecanismos nuevos, a menos que le apetezca escribir y mantener varias versiones del sitio.
Suministro de servicios y articulos digitales Muchos productos y servicios se puede vender a traves de la Web y enviar a 10s clientes por correo. Sin embargo, existen servicios que se pueden entregar de manera inmediata a traves de Internet. Si un servicio o articulo se puede trasmitir hasta un m6dem, se podri pedir, pagar y entregar de manera instantinea, sin interacci6n humana. El servicio de este tip0 m i s obvio es la informaci6n. En ocasiones la informacidn resulta completamente gratuita o se alimenta de publicidad. En algunos casos la informaci6n se suministra a traves de una suscripci6n o se paga por unidades. Entre 10s articulos digitales de este tip0 se incluyen libros electr6nicos y musica en formato electr6nico como MP3. Las bibliotecas de imigenes se pueden digitalizar y descargar. El software mforifiitico no tiene por que incluirse siempre en CD. Se puede comprimir y descargar. Entre 10s servicios que se pueden vender de esta forma se incluyen el acceso a Internet o servicios de alojamiento Web asi como servicios profesionales que se pueden sustituir por un sistema experto. El envio fisico de un articulo solicitado desde un sitio Web presenta ventajas e inconvenientes sobre 10s articulos y servicios digitales. El envio de un articulo fisicamente tiene un coste mientras que las descargas digitales son pricticamente gratuitas. Esto significa que si tiene algo que se pueda duplicar y vender digitalmente, el coste para su sitio sera el mismo si vende un unidad que si vende mil. Por supuesto, existen limites: si el nivel de ventas y el trifico aumenta, se verA obligado a invertir en hardware o ancho de banda. Los productos o servicios digitales se pueden vender con facilidad como articulos inmediatos. Si una persona realiza un pedido de un articulo fisico tendra que esperar uno o varios dias para recibirlo. Las descargas se suelen medir en segundos o minutos. La inmediatez puede convertirse en una carga para 10s comerciantes. Si distribuye un product0 digitalmente, tendra que hacerlo de inmediato. No puede supervisar
12. Creacidn de u n sitio W e b de comercio electrdnico
el proceso manualmente ni distribuir 10s picos de actividad durante el dia. Los sistemas de distribuci6n inmediata resultan por tanto mds proclives a1 fraude y suponen una carga sobre 10s recursos informiticos. Los articulos y 10s servicios digitales son ideales para el comercio electr6nico pero, como es obvio, el abanico de productos que se puede distribuir de esta forma es limitado.
C6mo aiiadir valor a 10s articulos y servicios Algunas secciones de sitios Web comerciales no venden ningun articulo ni servicio. Los servicios de seguimientos que incorporan las compaiiias de mensajeria (UPS en www. u p s . corn o Fedex en www. f edex corn) no estdn disefiados para generar ingresos directamente. Afiaden valor a 10s servicios existentes ofrecidos por la organizaci6n. Las compafiias obtienen una ventaja competitiva a1 permitir que 10s clientes puedan saber donde se encuentra su paquete o acceder a sus cuentas bancarias. Dentro de esta categoria se incluyen 10s foros de ayuda. Existen fundadas razones comerciales para ofrecer a 10s clientes un Area de debate en la que compartir sugerencias para resolver problemas sobre 10s productos de su compaiiia. Los clientes pueden resolver sus problemas consultando las soluciones dadas a otros, 10s clientes internacionales puede obtener ayuda sin tener que realizar llamadas internacionales y pueden responder a preguntas de otros clientes fuera de 10s horarios de oficina. Este tip0 de servicios puede contribuir a aumentar la satisfacci6n de 10s clientes con un coste muy bajo.
.
Recorte de costes Internet se suele utilizai. parzrecortar costes. El ahorro puede proceder de la distribuci6n de la informaci6n en linea, de la facilidad para el establecimiento de la comunicaci6n, de la sustituci6n de servicios o de la centralizaci6n de operaciones. Si necesita distribuir informaci6n a una gran cantidad de usuarios, probablemente pueda realizar la misma tarea a traves de un sitio Web de manera mEis econ6mica. Independientemente de que se trate de suministrar listas de precios, catAlogos, procedimientos documentados, especificaciones tecnicas o cualquier otra informaci6n, es probable que resulte m6s barato colocar la informaci6n en la Web que imprimirla y distribuirla en papel, en especial si la informaci6n cambia de manera regular. El resultado es el mismo, ya se trate de distribuir ofertas y responder a ellas rgpidamente o de facilitar la comunicaci6n directa de cliente con el mayorista o el fabricante, eliminando intermediarios: 10s precios b a j a r h o 10s ingresos crecerh. La sustituci6n de servicios que supongan un gasto por su versi6n electr6nica puede reducir 10s costes. Un buen ejemplo es el de Egghead.com. Los responsables de esta empresa decidieron cerrar sus almacenes de ordenadores y centrarse en actividades de comercio electr6nico. Aunque la construcci6n de un sitio de comercio electr6nico de cierta entidad cuesta dinero, el coste de mantener una cadena de mds de 70 tiendas
Desarrollo Web con PHP y MySQL
es mucho mayor. La sustituci6n de un servicio existente tiene sus riesgos. Entre ellos, la pkrdida de clientes que no utilicen Internet. La centralizaci6n tambien puede contribuir a reducir costes. El mantenimiento de una gran cantidad de sedes fisicas requiere el pago de rentas y gastos indirectos, el personal que trabaja en ellas y 10s costes del mantenimiento de inventario en cada sede. Un negocio en Internet puede situarse en un unico punto y resultar accesible a todo el mundo.
Riesgos y amenazas Todos 10s negocios deben hacer frente a riesgos, competidores, robos, cambios en las preferencias del public0 y a desastres naturales, entre otros. La lista es interminable. Sin embargo, muchos de 10s riesgos a 10s que deben hacer frente las compaiiias de comercio electronic0 son muy inferiores o resultan irrelevantes con respecto a otras iniciativas. Estos riesgos incluyen: Piratas inform~ticos Fracaso en la atraccion de suficiente negocio Fallos de hardware Fallos de alimentacion, de comunicacion y de red Fiabilidad de 10s servicios de distribucion Competencia Errores de softwareCambios en las politicas e impuestos gubernamentales Limites de la capacidad sistema
Pi ratas informhticos Las amenazas mas conocidas para 10s sitios de comercio electronic0 proceden de 10s usuarios de ordenadores malintencionados conocidos como piratas informaticos. Todos 10s negocios corren el riesgo de convertirse en el objetivo de 10s criminales, per0 no hay duda de que 10s comercios electr6nicos atraen la atencion de 10s piratas informaticos con una variedad de intenciones y habilidades. Los piratas pueden atacar por el desafio o la fama que supone sabotear un sitio, para robar o para obtener articulos y servicios gratuitos. La protection de un sitio implica una combination de tareas: Mantener copias de seguridad de la information importante
12. Creacidn de u n sitio W e b de comercio electrdnico
Aplicar politicas de contratacion que atraigan a personal honesto y mantener su fidelidad (10s ataques rnis peligrosos proceden del interior) Adoptar precauciones basadas en software, como seleccionar software seguro o actualizarlo Formar a1 personal para identificar objetivos y puntos d6biles Auditar y registrar las actividades para detectar las intrusiones o 10s intentos de intrusi6n Los ataques rnis efectivos sobre sistemas informiticos aprovechan puntos d6biles conocidos, como contraseiias ficiles d e averiguar, malas configuraciones y versiones antiguas de software. La adopci6n de unas cuantas medidas puede desanimar a 10s atacantes con poca experiencia y garantizar la disponibilidad de una copia de seguridad si ocurre lo peor.
Fracaso en la atraccion de suficiente negocio Aunque 10s ataques de 10s piratas informiticos son muy temidos, la raz6n de la mayor parte de 10s fracasos en el imbito de 10s comercios electr6nicos viene determinado por factores econ6micos tradicionales. La creaci6n y comercializaci6n de un sitio de comercio electr6nico de gran tamaiio exige fuertes inversiones. Las compaiiias aceptan la p6rdida de dinero a corto plazo si ello conlleva un refuerzo de la marca en el mercado y un increment0 de clientes e ingresos futuros. En el momento de escribir estas lineas, Amazon.com, que es con pocas dudas el establecimiento minorista rnis conocido de la Web, lleva perdiendo dinero durante cinco afios consecutivos (las perdidas en el primer trimestre de 2000 ascienden a 99 millones de d6lares). En la larga lista de fracasos sonados destaca la empresa europea boo. corn, que agot6 sus fondos y fue absorbida tras invertir mas 120 millones de d6lares en seis meses. No es que Boo no vendiera, sin0 que gastaban mucho rnis de lo que obtenia.
Fallos de hardware No hace falta decir que si su negocio depende de un sitio Web y falla una parte esencial de uno de 10s equipos, el resultado se veri afectado. En 10s sitios Web con mucho trifico o cuyo mantenimiento activo resulte esencia1 esta justificada la existencia de sistemas redundantes para que el fa110 de uno afecte a1 funcionamiento de todo el sistema. Como con todas las amenazas, debe determinar si la posibilidad de desactivar su sitio Web por un dia a la espera de que se realicen las reparaciones pertinentes justifica 10s gastos en equipo redundante.
Desarrollo W e b con PHP y MySQL
Fallos de alimentacion, comunicacion, red y distri bucion Internet se basa en una compleja red de proveedores de servicios. Si su conexidn con el resto del mundo falla, no podr6 hacer mucho m6s que esperar a que el proveedor vuelva a instalar el servicio. Otro tanto se puede decir con respecto a las cortes del fluido elktrico, a las huelgas y a otro tip0 de parones relacionados con las compafiias de reparto. Existe una soluci6n que depende del presupuesto y consiste en contratar varios servicios a proveedores distintos. El coste se incrementar6 pero si uno de 10s proveedores falla, pod& recurrir a otro. Los cortes breves de suministro elkctrico se pueden superar invirtiendo en generadores.
Com petencia Si va a abrir una tienda en una calle, no le costar6 mucho hacer un estudio exacto sobre la competencia con la que se va a enfrentar. Sus competidores ser6n principalmente negocios que vendan articulos similares y que e s t h situados en 10s alrededores. Adem6s surgir6n otros. En el Ambito del comercio electr6nic0, el terreno es m6s incierto. Los competidores dependerin de 10s costes de envio y pueden encontrarse en cualquier parte del mundo. Ademas, estar6n sujetos a las fluctuaciones de las divisas y a 10s costes de la mano de obra. En Internet la competencia es encarnizada y cambia a gran velocidad. Si trabaja en una categoria popular, puedemparecer competidores todos 10s dias. No hay mucho que pueda hacer para eliminar el riesgo de la competencia, per0 si se mantiene a1 tanto de 10s nuevos desarrollos, puede estar seguro de que su iniciativa resultar6 competitiva.
Errores de software Los negocios basados en software resultan vulnerables a 10s errores de las aplicaciones informhticas. Para reducir la probabilidad de errores vitales, seleccione software que resulte fiable, asigne tiempo suficiente para probarlo tras cambiar partes de su sistema, disponga de un proceso de prueba formal y no permita que se realicen cambios en el sistema activo sin probarlos antes en otra parte. Para reducir la gravedad de 10s resultados, realice copias de seguridad actualizadas de todos 10s datos, mantenga configuraciones operativas de software a1 realizar un cambio y supervise el funcionamiento del sistema para detectar problemas r6pidamente.
12. Creacio'n de un sitio W e b de comercio electro'nico
Cambios en las politicas e impuestos gubernamentales La legislaci6n sobre las empresas basadas en Internet varia segun 10s paises. Las posibilidades van desde que no exista legislaci6n alguna a que se encuentre en fase de desarrollo o que est6 suficientemente desarrollada. Esta situation es poco probable que continue asi. Como resultado, algunos modelos empresariales podrian verse amenazados, regulados o eliminados por la legislacion futura. Ademis, surgiran impuestos. No hay forma de evitar estas cuestiones. La unica soluci6n consiste en estar atento a la nueva legislaci6n y mantener el sitio dentro de la ley. Considere la posibilidad de integrarse en un grupo de presi6n cuando vayan surgiendo estas cuestiones.
Limites de la capacidad del sistema Una cuestion que deberia tener presente a1 diseiiar su sistema es el crecimiento. Lo normal es que su sistema reciba cada vez mas trafico por lo que deberia diseiiarse de forma se pueda escalar para hacer frente a la nueva demanda. Si el crecimiento es limitado puede incrementar la capacidad del sistema adquiriendo hardware mas ripido. Pero 10s equipos tienen un limite en cuanto a la velocidad. ~ E s t descrito su software para que a1 alcanzar ese punto, se puedan separar sus partes para compartir la carga entre varios sistemas? ~ P u e d esu base de datos procesar varias peticiones simultaneas procedentes de diferentes equipos? Hay muy pocos sistemas que puedan hacer frente a un crecimiento ingente si esfuerzos, per0 si disefia su sistema teniendo en cuenta el factor de la escalabilidad, podra identificar y eliminar loscuellos de botella cuando crezca su base de clientes.
Por quC estrategia optar Algunos creen que Internet cambia demasiado rapid0 como para poder realizar planes que resulten eficaces. Pero esa mutabilidad convierte en fundamental la labor de planificacibn. Si no establece metas y selecciona una estrategia, se verd obligado a improvisar ante 10s cambios en lugar de anticiparse a ellos. Tras examinar algunos de 10s objetivos tipicos de un sitio Web comercial y algunas de las amenazas principales a las que hacer frente, es probable que ya tenga pensada alguna estrategia para el suyo. Esta estrategia debe identificar un modelo de negocios. En general, el modelo de negocios suele ser una iniciativa cuyo funcionamiento ya se ha probado, per0 en ocasiones puede tratarse de una idea en la que tenga fe. ~Adaptardsu modelo de negocios actual a la Web, imitard a un competidor o creard un servicio pionero?
\
Desarrollo W e b con PHP y MySQL
A continuacion En el siguiente capitulo, abordaremos el tema de la seguridad en el comercio electr6nico y suministraremos una descripci6n general de 10s terminos, amenazas y t&nicas de seguridad.
En este capitulo se analiza el papel de la seguridad en el comercio electr6nico. Veremos qui6n puede estar interesado en nuestra informaci6n y c6mo podrian obtenerla, 10s principios irnplicados en la creacidn de una politica para evitar este tip0 de problemas y algunas tecnologias disponibles para salvaguardar la seguridad de u n sitio Web incluida la criptografia, la autenticaci6n y el rastreo. En este capitulo se examinarin 10s siguientes aspectos: Importancia de la i n f o f m a c h Arnenazas contra la seguridad Creaci6n de una politica de seguridad Equilibrio entre usabilidad, rendimiento, coste y seguridad Principios de autenticacidn Uso de autenticacion Fundamentos de la criptografia Criptografia de clave publica Firmas digitales Certificados digitales Servidores Web seguros Auditorias y registros
13. Aspectos de seguridad relacionados con el comercio electrdnico
Cortafuegos Copia de seguridad de datos Seguridad fisica
lmportancia de la informacion A1 analizar el tema de la seguridad, lo primer0 que tenemos que valorar es la importancia de 10s datos que estamos protegiendo, tanto para nosotros como para 10s atacantes potenciales. Puede resultar tentador creer que siempre deberia aplicarse el nivel mas alto seguridad a todos 10s sitios, per0 la protecci6n tiene un coste. Antes de decidir el esfuerzo o 10s gastos que se desean invertir en el sistema de seguridad, es necesario determinar el valor de la informaci6n. El valor de la informacion almacenada en el equip0 de un usuario que utilice su ordenador para divertirse, el de una empresa, el de un banco y el de una organizaci6n militar es diferente, a1 igual que varian 10s esfuerzos que invertir6 un atacante para obtener acceso a dicha informaci6n. Tenemos que determinar el valor que tienen 10s contenidos almacenados en nuestros equipos para un visitante malintencionado. Los usuarios que utilizan el ordenador como pasatiempo dispondran de tiempo limitado para profundizar en el tema de la seguridad de sus sistemas o en aumentarla. Como la informaci6n que almacenardn en sus equipos es poco probable que interese a otros usuarios, 10s ataques seran poco frecuentes y el esfuerzo invertido en ellos serd limitado. Sin embargo, todos 10s usuarios de equipos con conexi6n a la red deberian tomar una serie dz precauciones ya que incluso 10s equipos con 10s datos menos interesantes pueden utilizarse como plataformas para lanzar ataques a otros sistemas. Los equipos militares son un objetivo obvio tanto para individuos como para gobiernos extranjeros. Para atacar a 10s gobiernos es necesario disponer de muchos medios, por lo que resulta aconsejable invertir en personal y otro tip0 de recursos para garantizar la aplicaci6n de todas las precauciones posibles. Si es responsable de un sitio de comercio electr6nic0, su atractivo para 10s piratas informdticos se situara entre estos dos extremos.
Amenazas contra la seguridad iCuAles son 10s riesgos que se ciernen sobre su sitio? iQu6 amenazas existen? En un capitulo anterior se analizaron algunas de las amenazas a las que se expone un comercio electr6nico. Muchas de ellas estan relacionadas con la seguridad.
Desarrollo Web con P H P y MySQL
Las amenazas variartin en funci6n del tip0 de sitio Web per0 se pueden citar las siguientes: '0
Exposici6n de datos confidenciales Pkrdida o destruccidn de datos Modificaci6n de datos Denegaci6n de servicio Errores en el software Repudio
En las siguientes secciones se analiza cada una de ellas.
Exposicion de datos confidenciales La informaci6n almacenada en 10s equipos, o la transmitida de un equipo a otro, puede ser confidencial. Podria tratarse de informaci6n destinada unicamente a determinadas personas, como listas de precios de mayoristas, informacidn suministrada por un cliente, como su contraseiia, datos de contact0 o el numero de una tarjeta de crkdito. No deberia guardar la informacidn que no desee compartir en su servidor Web. Los servidores Web no son el lugar m6s aconsejable en el que guardar informaci6n secreta. Si almacena 10s datos sobre su n6mina o su plan para la dominaci6n del mundo en un ordenador, procure que no sea el mismo que el utilizado como servidor Web. Los servidores Web son equipos diseiiados para su acceso publico por lo que s610 deberian contener informaci6n que se ofrezca publicamente o que se acabe de recoger del publico. Para reducir el riesgo de h exposici6n de datos, debe limitar 10s mktodos de acceso a la information y 10s usuarios que disponen de dicho acceso, lo cual implica desarrollar las labores de diseiio teniendo presente la seguridad, configurar el servidor y el software de manera correcta, programar con atencibn, realizar pruebas exhaustivas, eliminar 10s servicios innecesarios del servidor Web y exigir autenticaci6n. Diseiie, configure, codifique y pruebe atentamente su sitio Web para reducir 10s riesgos de un ataque y, lo que es m6s importante, para reducir la probabilidad de que un error exponga accidentalmente la informaci6n. Suprima 10s servicios innecesarios de su servidor Web para reducir el numero de puntos dkbiles potenciales. Cada servicio que estk ejecutando puede resultar vulnerable. Es necesario mantener todos 10s servicios actualizados para eliminar 10s puntos vulnerables conocidos. Los servicios no utilizados pueden resultar peligrosos. Si no utiliza el comando rcp, ,porquk tenerlo instalado? Si indica a1 instalador que su equipo es un host de red, las distribuciones mds importantes de Linux y Windows NT instalardn una gran cantidad de servicios que no necesita y que deberia eliminar.
13. Aspectos de seguridnd relncior~ndoscon el corncrcio electrdnico
La autenticacion implica solicitar a 10s usuarios que demuestren su identidad. Cuando un sistema sabe q u i h realiza una petition, puede decidir si dicha persona dispone de acceso. Existen varios m6todos d e autenticacion d e 10s cuales s61o se utilizan dos de forma generalizada: las contrasefias y las firmas digitales. Los analizaremos m i s adelante. CD Universe ofrece un buen ejemplo del coste, tanto en dinero como en reputation, clue supone permitir la exposici6n de information confidencial. A finales de 1999, un pirata informitico, que se hacia llamar Maxus, se puso en contacto con CD Universe para indicarles clue disponia d e 300.000 n6meros d e tarjetas d e cr6dito clue habia sustraido su sitio Web. Por la destruccion d e esta informacion pedi6 una recompensa que CD Universe se neg6 a pagar. Como resultado, CD Universe acabo en las primeras pdginas d e todos 10s peri6dicos d e mayor tirada cuando Maxus comenz6 a hacer p6blicos 10s numeros d e las tarjetas d e credit0 d e sus usuarios. Los datos tambien corren el riesgo d e exposici6n e n sus trayectos por la red. Las redes TCP/ IP incoryoran una gran cantidad de funciones clue han contribuido a convertirlas en el estandar d e facto para la conexi611 de diversas redes como Internet. Sin embargo, la seguridad no se incluye entre ellas. Los protocolos TCPJIP dividen 10s datos en paquetes y 10s reenvian de equipo en ecluipo hasta que alcanzan su destino. Por lo tanto, 10s datos pasaran a trav6s de una gran cantidad de ordenadores hasta llegar a su destinatario, como se ilustra en la figura 13.1, y cualquiera de ellas puede ver 10s datos en su transito.
Figura 13.1. Los datos enviados a traves de lnternet recorren una gran cantidad de equipos potencialrnente inseguros
Para ver la ruta que siguen 10s datos desde un equipo hasta el equipo d e destino, puede utilizar el comando t r a c e r o u t e (en un equipo UNIX). Este comando devuelve las direcciones de 10s ecluipos a travt;s d e 10s cuales han yasado 10s datos para alcanzar el host de destino. Si 10s datos van dirigidos a un ecluipo d e su propio pais, podrian atravesar una decena d e ecpipos diferentes. Si fueran destinados a un equipo situado fuera del pais, el numero de intermediarim podria superar la veintena. Si
Desarrollo Web can PHP y MySQL
su organizaci6n es de gran tamafio y consta de una red compleja, 10s datos podrian recorrer hasta cinco equipos antes de abandonar el edificio. Para proteger la informaci6n confidencial, puede cifrar 10s datos antes de enviarlos a travks de una red y descifrarlos en el otro extremo. Los servidores Web suelen utilizar el sistema SSL (Secure Socket Layer), desarrollado por Netscape para realizar esta tarea mientras 10s datos navegan entre 10s servidores Web y 10s navegadores. Se trata de una forma bastante barata en terminos de costes y de esfuerzos de proteger las transmisiones, per0 como el servidor necesita cifrar y descifrar 10s datos en lugar de enviarlos y recibirlos simplemente, el numero de visitantes por segundo a1 que puede dar servicio el equipo se reduce dristicamente.
Pbrdida o destruccion de datos La perdida de datos puede resultar mis costosa que su apropiaci6n indebida. Si lleva meses construyendo su sitio, recogiendo informaci6n sobre usuarios y pedidos, iseria capaz de determinar el coste, en tiempo, reputaci6n y dinero, resultante de perder toda esa informaci6n? Si no ha realizado ninguna copia de seguridad de esos datos, se veri obligado a volver a escribir el sitio Web y a comenzar desde cero. Un pirata informitico podria colarse en su sistema y formatear su disco duro. Tambikn podria ocurrir que un programador o un administrador poco atento eliminen el disco sin querer o que un disco se estropee. Los discos duros giran miles de veces por minuto y en ocasiones fallan. Segun la ley de Murphy, fallarii el disco m6s importante y mucho despues de realizar una copia de seguridad. Puede adoptar varias medidas para reducir la probabilidad de perder datos. Proteja sus servidores contra ataques informiticos. Reduzca a1 minimo 10s empleados con acceso a su equipo. Contrate unicamente personal competente y atento. Compre discos duros de calidad. Utilice la arquitectura RAID para permitir el uso de varios discos duros cqmo un disco miis ripido fiable. Independientemente del causante de las perdidas de datos 6 1 0 hay una forma de protecci6n real: las copias de seguridad. La realizaci6n de copias de seguridad no es exactamente una tarea divertida y con suerte no necesitarii recurrir a ellas, per0 su funci6n es vital. Asegurese de volcar sus datos de manera peri6dica y de probar el procedimiento para asegurarse de que resultan recuperables. Asegurese de almacenar las copias de seguridad lejos de 10s equipos habituales. Aunque es poco probable que 10s locales de su empresa se quemen o sufran alguna otra catistrofe, el almacenamiento de una copia de seguridad fuera de ellos es una medida de seguridad barata y eficaz.
Modificacion de 10s datos Aunque la perdida de 10s datos puede causar muchos daiios, su modificaci6n puede resultar aun peor. iQu6 ocurriria si alguien logra acceder a sus datos y 10s modifica? La eliminaci6n completa de 10s datos no tardaria mucho tiempo en detectarse, per0 preguntese cu6nto tiempo llevaria detectar su modificaci6n.
13. Aspectos de seguridad relacionados con el comercio electrdnico
Entre las formas de modificaci6n se incluyen cambios en 10s archivos de datos o ejecutables. La intenci6n de un pirata informtitico puede ser modificar el aspect0 de la Web u obtener beneficios fraudulentos. Mediante la sustituci6n de archivos ejecutables con versiones saboteadas, un pirata informatic0 que haya logrado entrar una vez en el sistema podria crear una puerta trasera secreta para futuras visitas. Puede proteger 10s datos contra su modificaci6n a1 viajar por la red mediante una firma. Esta tdcnica no impide la modificaci6n de 10s datos pero, si el receptor comprueba que la firma coincide a1 recibir 10s archivos, sabr6 que el archivo no se ha modificado. Si cifra 10s datos para protegerlos contra la visualizaci6n no autorizada, resultartin muy dificiles de modificar durante el trayecto sin su detecci6n. La protecci6n de 10s archivos almacenados en un servidor frente a su modificaci6n exige el uso de las funciones de permisos de acceso a archivos que incorpore su sistema operativo y protege el sistema de accesos no autorizados. La aplicaci6n de permisos de archivos permite autorizar el uso del sistema, pero no modificar 10s archivos del sistema ni de otros usuarios. La falta de un sistema de permisos es una de las razones que convertian a 10s sistemas operativos Windows 95 y Windows 98 en poco aptos para su uso con servidores. Detectar las modificaciones puede resultar dificil. Si descubrimos que alguien ha penetrado en nuestro sistema de seguridad jc6m0 podremos saber si se han modificad0 archivos importantes? Algunos archivos, como 10s archivos de datos que se almacenan en una base de datos, est6n ideados para cambiar con el paso del tiempo. Sin embargo, la intenci6n de otros es permanecer invariables desde su instalaci6n a menos que se actualicen deliberadamente. La modificaci6n de programas y datos puede resultar engafiosa, y aunque 10s programas puedan reinstalarse si se sospecha que han sido modificados, puede que no sepa qu6 versi6n de 10s datos estd "intacta". Existen aplicaciones que permiten comprobar la integridad de 10s archivos, como Tripware. Esta aplicaci6n regist& informaci6n sobre archivos en un estado seguro, probablemente inmediatamente despu6s de la instalacibn, y permite utilizarla en un momento posterior para verificar si 10s archivos han variado. Puede descargar la versi6n comercial o gratuita de
Errores en el software Es posible que el software que haya comprado, obtenido o escrito incluya errores graves. Dado 10s cortos plazos de desarrollo asignados a 10s proyectos Web, es muy probable que el software incluya errores. Todas las iniciativas comerciales basadas en procesos inform6ticos resultan vulnerable~a software con errores. Los errores en el software pueden causar todo tipo de comportamientos impredecibles incluida la indisponibilidad del servicio, lagunas de seguridad, perdidas financieras y servicios deficientes.
Desarrollo W e b con P H P y MySQL
Entre las causas habituales de 10s errores se pueden citar las malas especificaciones tbcnicas, suposiciones err6neas realizadas por 10s desarrolladores y pruebas incompletas.
Malas especificaciones t6cnicas Cuanto mds escasa y ambigua resulte su documentaci6n de disefio, mds probable es que el product0 final incluya errores. Aunque puede que resulte obvio especificar la anulaci6n de un pedido si se rechaza la tarjeta de crbdito de un cliente, puedo hablarles de un sitio con un alto presupuesto que incluia este error. Cuanta menos experiencia tengan 10s desarrolladores con el tip0 de sistemas con el que estdn trabajando, mds precisas deberian ser las especificaciones tbcnicas.
Suposiciones erroneas hechas por 10s desarrolladores Los disefiadores y 10s programadores de un sistema necesitan realizar una gran cantidad de suposiciones. Es de esperar que las documenten y que resulten acertadas. Sin embargo, las suposiciones pueden resultar err6neas. Por ejemplo, un desarrollador podria asumir que 10s datos de entrada serdn viilidos, que no incluiriin caracteres inusuales o que la cantidad de caracteres introducidos serii inferior a un tamafio dado. Tambibn podria asumir que no tendriin lugar dos acciones simultiineas que entren en conflict0 o que una tarea de procesamiento compleja lleve mds tiempo que una tarea sencilla. Suposiciones como bsta se pueden deslizar porque suelen ser ciertas. Un pirata informiitico puede aprovecharse de un desbordamiento de bufer generado por una suposicidn hecha por un programador con respecto a la longitud mdxima de 10s datos de entrada o un usuario legitimo puede obtener mensajes de error confusos o abandonar la visita porque a 10s desarrolladores no se les ocurri6 prever que el nombre de una persona pueda incluir un ap6strofe. Este tip0 de errores se pueden detectar y solucionar mepiante una combinaci6n de pruebas y revisi6n detallada del cbdigo. Histbricamente, el sistema operativo o las debilidades del nivel de aplicaci6n explotadas por 10s piratas informiitica se relacionan con 10s desbordamientos de b6fer o con 10s errores de sincronizaci6n.
Pruebas incompletas Resulta priicticamente imposible verificar todas las posibles entradas de 10s usuarios en todos dispositivos de hardware existentes, con todos 10s sistemas operativos posibles y utilizando todos 10s pariimetros de usuario disponibles. Esto es especialmente cierto en el caso de 10s sistemas basados en la Web. Es necesario implementar un plan de pruebas bien disefiado que verifique todas las funciones del software en un conjunto representativo de equipos. Un conjunto de pruebas bien planeado deberia probar todas las lineas de c6digo del proyecto a1 menos una vez. De manera ideal, estas pruebas deberian automatizarse para poder ejecutarlas en 10s equipos seleccionados con muy poco esfuerzo.
13. Aspectos de seguridad relacionados con el comercio electrdnico
El problema m6s importante de esta operation es que se trata de un trabajo repetitivo muy poco atractivo. Aunque hay gente a la que le gusta romper cosas, hay muy pocas a las que le guste romper la misma cosa una y otra vez. Es importante que en este proceso participen otras personas adem6s de 10s desarrolladores originales. Uno de 10s objetivos principales de las pruebas es detectar las suposiciones erroneas realizadas por 10s desarrolladores. Es probable que una persona no implicada realice suposiciones diferentes. Ademgs, 10s profesionales no suelen mostrarse muy inclinados a buscar errores dentro de su trabajo.
Repudio El ultimo riesgo que considerar es el repudio. El repudio tiene lugar cuando una parte implicada en una transaccion niega haber tomado parte en ella. En el comercio electronico puede tratarse de una persona que realice un pedido a travks del sitio Web y que rechace la autorizacion para realizar el cargo sobre su tarjeta de crkdito, o una persona que acepte algo procedente del correo electronic0 y que despuks afirme que alguien falsific6 dicho correo. De manera ideal, las transacciones financieras deberian garantizar la seguridad de que ninguna d e las partes las repudiar6. Ninguna parte podria denegar su participaci6n en una transaccion o, para ser m6s exacto, ambas partes podrian demostrar de manera terminante las acciones realizadas por la otra parte ante un tercero, como por ejemplo un tribunal. En la practica, esto no suele ocurrir. La autenticacion ofrece ciertas garantias sobre la parte con la que se esta tratando. Los certificados digitales d e autenticacion emitidos por una organization d e confianza brindan una gran fiabilidad. Tambikn deberian poder certificarse 10s contenidos d e lo mensajes enviados por cualquiera d e las partes. No sirve de mucho poder demostrar que Corp Pty Ltd nos ha enviado un mensaje si no p d e m o s probar que hemos recibido exactamente 10s que 10s han enviado. Como se indico anteriormente, la firma o el cifrado de 10s mensajes dificulta su alteracion de manera subrepticia. Para las transacciones entre las partes con una relacion ya establecida, 10s certificados digitales y el uso de comunicaciones cifradas o firmadas proporcionan una forma efectiva de limitar el repudio. Si las transacciones son aisladas, como el contact0 inicial entre un sitio d e comercio electronico y un usuario que utilice una tarjeta de crkdito, esta opci6n no resulta tan practica. Las compafiias de comercio electronico deben estar dispuestas a probar su identidad y a contratar 10s servicios de una autoridad de certification como VeriSign ( h t t p : //www.verisign. com/)oThawte(http: / / w w w . t h a w t e . com/)paragarantizar la autenticidad de la compafiia. iEstar6 dispuesta esa misma compafiia a rechazar a todos 10s clientes que no estkn dispuestos a adoptar la misma medida para demostrar su identidad? En las pequeiias transacciones, 10s comerciantes est6n dispuestos a admitir un determinado nivel de fraude o riesgo de repudio a cambio de mantener el nivel de transacciones.
Desarrollo Web con P H P y MySQL
Desde 1997 existe una alianza entre VISA, un determinado numero de organizaciones financieras y compaiiias de software para promover un estindar llamado SET (del ingl6s Secure Electronic Transaction, Transaccion electr6nica segura). Este sistema permite a 10s titulares de tarjetas de credit0 obtener certificados digitales de 10s emisores de sus tarjetas. Si esta iniciativa sigue adelante, podria reducirse el riesgo de repudio asi como otros tipos de fraude en las transacciones por Internet. Por desgracia, aunque la especificacion lleva en pie desde hace muchos aiios, parece que 10s bancos no se animan a emitir certificados compatibles con SET a 10s titulares de tarjetas. Los comerciantes no parecen dispuestos a rechazar a 10s clientes sin software SET y 10s usuarios muestran poco entusiasmo en adoptarlo. No hay muchas razones que obliguen a 10s clientes a hacer cola en sus bancos y a instalar el monedero digital en sus equipos si 10s comerciantes no van a rechazarlo si no lo utilizan.
Equilibrio entre usabilidad, rendimiento, coste y seguridad Por su propia naturaleza, la Web es un lugar peligroso. Este medio est6 diseiiado para permitir que numerosos usuarios soliciten servicios desde sus equipos. La mayor parte de estas peticiones realizan peticiones de p6ginas Web perfectamente legitimas, per0 a1 conectar sus equipos a Internet tambi6n existe la posibilidad de que la gente realice otros tipos de conexiones. Aunque resulta tentador asumir que es apropiado establecer el nivel de seguridad m6s alto, no suele ser asi. Si desea estar completamente protegido, tendr6 que colocar todos 10s equipos en una caja fuerte sin conexi6n a la red. Para que 10s equipos resulten accesibles y se puedan utilizar, es necesario rebajar el nivel de seguridad de alguna manera. Debemos buscar un equilibrio entre la seguridad, la usabilidad, el coste y el rendimiento. Si aumentamos la seguridad de un servicio podemos reducir su capacidad de uso, por ejemplo, a1 limitar lo que puede hacer la gente o pedir que se identifiquen. El increment0 de la seguridad tambi6n puede reducir el nivel de rendimiento de sus equipos. La ejecuci6n de software para lograr que el sistema resulte m6s seguro (corno sistemas de encriptaci6n y detecci6n de intrusos, escaneres de virus y operaciones de registro de usuarios) absorbe recursos. Se necesita mucho m6s potencial de procesamiento para suministrar una sesi6n cifrada, como una conexi6n SSL a un sitio Web, que una sesion normal. La p6rdida de rendimiento se puede compensar con la adquisici6n de equipos o hardware m6s r6pido que est6 especialmente diseiiado para operaciones de encriptaci6n. El rendimiento, la usabilidad, el coste y la seguridad se pueden considerar como objetivos contrapuestos. Deber6 examinar 10s pros y 10s contras de cada opci6n y tomar una decisi6n que logre un compromiso en funci6n del valor de la informaci6n, del presupuesto, de la cantidad de visitas esperadas y de 10s obst6culos que considere que aceptar6n 10s usuarios legitimos.
-
13. Aspectos de seguridad relacionados con el cornercio electro'nico
Creaci6n de una politica de seguridad Una politica de seguridad es un documento que describe La filosofia general sobre seguridad en su organizaci6n Quk se debe proteger: software, hardware y datos Quikn es responsable de la protecci6n de estos elementos Estindares de seguridad e indicadores para medir el cumplimiento de dichos est6ndares A la hora de desarrollar la politica de seguridad se pueden aplicar las mismas reglas utilizadas para escribir un conjunto de requisitos de software. En esta politica no deberia hablarse de implementaciones o soluciones, sin0 de requisitos de seguridad y de objetivos dentro del entorno. Y no deberia actualizarse a menudo. Deberia crear un documento en el que se establezcan las directrices utilizadas para medir el cumplimiento de la politica de seguridad en un entorno dado. Puede establecer directrices diferentes para las distintas partes de la organizaci6n. Seria como un documento de diseiio o un procedimiento manual en el que se recoja quk se est6 haciendo para garantizar el nivel de seguridad requerido.
Principios de autenticacion El objetivo de la autenticaci6n es demostrar que alguien es quikn dice ser. Existen muchas formas de suministrar autenticaci6n per0 como en el caso de muchas medidas de seguridad, cuanto m6s seguros son 10s mktodos m6s problem6ticos resultan de utilizar. Las tkcnicas de autenticaci61-1incluyen el uso de contraseiias, firmas digitales, medidas biomktricas mediante esc6neres de huellas y medidas que implican el uso de hardware como tarjetas inteligentes. En la Web s610 se utilizan dos de manera extendida: las contraseiias y las firmas digitales. Las medidas biomktricas y la mayor parte de las soluciones de hardware implican el uso de dispositivos de entrada especiales, lo que limitaria el acceso a aquellos usuarios autorizados con ordenadores equipados. Esta opci6n podria resultar aceptable o incluso deseable para obtener acceso a 10s sistemas internos de una organizacibn, per0 reduce gran parte de las ventajas de permitir el acceso a1 sistema en la Web. Las contraseiias resultan f6ciles de implementar, sencillas de utilizar y no requieren el uso de dispositivos de entrada especiales. Suministran un determinado nivel de autenticaci61-1per0 es posible que resulten insuficientes para sistemas de alta seguridad. El concept0 de una contraseiia es sencillo. El usuario y el sistema conocen la contraseiia. Si otro visitante afirma ser un usuario y conoce su contraseiia, el sistema
-
Desarrollo Web con P H P y MySQL
lo aceptard. Este sistema resulta seguro siempre y cuando nadie m i s sepa o pueda adivinar la contrasefia. Las contrasefias presentan en si mismas varios puntos dbbiles y no suministran autenticaci6n segura. Muchas contrasefias resultan f6ciles de averipar. Si permite que 10s usuarios seleccionen sus propias contrasefias, un 50% escogerd contrasefias fdciles de descubrir, como vocablos de un diccionario o el nombre de usuario. Puede obligar a 10s usuarios a incluir numeros o signos de puntuaci6n en sus contrasefias, aunque esta medida afectari a la usabilidad ya que 10s usuarios tendr6n dificultades para recordarlas. Otra opci6n consiste en mostrar a 10s usuarios c6mo seleccionar mejores contrasefias per0 de todas maneras el 25% de ellos seguir6 utilizando contrasefias sencillas de adivinar. Puede implementar politicas de contrasefias que impidan a 10s usuarios seleccionar combinaciones ficiles comparando las contrasefias introducidas con un diccionario o exigiendo el uso de n ~ m e r o os signos de puntuaci6n o una combinaci6n de letras en mayusculas y minusculas. El peligro de una politica de este tip0 es que 10s usuarios legitimos no logren recordar las contraseiias escogidas. Las contrasefias dificiles de recordar aumentan la probabilidad de que 10s usuarios realicen una acci6n poco segura como escribirlas en una nota y pegarla en sus monitores. Es necesario educar a 10s usuarios para que no escriban sus contrasefias ni las comuniquen por telbfono a alguien que afirme estar trabajando en el sistema. Las contrasefias s610 deberian capturarse electrbnicamente. Meditante el uso de programas para capturar pulsaciones del teclado en una terminal o la informaci6n que circula por la red, 10s piratas informdticos pueden capturar pares de nombres de usuario y contrasefias. Puede limitar las oportunidades de capturar contrasefias cifrando el trafico de red. A pesar de sus defectos potenciales, las contraseiias son una forma sencilla y relativamente efectiva de autenticar usuarios. Puede que el nivel de anonimato no resulte adecuado para la seguridad nacional, per0 son una soluci6n perfecta para comprobar el estado del pedido de un cliente.
a autenticacion P
La mayor parte de 10s navegadores y servidores Web incorporan mecanismos de autenticaci6n. Los servidores Web se pueden configurar para solicitar un nombre de usuario y una contrasefia para permitir el acceso a 10s archivos de determinados directorios del servidor. Cuando se necesite introducir u n numero de usuario y una contrasefia, el navegador presentard un cuadro de diilogo parecido a1 de la figura 13.2. Tanto Apache como el servidor IIS de Microsoft permiten proteger de manera sencilla una parte del sitio o el sitio en su totalidad de esta forma. PHP y MySQL incorporan muchas otras formas de lograr el mismo objetivo. MySQL resulta m6s r6pido que la autenticaci6n integrada. PHP suministra una autenticaci6n rnis flexible o presenta la solicitud de forma rnis atractiva.
Figura 13.2. Los navegadores Web solicitan a 10s usuarios que se autentiquen al
intentar visitar u n directorio de acceso restringido en u n servidor Web En u n capitulo posterior veremos algunos ejernplos d e autenticaci6n.
Un algoritmo cle e n c r i p t a c i h es un proceso matemfitico que transforma informacion en una cadena aparentemente aleatoria d e datos. Los datos d e 10s que se parte so11 texto sin procesar, aunque es importante para el proceso que represente la informaci6n (que se trate d e texto o d e otro tipo d e datos). La inforrnacion cifrada se conoce corno texto encriptado, aunque se parezca poco a un texto e n la mayor parte d e los casos. La figura 13.3 muestra el proceso d e encriptado e n forrna d e diagrama d e flujo. El texto que se desea cifrar se introduce en u n motor d e encriptacion, que podria ser un dispositivo mecinico, como 10s equipos Enigma d e la segunda guerra mundial, auque e n la actualidad presenta prficticamente siernpre el aspecto d e un programa informitico. El motor devuelve el texto encriptado. . -
Algor~tmo procesar
encr~ptac~dn
Texto c~frado
Figura 13.3. La encriptacion toma texto sin procesar y lo transforma en texto encriptado
Para crear el directorio protegido cuya solicitud d e autenticaci6n se muestra e n la figura 13.2, utilizamos el tipo d e autenticacion mds bdsica d e Apache. (En el siguiente capitulo le mostraremos ccirno utilizarlo). Este metodo cifra las contraseiias antes d e almacenarlas. Creamos un usuario con la contrasefia p a s s w o r d . 6sta se cifro y se almacenci como aWDuA3X3H. mc2.Como puede observar, el texto d e partida y la cadena cifrada n o se parecen en nada. Este sistema d e cifrado no es reversible. Muchas contrasefias se almacenan utilizando un algoritmo d e encriptaci61-1d e una sola direction. Para pocler determinar si una contraseiia introducida results correcta, no es necesario descifrar la contraseiia
Desarrollo W e b con P H P y MySQL
almacenada. En su lugar, bastar5 con cifrar la contraseiia introducida y compararla con la versi6n almacenada. Muchos procesos de encriptacion se pueden invertir, aunque no todos. El proceso inverso a1 encriptaci6n se conoce como decriptar. La figura 13.4 muestra un proceso de encriptacion de doble sentido.
Texto sin procesar
-
Algoritrno de encriptacibn
Algorltrno
Texto
Texto
de 4 sin + cifrado +decriptacibn procesar
-
Figura 13.4. El proceso de encriptacion toma texto sin procesar y lo transforma en texto cifrado con aspect0 aleatorio. El proceso de decriptado toma el texto encriptado y lo transforma en el texto de partida
La criptografia tiene unos 4000 afios de antigiiedad, per0 alcanz6 la mayoria de edad en la segunda guerra mundial. Su crecimiento desde entonces ha seguido de cerca a1 desarrollo de las redes de ordenadores. En un principio s610 era utilizada por las instituciones militares y organizaciones financieras. En 10s aiios 70 se extendi6 su uso y en 10s aiios 90 se hizo omnipresente. En 10s ultimos aiios, la encriptacih ha pasado de ser un concept0 que la gente s610 conocia por las peliculas de espias y de la segunda guerra mundial a convertirse en algo de lo que se habla en 10s peri6dicos y se utiliza cada vez que se compra algo a trav6s de navegadores Web. Existen muchos algoritmos de encriptaci6n disponibles. Algunos, como DES, utilizan una clave secreta o privada; otros, como RSA, utilizan una clave publica y una clave privada distinta.
Encriptacion de clave privada La encriptaci6n de clave privada se basa en usuarios autorizados que conocen o disponen de acceso a una clave. Esta clave debe mantenerse en secret0 ya que de lo contrario 10s mensajes cifrados podrian ser leidos por personas no autorizadas. Como se muestra en la figura 13.4, tanto el remitente (la persona que cifra el mensaje) como el receptor (el que descifra el mensaje) tienen la misma clave. El algoritmo de clave secreta mris utilizado es DES (del ingl6s Data Encryptation Standard, Est6ndar de encriptaci6n de datos). Este m6todo fue desarrollado por IBM en 10s afios 70 y fue adoptado como el esthdar americano para comunicacionescomerciales y gubernamentales no clasificadas. La velocidad de 10s ordenadores ha aumentado enormemente desde entonces y DES ha quedado obsoleto desde a1 menos 1998. Otros sistemas de claves secretas conkidos son RC2, RC4, RC5, triple DES e IDEA. El sistema triple DES resulta bastante seguro. Utiliza el mismo algoritmo que DES, per0 se aplica tres veces con hasta tres claves diferentes. El mensaje de texto se cifra con la primera clave, se descifra con la segunda y se vuelve a cifrar con la tercera.
13. Aspectos de seguridad relacionados con el comercio electrdnico
Uno de 10s defectos de la encriptacion con clave secreta es que para enviar un mensaje seguro a alguien, es necesario disponer de un forma segura de poderles enviar la clave secreta. Si dispone de una forma segura de enviar una clave, ipor qu6 no utilizarla para enviar el mensaje? Afortunadamente, en 1976 se produjo un avance significativo cuando Diffie y Hellman publicaron el primer m6todo de clave pfiblica.
Encriptacion de clave pu blica La encriptacion de clave publica se basa en dos claves, una clave publica y una clave privada. Como se ilustra en la figura 13.5, la clave publica se utiliza para cifrar mensajes y la clave privada para descifrarlos. La ventaja de este sistema es que la clave publica, como su nombre indica, se puede distribuir pGblicamente. Todo el mundo a1 que le entreguemos nuestra clave publica puede enviarnos un mensaje seguro. Mientras mantengamos en secret0 nuestra clave privada, s610 nosotros podremos descifrar el mensaje.
privada
Texto sin procesar
Algoritmo
de +encriptacibn
Texto cifrado
Texto Algoritmo de --) sin decriptacibn procesar
Figura 13.5. La encriptacion de clave publica utiliza claves distintas para cifrar y descifrar rnensajes
-
El algoritmo de clave pGblica mds utilizado es RSA, desarrollado por Rivest, Shamir
y Adelman en MIT y publicado en 1978. RSA era un sistema propietario per0 la patente vencid en septiembre de 2000. La capacidad para transmitir una clave ptiblica de forma abierta y sin necesidad de preocuparse por que resulte visible para una tercera parte supone una gran ventaja. Un sistema de clave publica se utiliza para transmitir la clave para un sistema de clave secreta que se utilizard durante el resto de una comunicacidn de sesidn. Esta complejidad aiiadida resulta tolerable porque 10s sistemas de clave secreta son unas 1000 veces mds rdpidos que 10s sistemas de clave publica.
Firmas dieitales Las firmas digitales estdn relacionados con la criptografia de clave publica, per0 invierten 10s papeles de las claves publicas y privadas. Un remitente puede cifrar y
Desarrollo Web con P H P y MySQL
firmar digitalmente un mensaje con su clave secreta. Cuando se recibe el mensaje, el receptor puede descifrarlo con la clave secreta del remitente. Como el remitente es la unica persona con acceso a la clave secreta, el receptor puede estar bastante seguro de la procedencia del mensaje y de que no se ha alterado. Las firmas digitales resultan muy 6tiles. Garantizan la procedencia de 10s mensajes y dificultan el rechazo del envio por parte del remitente. De todos modos, es importante tener en cuenta que aunque el mensaje se ha cifrado, cualquier persona que tenga la clave ptiblica puede leerlo. Si bien se utilizan las mismas tecnicas y claves, la finalidad del uso de la encriptaci6n en este caso es impedir la modificaci6n de 10s mensajes y su repudio, no su lectura. Como el cifrado de clave p6blica resulta bastante lento en el caso de mensajes de gran tamaiio, se suele utilizar otro tip0 de algoritmo, llamado funci6n hash, para mejorar la eficacia. La funcion hash calcula un mensaje implicito o valor hash para cualquier mensaje que se le indique. El valor generado por el algoritmo no es importante. Lo importante es que el resultado sea fijo, es decir, que sea el mismo cada vez que se utiliza una entrada dada, que sea pequeiio y que el algoritmo sea ri5pido. Las funciones hash m6s habituales son MD5 y SHA. Una funci6n hash genera un mensaje implicito que coincide con un mensaje dado. Si disponemos de ambos mensajes, podremos verificar si el texto se ha variado, siempre y cuando estemos seguros de que no se ha tocado el mensaje implicito. La forma mas habitual de crear una firma digital consiste en crear un mensaje implicito para todo el mensaje utilizando una funci6n hash ri5pida y, a continuacibn, cifrar unicamente el mensaje implicito utilizando una algoritmo de clave publica. Seguidamente se puede enviar la firma con el mensaje a traves de cualquier metodo normal no seguro. Cuando se recibe un mensaje, se puede realizar su comprobaci6n. La firma se descifrarii utilizando la clave ~ u b l i c adel remitente. Se genera un valor hash para el mensaje utilizando el misko metodo utilizado por el remitente. Si el valor hash descifrado coincide con el valor hash generado, podemos estar seguros de que el mensaje procede del remitente y no se ha alterado.
Certificados digitales La posibilidad de verificar que un mensaje no se ha alterado y que procede de un usuario o de un equipo dado es un gran avance. Para las interacciones comerciales, resultaria incluso mejor disponer de la posibilidad de vincular a dicho usuario o servidor a una entidad legal real como una persona o compaiiia. Un certificado digital combina una clave p6blica con 10s detalles de una organizaci6n o individuo en un formato digital firmado. En un certificado, nosotros tenemos la clave publica de la otra parte, por si queremos enviar un mensaje cifrado y tendremos 10s detalles de la otra parte, que podemos estar seguros de que no se han alterado.
El problema en este caso es que la fiabilidad de la informaci6n depende de lo fiable que sea el remitente ya que todo el mundo puede generar y firmar u11 certificado utilizando otra identidad. En las transacciones comerciales, resulta iltil utilizar una tercera parte d e confianza que acredite la identidad d e 10s participantes y 10s detalles d e s u s certificados. Estas terceras partes se conocen como CA (del inglks Certifying Authorities, Autoridades de certificacicin). Las autoridades de certificacion expiden certificados digitales a individuos y compafiias sujetas a una serie de comprobaciones de identidad. Las dos CA mAs conocidas son VeriSign ( h t t p : / / w w w . v e r i s i g n corn/) y Thawte ( h t t p : //www. t h a w t e . corn/), pero existen otras. VeriSign y Thawte pertenecen a la misma compariia y hay muy poca diferencia entre ambas. Algunas menos conocidas, como Equifax Secure (www .e q u i fa x s e c u r e . corn), resultan bastante m6s baratas. Las autoridades firman un certificado para acreditar que se ha comprobado la identidad d e una persona o compaiiia. Tenga en cuenta que el certificado no es una referencia ni una declaracion d e solvencia. No garantiza que se estA tratando con una entidad fiable. Lo Gnico clue garantiza es que en caso d e que nos engaiien, es probable que obtengamos una direccion fisica y una entidad o persona contra la que dirigir la demanda. Los certificados suministran una estructura d e confianza. Si confiamos en la CA, podemos confiar en aquellas partes en las que confia la CA y a su vez en aquellas partes e n las que confia la parte certificada. En la figura 13.6 se ilustra la ruta d e certificados que muestra Internet Explorer para un certificado concreto. En ella, pued e observar que www e q u i fa x s e c u r e . corn tiene un certificado emitido por Equifax Secure E-Business Certifying Authority. Esta CA, a s u vez, dispone d e un certificado emitido por Thawte Server Certifying Authority.
.
.
Figura 13.6. La ruta de certificados de www.equifaxsecure.com muestra la estructura de
confianza que perrnite confiar en este sitio
Desarrollo Web con PHP y MySQL
Los certificados digitales se suelen utilizar para conferir un aire de respetabilidad a1 sitio Web de un comercio electrhico. Con un certificado emitido por una CA conocida, 10s navegadores Web pueden establecer conexiones SSL a nuestro sitio sin generar cuadros de dialogo de advertencia. Los servidores Web que permite conexiones SSL se suelen llamar servidores Web seguros.
Servidores Web segu ros Puede utilizar el servidor Web Apache, el servidor IIS de Microsoft o cualquier otro servidor Web comercial para establecer comunicaciones seguras con navegadores a travbs de SSL. Apache permite utilizar un sistema operativo de tip0 UNIX, que suelen resultar mas fiables per0 m i s dificiles de configurar que 11s. El servidor Apache se puede utilizar en una plataforma Windows. El uso de SSL sobre IIS implica sencillamente instalar IIS, generar un par de claves e instalar el certificado. El uso de SSL en Apache requiere la instalacibn de tres paquetes diferentes: Apache, Mod-SSL y OpenSSL. Tambibn puede obtener lo mejor de 10s dos mundos comprando Stronghold. Stronghold es un producto comercial disponible desde www. c2 n e t por unos 1000 dblares. Esti basado en Apache per0 tiene forma de archivo binario autoinstalable y lleva preconfigurado el sistema SSL. De esta forma, se obtiene la fiabilidad de UNIX asi como un producto de facil instalacibn con asistencia tecnica del proveedor. Las instrucciones de instalacibn para 10s dos servidores Web m i s populares, Apache e IIS, se incluyen en el apbndice A. Puede comenzar a utilizar SSL de forma inmediata si genera sus propios certificados digitales per0 10s visitantes que acudan a su sitio recibirin una advertencia de sus navegadores indicandoles que hemos firmado nuestros propios-certi%cados. Para poder utilizar SSL con eficacia, necesitara un certificado publicado por una autoridad de certificacibn. El proceso exacto para lograrlo varia segun la autoridad de certificacibn, per0 por regla general deberi demostrar que su empresa esti reconocida legalmente, que consta de una direcci6n fisica y que es el titular del nombre de dominio pertinente. Necesitari generar una solicitud de firma de certificado. El proceso para lograrlo varia de un servidor a otro. Encontrari las instrucciones en 10s sitios Web de las autoridades de certificacibn. Stronghold e IIS incorporan un proceso basado en cuadros de dialogo mientras que Apache requiere la introduccibn de comandos. Sin embargo, el proceso es esencialmente el mismo para todos 10s servidores. El resultad0 final es una solicitud de firma de certificado (CSR) cifrada. Las CSR presentan un aspect0 parecido a1 siguiente:
.
B E G I N NEW CERTIFICATE REQIJEST--MIIBuwIBAAKBqQCLnlXX8faMtit~tzStp9wY6BVTPuEU9~pMmt~rb6vqaNZy4dTe6VS P4p7wGepq5CQ]fOL4Hjdatq12~~t08~~BkCDO98Xq9qP6CY45HZk+q6GyGOLZSOD 8cQHwhio~JP65s5Tz0180FB~pI3bHxfO6aYe~WYz~DiFKplBrUd~~at~~K4SQIVAPLH
13. Aspectos de seguridad relacionados con el comercio electrdnico
Tras adquirir la CSR, pagar la cuota correspondiente, conseguir la documentaci6n que prueba nuestra existencia y verificar que el nombre de dominio que estamos utilizando es el mismo que el incluido en la documentaci6n corporativa, estari en disposici6n de firmar un certificado con una autoridad de certificacibn. Cuando la autoridad de certificados emita el suyo, deberi almacenarlo en su sistema e indicarle a su servidor Web d6nde encontrarlo. El certificado finales un archivo de texto parecido a1 CSR mostrado anteriormente.
Auditorias y registros Su sistema operativo le permitiri registrar todo tip0 de eventos. Los eventos en 10s que puede estar interesado desde el punto de vista de la seguridad incluyen errores de red, acceso a archivos de datos concretos como 10s de configuraci6n o el registro de NT y llamadas a programas como su (que se utiliza para convertirse en otro usuario, por regla general el usuario raiz, en un sistema UNIX). Los archivos de registro pueden servir de ayuda para detectar comportamientos err6neos o malintencionados cuando tienen lugar. Tambikn se puede utilizar para determinar c6mo tuvo lugar un problema o una intrusidn si se examina tras observar problemas. Los archivos de registro presentan dos problemas principales: el tamafio y la veracidad. Si establece 10s criterios para detectar y registrar problemas en el nivel de mayor paranoia, terminari obteniendo registros gigantescos que resultan muy dificiles de examinar. Para trabajar con archivos de registro de gran tamafio, tendri que recurrir a una herramienta existente o derivar algunas secuencias d e comandos de la politica de seguridad establecida para realizar bdsquedas de eventos "interesantes" dentro de 10s registros. El proceso de auditar 10s registros puede realizarse en tiempo real o de manera peribdica. Los archivos de registros resultan vulnerables a ataques. Si un intruso dispone de acceso de usuario raiz o de administrador a nuestro sistema, podri alterar 10s archivos de registros para borrar sus huellas. Unix permite registrar eventos en un equipo diferente, lo que implica que el intruso deberi acceder a dos equipos a1 menos para cubrir sus huellas. NT dispone de funcionalidad similar, per0 no resulta tan sencilla de implementar. El administrador de sistema puede realizar auditorias peri6dicas, per0 ademis, podriamos contratar un servicio de auditorias externo para que controlara el comportamiento de 10s administradores.
-
Desarrollo Web con P H P y MySQL
Cortafuegos El objetivo de 10s cortafuegos es alejar una red del mundo exterior. De la misma forma que 10s cortafuegos de un edificio o de un coche impiden que el fuego se extienda a otros compartimentos, 10s cortafuegos de red impiden que el caos se extienda por una red. Los cortafuegos estin disefiados para proteger 10s equipos de una red del mundo exterior. Filtran y rechazan el trifico que no cumple las reglas establecidas en ellos. Restringe las actividades de la gente y de 10s equipo situados fuera del cortafuegos. En ocasiones, 10s cortafuegos tambien se pueden utilizar para restringir Tas actividades de 10s equipos incluidos en su interior. Un cortafuegos puede limitar 10s protocolos de red que se pueden utilizar, 10s hosts a 10s que se pueden conectar o forzar el uso de un servidor proxy para reducir costes en terminos de ancho de banda. Un contrafuegos puede ser un dispositivo de hardware, como un enrutador con reglas de filtrado o u n programa de software que se ejecute en un equipo. En cualquier caso, el cortafuegos necesita interfaces para las dos redes y un conjunto de reglas. Su misi6n consiste en supervisar todo el trifico que intenta pasar de una red a otra. Si el trifico cumple las reglas establecidas, serd dirigido a otra red; de lo contrario, se detendri o se rechazard. Los paquetes se pueden filtrar por su tipo, direcci6n de origen, direcci6n de destino o puerto. En algunos casos, 10s paquetes pueden rechazarse simplemente y en otros pueden desencadenar entradas en el registro o activar alarmas.
Copia de seguridad de 10s datos *
-
No se puede subestimar la importancia de las copias de seguridad en n i n g ~ n plan de recuperaci6n de desastres. El hardware y 10s inmuebles se puede asegurar y sustituir, o 10s sitios alojados en cualquier host, per0 si su software Web personal desaparece, ninguna entidad aseguradora podri sustituirlo. Debe hacer una copia de seguridad de todos 10s componentes de su sitio Web (pdginas estdticas, secuencias de comandos y bases de datos) peribdicamente. La frecuencia depende del dinamismo del sitio. Si se trata de un sitio completamente estitico, bastari con hacer una copia cuando se modifique. Sin embargo, el tip0 de sitios que estamos tratando en este libro es probable que cambien con frecuencia, en especial si se reciben pedidos en linea. La mayor parte de 10s sitios con un tamafio razonable deben alojarse en un servidor con sistema RAID (del ingles Redundant Array of Inexpensive Disks, Matriz redundante de discos independientes) que admiten funciones de replica. De esta forma, queda cubierta la probabilidad de que ocurra un fa110 en el disco duro. Considere, sin embargo, qu6 ocurriria en una situaci6n que afecta a la matriz, a1 equipo o a1 edificio entero.
13. Aspectos de seguridad relacionados con el cornercio electrdnico
La frecuencia con la que realizar 10s volcados de seguridad deberia corresponderse con el volumen de actualizaci6n. Estas copias de seguridad deberian almacenarse en un soporte diferente y a ser posible en un lugar distinto y seguro contra incendios, robos o desastres naturales. Existen muchas aplicaciones para realizar funciones de copia de seguridad y recuperaciones. En nuestro caso, nos centraremos en c6mo volcar un sitio construido con PHP y equipado de una base de datos MySQL.
Copia de seguridad de 10s archivos generales Los volcados de archivos HTML, PHP, imigenes y otros archivos que no Sean de base de datos se puede realizar con facilidad en la mayor parte de 10s sistemas utilizando software para la realizaci6n de copias de seguridad. Entre las herramientas gratuitas mas utilizadas se puede mencionar AMANDA desarrollada por la University of Maryland. Esta utilidad se incorpora en la mayor parte de las distribuciones de UNIX y tambien se puede utilizar para realizar copias de seguridad en equipos Windows a traves de SAMBA. Si desea saber mas sobre AMANDA, dirijase a
Copia de seguridad y restauracion de bases de datos
YSQL El proceso de volcado de seguridad de una base de datos en funcionamiento resulta mas complicado ya que no queremos copiar ningfin dato mientras la base de datos se estA modificando. En un capitulo anterio;encontrar~ instrucciones sobre c6mo volcar y restaurar una base de datos MySQL.
-
eguridad fisica Las amenazas de seguridad consideradas hasta el momento hacen referencia a elementos intangibles como el software, per0 no deberia descuidar la seguridad fisica de su sistema. Debe prever u n sistema de aire acondicionado y sistemas de protecci6n contra el fuego, personas (torpes o criminales), fallos en el suministro electric0 y fallos en la red. Su sistema deberia estar protegido bajo llave en un lugar seguro. El lugar concreto dependerd de cada caso per0 puede ser una habitacibn, una jaula o un armario. S610 se deberia conceder permiso de acceso a esta habitaci6n a1 personal pertinente. El personal no autorizado podria, voluntaria o involuntariamente, desconectar 10s cables o intentar eludir 10s mecanismos de seguridad utilizando un disco de reinicio.
Desarrollo Web con PHP y MySQL
Los rociadores de agua pueden causar tanto dafio a 10s componentes electr6nicos como el fuego. En el pasado, se utilizaron sistemas de extinci6n de incendios alimentados por gas hal6n para evitar este problema per0 en la actualidad la producci6n de este gas est6 prohibida por el Protocolo de Montreal sobre sustancias que reducen la capa de ozono, por lo que 10s sistemas para la extinci6n de incendios deben utilizar otras alternativas menos dafiinas como el gas arg6n o el di6xido de carbono. Puede leer m6s a1 respecto en
En determinados lugares, se producen breves cortes de fluido electr6nico de manera habitual. En sitios con climatologias extremas o cables enterrados se suelen producir cortes de fluido de larga duraci6n. Si el funcionamiento continuo del sistema es un factor importante deberia invertir en un SAI (sistema de alimentaci6n ininterrumpido). El coste de un SAI capaz de mantener el fluido electric0 para un equipo durante 10 minutos asciende a nos 300 d6lares. Si se necesita un sistema para cubrir cortes de suministro m i s largos o mas equipos, el coste se elevar6. Los cortes de suministro de larga duraci6n requieren un generador que alimente el sistema de refrigeration y 10s equipos. A1 igual que 10s fallos de suministro elkctrico, 10s fallos de red, que pueden durar minutos o horas, quedan fuera de nuestro control y se producen irremediablemente de tiempo en tiempo. Si el mantenimiento de la red es vital, es aconsejable contratar 10s servicios de varios proveedores de servicios. El coste ser6 superior, per0 en caso de fallo, su sitio seguir6 siendo visible, aunque se vea afectada su capacidad. Este tip0 de cuestiones podrian llevarle a considerar la opci6n de ubicar sus equipos dentro de una infraestructura dedicada. En u n negocio de tamafio medio puede que no resulte justificable el uso de u n SAI que mantenga el fluido electrico durante varios minutos, varias conexiones de red redundantes y sistemas antiincendios. Sin embargo, en una infraestructqa de calidad en la que se alojen cientos de equipos similares si resultaria justificable.
En el siguiente capitulo, nos centraremos de manera especifica en la autenticaci6n, funci6n que permite a 10s usuarios acreditar su identidad. Examinaremos varios metodos diferentes, incluido el uso de PHP y MySQL para autenticar a nuestros visitantes.
En este capitulo veremos c6mo implementar varias tdcnicas de PHP y MySQL para autenticar a un usuario. Entre 10s aspectos que analizaremos se incluyen 10s siguientes: Identificaci6n de visitantes
-
Jmplementaci6n del control de acceso Autenticaci6n b6sica
-
Uso de la autenticaci6n b6sica de PHP Uso de la autenticaci6n b6sica .htaccess de Apache Uso de la autenticaci6n b6sica con IIS Uso de la autenticaci6n con mod-a u t h -mysql Creaci6n de procesos de autenticaci61-1personalizados
Identificaci6n de visitantes La Web es un medio relativamente an6nim0, per0 a menudo resulta util saber quidn est6 visitando nuestro sitio. Afortunadamente para la privacidad de 10s visitantes, 10s datos que se pueden obtener sin su colaboraci6n son bastante escasos.
14. Implementacidn de la autenticacidn con PHP y MySQL
Con un poco de trabajo, 10s servidores pueden averiguar bastantes datos sobre 10s equipos y las redes que se conectan a ellos. Los navegadores suelen identificarse, para lo cual indican a1 servidor qu6 navegador, versi6n y sistema operativo se est6 utilizando. Se puede determinar qu6 resolucidn y profundidad de color est6 utilizando el visitante en su pantalla asi como el tamaiio asignado a la ventana del navegador Web. Cada equipo que se conecta a Internet tiene una direcci6n IP exclusiva. Esta direcci6n permite deducir algunos datos sobre el visitante. Se puede determinar a qui6n pertenece la IP y, aproximadamente, la ubicaci6n geogrifica del visitante. Algunas direcciones resultan m6s 6tiles que otras. Por regla general, 10s usuarios con conexiones permanentes a Internet tendr6n una direcci6n permanente. A 10s clientes que llamen a un proveedor de acceso a Internet se les suelen asignar direcciones para su uso temporal. Si vuelve a ver dicha direcci6n es probable que est6 siendo utilizada por un equipo distinto y si vuelve a encontrar a1 visitante es probable que est6 utilizando una direcci6n IP diferente. Por suerte para 10s usuarios Web, ninguno de 10s datos que ofrece el navegador sirve para identificarles. Si desea saber el nombre u otra informaci6n sobre un visitante, tendrd que preguntarles. Muchos sitios Web utilizan razones convincentes para obtener datos de 10s usuarios. El New York Times (ht tp : //www. nyt i m e s . corn) ofrece su contenido gratis per0 s610 a aquellas personas que est6n dispuestas a suministrar datos como su nombre, sex0 e ingresos. El sitio Slashdot (http : / / www. slashdot. org) permite a 10s usuarios registrados participar en 10s debates con un apodo y personalizar la interfaz que ven. La mayor parte de 10s sitios de comercio electr6nico registran informaci6n sobre sus usuarios cuando realizan el primer pedido. De esta forma no tendr6n que volver a hacerlo en 10s pedidos siguientes. Tras solicitar y recabarinfor'maci6n de 10s visitantes, necesitamos una forma de asociar dicha informacidn con sus usuarios correspondientes cuando vuelvan a visitarnos. Si partimos del supuesto de que cada persona visitar6 su sitio desde una cuenta determinada y desde un equipo dado, y que cada visitante utiliza 6nicamente un equipo, podemos almacenar una cookie en el equipo del usuario para identificarle. Sin embargo, no ocurre siempre es asi. Con frecuencia, la gente comparte un equipo y muchos usuarios utilizan varios equipos para navegar. Por lo tanto, no quedar6 m6s remedio que preguntar a1 visitante qui6n es de nuevo. Ademis de solicitar que se identifique, tendr6 que pedirle alguna prueba que confirme que es qui6n dice ser. Como se indicd en un capitulo anterior el proceso de pedir a 10s usuarios que demuestren su identidad se conoce como autenticaci6n. El metodo habitual de autenticaci6n utilizado en 10s sitios Web consiste en pedir a 10s usuarios que introduzcan un nombre de usuario y una contraseiia. El proceso de autenticaci6n se suele utilizar para conceder o rechazar el acceso a p6ginas o recursos concretos, per0 puede resultar adecuado o 6til para otros fines como la personalizaci6n.
Desnrrdlo Web con PHP y MySQL
Un control de acceso sencillo no resulta dificil de implementar. El codigo incluido en el listado 14.1 devuelve tres posibles resultados. Si el archivo se carga sin parimetros, mostrari un formulario HMTL solicitando un nombre de usuario y una contrasetia. En la figura 14.1 se muestra este tip0 d e formulario.
Archm Ediabn Ver Favorms .Herramienbs Ayuda ~~~~
-
-.
(an ~ p - l ~ ~ ~ t .
O~reccibn
c ~ ~ s : i i i ~ ~ : ~ ~ ~ l ~ / s ~ r , c ~
Please Log In
-
Figura 14.1. Nuestro formulario HTML pide a 10s visitantes que introduzcan un nombre de usuario y una contrasetia para poder acceder
Si se han introducido 10s par6metros pero no son correctos, se mostrari un mensaje de error. En a1 figura 14.2 se muestra dicho mensaje.
Figura 14.2. Cuando 10s usuarios introducen inforrnacion incorrecta, tenernos que devolver un mensaje de error
Si 10s parimetros se han introducido y son correctos, se mostrari el contenido secreto, coino se ilustra en la figura 14.3.
El c6digo para crear la funcionalidad ilustrada en las figuras 14.1, 14.2 y 14.3 se muestra en el listado 14.1.
Archwu Ed1u6n Ver Fsvonloe Herrarn~entas A p d a Dmmbn k 1 hm / / W ~ S C I Y C ~ / Cll~
4 / ~ u eoh2 1
.I
I
?
Here it is! I bet you are glad you can see this secret page
Figura 14.3. Cuando se introducen 10s detalles correctos, la secuencia de comandos muestra el contenido. Listado 14.1. secret.php. Codigo PHP y HTML para proporcionar un sencillo mecanismo de autenticacion
Desarrollo W e b con PHP y MySQL 1 else if($name=='user'&&$password=='pass')
t / / el nombre y la contrasetia del visitante son correctos echo 'Here it is!'; echo 'I bet you are glad you can see this secret page.';
I else i / I el nombre y la contrasetia del visitante no son correctos echo 'Go Away!'; echo 'You are not authorized to view this resource.';
I ?>
El codigo del listado 14.1 constituye un sencillo mecanismo de autenticacion para conceder acceso a una piigina a 10s usuarios autorizados, per0 presenta algunos problemas importantes. Esta secuencia de comandos Incluye un nombre de usuario y una contraseiia en su interior Almacena la contraseiia en forma de texto sin procesar S610 protege una piigina Transmite la contraseiia en forma de texto sin procesar Estas cuestiones se pueden resolver con diferentes grados de esfuerzo y exito.
Almacenamiento de contrasenas Existen muchos lugares en 10s que almacenar nombres de usuario y contraseiias mejores que dentro de urta sehencia de comandos. Los datos introducidos dentro de una secuencia de comandos resultan dificiles de modificar. Se podria escribir una secuencia de comandos que se modificara a si misma per0 no es una buena idea ya que supondria tener una secuencia de comandos en el servidor, que se ejecutaria en 61 per0 que otros podrian modificar o escribir sobre ella. Si almacenamos 10s datos en otro archivo dentro del servidor resultarii miis sencillo escribir un programa para agregar y eliminar usuarios y alterar contraseiias. El uso de secuencias de comandos u otros archivos de datos con funciones de almacenamiento presenta un limite en cuanto a1 numero de usuarios que se pueden incluir sin que se vea afectada la velocidad de la secuencia de comandos. Si tiene previsto almacenar y realizar busquedas en un archivo con una gran cantidad de elementos, deberia considerar la opci6n de utilizar una base de datos, como se coment6 anteriormente. Como regla, si el numero de elementos que necesita almacenar y buscar supera 10s 100, utilice una base de datos en lugar de un archivo. El uso de una base de datos para almacenar nombres de usuario y contraseiias complicarii la secuencia de comandos, per0 a cambio permitirii autenticar a muchos
14. Implementacio'n de la autenticacidn con PHP y M y S Q L
usuarios riipidamente. Tambikn permitirii escribir con facilidad una secuencia de comandos para agregar nuevos usuarios, para eliminar usuarios y para permitir que 10s usuarios cambien sus contrasefias. En el listado 14.2 se incluye una secuencia de comandos para autenticar visitantes utilizando una base de datos. Listado 14.2. secretdb.php. Hemos utilizado MySQL para mejorar nuestro sencillo
mecanismo de autenticacion
if(!isset($HTTP~POST~VARS['r1ame'])&&!isset($l4TTP-POST-VARS['password'])) i //El
v i s i t a n t e t i e n e q u e i n t r o d u c i r un nornbre y una c o n t r a s e A a
?>
< h l > P l e a s e Lcy Ini/hl> T h i s page i s s e c r e t . | | |