You are on page 1of 77
ses Los secretos de PHP om Nimero 30 =Los secretos de PHP y MYSQL 5,00 EUR. y MYSQL g0030 3 AN 54 in 2) PC Cuadernos PHP y MySQL Johann-Christian Hanke © Copyright: KnowWare EURL Traduccién: Victoria Mengual PC Cuadernos - Basicos www.pe-cuadernos.com Sociedad editora: KnowWare E.UR.L. 70, rue Georges Villette F-77250 Ecuelles Francia Director: Mikkel Franck Direccién electrénic: info@pe-cuadernos.com Depésito legal: 8-22770-2006 ISBN: 2-915605-46-7 Imprenta: Imprintsa impressions intercomarcals, S.A. Sant Fruités de Bages, Barcelona Distribucién quioscos: Coedis S.L. Avda. de Barcelona, 225 Molins de Rei Barcelona Venta por numeros: Después de su aparicion, los nuimeros de esta coleccién pueden pedirse por correo. | (Consulta la pagina 77) - Secretosde Con “Secretos de PHP y MySQL”, Johann- Christian Hanke nos trae la continuacién del cuaderno “PHP 5" publicado anteriormente. En este nuevo titulo, el autor va mas alla en sus explicaciones y explora el verdadero po- tencial del lenguaje PHP cuando se utiliza en combinacién con bases de datos. EI cuaderno empieza repasando los cam- bios de sintaxis en las ultimas versiones de PHP, hablando de las funciones propias y de trucos de notacién que facilitan las cosas al programador, ademas de presentar la forma de vincular archivos con el comando inclu- de. Desde el punto de vista practico, apren- derds a cargar archivos a una pagina web con ayuda de PHP. Los siguientes capitulos se centran en co- nocer MySQL, la interfaz PHPMyAdmin y los principales comandos SQL para consultar, modificar, filtrar y eliminar tablas de bases de datos. El autor incluye también una lista con los principales tipos de datos y presenta las distintas formas posibles de mostrar los datos como HTML. Todo ello, sin olvidarse de los formularios como herramienta para introducit datos y del procedimiento para crear copias de Seguridad de tablas. Al final del cuaderno se presentan dos pro- yectos sumamente interesantes: un script para enviar automaticamente felicitaciones de cumpleafios a tus conocidos (utilizando un eronjob), y un completo proyecto para un libro de visitas con fotografias, que se puede modificar facilmente para convertirlo en un fotoblog o un sistema de gestion de conte- nidos. Mikkel Franck, editor. mfranck@po-cuadernos.com Todos los productos citados en este manual son ‘marcas registradas o marcas comerciales. El au- tory el editor declinan toda responsabilidad que pueda surgir de Ia utilizacién de los datos 0 pro- gramas que aparecen en este libro. Bienvenido al mundo de los sitios web dinamicos 3 Bienvenido al mundo de los sitios web dinamicos Eneste cuademo seguiremos profundizando en PHP. Por fin esta aqui la esperada segunda parte de mi cuaderno titulado “PHP 5”. A todos y to- das, bienvenidos, y me alegro de que este tema siga despertando vuestra curiosidad e interés. le qué trata el cuaderno’ Como no podia ser de otra forma, este cuaderno trata sobre PHP y MySQL. Te sonar a mucha préctica, y de eso se trata precisamente. Pero como siempre, antes de la practica dte ofreceré tuna raci6n de teoria. Técnicas avanzadas de PHP En la primera parte del cuademno, hablaremos de determinadas técnicas de programacién avan- zadas, Entre otras cosas, veremos: Nueva sintaxis desde PHP 4.2 ‘Cémo escribir tus propias funciones Separacién de médulos mediante include() Métodos para que el cédigo sea més legible Después de ocupamos de esto, iremos al grano. Nos pondremos con el tan esperado... Curso sobre MySQL y SQL Hablaremos de cémo configurar y utilizar MySQL en tu proveedor de hosting, y c6mo ma- nejar bases de datos (0 base de datos, ya que al- gunos proveedores solamente permiten usar una). Y le seguirdn los ejemplos. Pero antes de poner- nos con el primer ejemplo practico de base de datos, también es necesario un poco de teoria. Aprenderés SQL, el lenguaje para crear, mante- ner y consultar tablas de bases de datos. Con ayuda de una libreta de direcciones, te mostraré como: * Crear tablas de una base de datos * Introducir datos + Presentar las filas deseadas * Incluir comandos SQL en PHP 2 la préctica? En este caso he pensado que te gustaria un libro de visitas realmente comodo: con campo para incluir una fotografia, bloqueo contra reload y presentaci6n de los datos por paginas. También se puede utilizar como siste- ma de gestion de contenidos, weblog o fotoblog. Como calentamiento te presentaré un pequefto “script de cumpleaitos” que enviara automati- camente a todos tus contactos una felicitacién electrénica por su cumpleafios. Los limites del cuaderno -» Se encuentran en el disefio de bases de datos telacionales, es decir, la vinculacién de varias ta~ blas para hacer que el almacenamiento de datos sea més efectivo. Hablaremos de ello por encima de forma muy didéctica y comprensible. Después te remitiré a otra autora, Petra Bilke. El motivo es que Petra ofrece en su cuaderno sobre “PHP y MySQL", publicado anteriormente, una introduccién detallada a esta materia, y repetir Jo mismo serfa como llevar lea al monte. ST cml g No soy ningtin programador genial, sino auto- didacta. Sin embargo, la programacin es mi afi- ci6n, a la que he dedicado muchas, muchas no- ches y fines de semana. Puedes encontrar un ejemplo en la pagina alemana www.phpkid.de, la primera que logré crear controlada exclusiva- mente con bases de datos. Ena “concepcién” de este portal aprend{ mu- chisimo, y estoy orgulloso de poder transmitir los conocimientos adquiridos. Te deseo todo el éxito del mundo con “Secretos de PHP y MySQL”. a Bienvenido al mundo de los sitios web dinamicos Descarga de los archivos de ejemplo Encontrards los archivos de ejemplos del cua- derno en el suplemento gratuito que se puede descargar en linea desde: I 000 femos. Johann-Christian Hanke Lanueva sintaxis de PHP 5 La nueva sintaxis de PHP desde la version 4.1 6 4.2 {Qué pena! Asi describiria yo la aparicién de la primera edicién alemana del cuaderno “Intro- duccion a PHP”, que terminé de redactarse en abril de 2002, La tiltima version de PHP en esa €poca era la 4.1, y cuando se publicé el cuader- no, todo parecfa ir bien. Sin embargo, poco después de la aparicién de ese titulo (en junio de 2002) aparecié una version totalmente nueva de PHP: la conocida versién 4.2. ,Cémo lo supe? Por los muchos lectores que ‘me enviaron sus quejas por correo electrénico, diciendo que todos los ejemplos a partir del ca- pitulo 5 ya no funcionaban. ;Qué habia ocurri- do? En lugar de register_globals = on, la opcién predefinida pas6 a ser register_globals = off. Ergo: la mayoria de scripts dejaron de funcionar. Esta verdad solamente es aplicable en el caso de una instalacién offline, por ejemplo, cuando se trabaja a mano o con FoxServ. Por suerte, pronto pude tranquilizar a mis lecto- res, Todos los ejemplos del cuademno eran y si- guen siendo validos, siempre que se vuelva a modificar la variable. En la segunda edicién alemana del cuaderno de principios de 2003, in- cluf una nota sobre este problema, en la que re~ comendaba volver a cambiar la variable de C:\Windows\ php.ini a On: Pee Yer Sy 7 2 Qgad 2c soa meleiaa a Ale 7 register_globals co be an; using fore variables fa ghobals can cantly ead TcSiprsinie sacrtty probe, the cote fs et i thee oor ko vaca se ot6-tye Sot Liopors Sr Sos educa i yeu En aquel entonces, el archivo php.ini se solia encon- trar en C:\Windows; pero si trabajas con la herra- mienta de instalacin XAMPP presentada aqui, lo encontrards en xampp/apache/bin. Incluso el propio XAMPP antepone la comodi- dada la seguridad y no quiere molestar a los ‘usuarios. En todas las versiones que he podido probar, siempre se mantiene en “On”. TUE ean eCémo esté configurado register_globals en tu servidor local, o en tu proveedor? Compruébalo utilizando la conocida funcién phpinfo().Como recordatorio: crea un documento con el siguiente contenido, guardalo como info.php y colécalo en a carpeta raiz del servidor local o en tu pagina web: Se podia consultar de esta forma: echo "$Nonbre", ‘ami sitio\n"; bienvenido & La nueva sintaxis de PHP No importaba si el formulario se enviaba por method="post" 0 method="get". Incluso era po- sible determinar el valor de las cookies utilizan- do el nombre de las mismas. Una cookie llamada nombre se convertia en una variable llamada $nombre. Admito que esta forma de escribir era y es muy comoda. ;Demasiado cémodal De un lado, es posible que cree confusion, Imagina que has creado un campo de formulario llamado name, y casualmente tienes una cookie con el mismo nombre en el cédigo fuente. En ese caso, a través de $name se accederé tanto al contenido del campo de formulario como al valor de la cookie. ¢Quién ganaré? Dependerd del script. Es cierto que podriamos ahorrarnos todos estos problemas desde el principio. Basta con asignar una abreviatura s6lo a las cookies 0 a los campos de formulario. Cédigo fuente del archivo inseguro.php Observa el cédigo que aparece a continuacién. Copialo y guardalo como inseguro.php. Abre el archivo en el navegador (Naturalmente, para que el ejemplo funcione, asumo que register_globals sigue todavia en On en tu servidor local). <{DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN*> chead> * one/ha> hp"; 2>" method="post "> ame="pasa"> La nueva sintaxis de PHP 7 } Resumen del cédigo fuente Estoy trabajando con la variable Slogin. Su valor deberia ser txue sélo si se conoce la contrasefia correcta. if (Spas Slogin ) Desafortunadamente, no he inicializado la va- riable con false desde el principio. Por causa de esta pequefio descuido en el cOdigo es posible que cualquiera que no conozea la contrasefia vea lo queno deberia ver, ,C6mo? Solo tendria que agregar 7login=true o ?login=1 a Ia URL. Porque 1 significa true. En ese caso, la variable Slogin pasaria a ser true y se abriria la “puerta” al 4rea secreta. "abe_xy2_123") { true; Pruébalo: abre el archivo inseguro.php escribien- do: inseguro.php?iegine1! Podemos entrar sin saber la contrasefia. Matrices $ POST y $_GET Los creadores de PHP reconocieron este proble- ma de seguridad, y lo solucionaron con PHP 4.1: * Todos los datos de formularios enviados me- diante method="post” se guardan en la array, $_POST. * Los datos de method="get” se almacenan en la array $_GET. Entre ellos también se cuentan Jos pardmetros transmitidos a través de la URL. Si deseamos acceder al valor de “?login=true” aftadido a la URL, s6lo podremos hacerlo desde: $_GeT{ Login] . Por lo tanto, esta es la variante més segura, y por ese motivo deberfas dejar definitivamente regis- ter_globals en Off . Establecer register_globals en off En este curso, te recomiendo sin dudarlo que trabajes siempre con register_globals desactivado. Sélo tienes que cambiar el valor en el archivo php.ini a Off. .Cémo puedes hacerlo? En primer lugar, comprueba dénde se en- cuentra php.ini. XAMPP no utiliza la ruta CA Windows, sino una ruta de acceso propia. > php.ini 2. XAMPP suede utilizar, por ejemplo, CA xamppi(ite)\apache\bin\ php.ini, Detén el servicio XAMPP y abre el archivo php.ini. 3, Busca la linea register_globals = On (no tiene que tener un punto y coma delante, ya que punto y coma equivale a comentar el c6di- 80). 4, Sustituye On por Offy guarda el archivo ini. Inicia otra vez XAMPP y comprueba la con- figuraci6n, Prueba nuevamente el truco de login. Ya no fun- ciona, de modo que hemos cerrado el agujero de seguridad, Desde 2003 ya se hablaba mucho de PHP 5. De echo, los primeros libros sobre PHP 5 aparecie- ron mucho antes de que surgiera PHP 5. Sin embargo, las capacidades mejoradas (pero no necesariamente suficientes) en relacién con la programacién orientada a objetos slo son inte- resantes para verdaderos expertos. PHP es un lenguaje de scripts. En nuestro caso, el trabajo orientado a objetos seria como disparar a go- riones con cafiones. Y, teniendo en cuenta que la mayoria de proveedores siempre van por detras de las tiltimas versiones con meses 0 incluso afios de retraso, personalmente actuaria con pru- dencia. 8 La nueva sintaxis de PHP Las novedades realmente interesantes para la gente que se inicia en la programacién se intro- dujeron en la versin PHP 41. A partir de esta versi6n, ademas de las arrays ya mencionadas $_POST y $_GET también se presentaron las arrays asociativas: $_COOKIE Esta array contiene todas las variables de una ‘cookie. Con $_COOKIE{ visita'] podemos deter- minar, por ejemplo, el valor de la cookie visita $_REQUEST Esta array juega un papel especial. Contiene to- dos los valores de $_POST, $_GET y $_COOKIE. Puede resultar practico cuando el script recibe tanto datos procedentes de un formulario como datos que hayan sido transmitidos mediante un pardmetro de la URL de la pagina anterior. Por tanto, podriamos acceder al valor del campo de formulario tanto si el formulario se envia mediante nethod="post" como method="get". Sin embargo, soy muy prudente en el uso de $_REQUEST, ya que suele limitar ligeramente los esfuerzos para un mayor “orden”. ‘También son nuevas las variables de arrays $_SERVER, $_ENV y $_SESSION. $_ENV es res- ponsable de las variables de entorno y $_SESSION se encarga de la gestién de sesiones. Hablaremos de las sesiones en un futuro tercer cuaderno dedicado a PHP. La variable $_ SERVER Sin duda, la més interesante es la variable $_SERVER, ya que contiene todas las variables de servidor, es decir, todas las variables que transmite el servidor web. El servidor transmite todas las que se pueden reconocer con la funcion phpinfo(). A nosotros nos interesan sobre todo el nombre de archivo y la ruta de acceso. Anteriormente, cuando queriamos determinar la ruta y el nombre de un archivo, escribfamos $PHP_SELE Segtin la nueva sintaxis, ahora s6lo se puede acceder a este valor mediante $.SERVER[PHP_SELF]. Clee a ML) Chany La préctica hace al maestro, asi que a continua- ci6n te propongo un par de ejercicios. '@ Ejercicio 1: variable de servidor Integra la variable de servidor $_SERVER['PHP_SELF] en el archivo insegu- ro.php y sustituye la variable $pass por la varian- te $_POST. Encontrarés mi solucién en insegu- ro2.php. ® Ejercicio 2: comparacién en cédigo fuente ‘Compara ambas variantes; la que indica direc- tamente el nombre del archivo y la que utiliza la variable de servidor. Analiza el cédigo fuente de Ja pagina generada por el servidor. El servidor web siempre envia un archivo HTML al navegador; en oano buscarts los comandos de PHP. Qué diferencia puedes observar? @ Ejercicio 3: inicializar variables Arregla mis chapuzas del ejemplo “inseguro”. Asegtirate de que no quede ninguna puerta abierta a los mirones, incluso aunque regis- ter_globals esté activado. Encontrarés la solucién en el archivo inseguro3.php. Trucos de notacién 9 Trucos de notaci6n que hacen la vida mas facil con PHP @Puedo confesarte algo? En la escuela me consi- deraban un bicho raro. En lugar de ir a la disco- teca, iba a clase de miisica, y en lugar de por el fatbol, me interesaba por la arquitectura, la lite- ratura y la fotografia. Si todo el mundo crefa que solamente A podia ser correcto, yo me obstinaba ‘en buscar una alternativa llamada Bo C que tu- viera exactamente el mismo resultado. De forma parecida me sentf con PHP cuando ocurrié todo el tema de “register_globals = Off” y el cambio a la nueva sintaxis. No podia con- formarme con la idea de que la notacién me- dante las arrays $_POST, $_GET 0 § REQUEST tuviera que volverse tan complicada. ‘Te mostraré un par de trucos que he descubierto mediante prueba y error. Pocas veces los encon- trards en los libros para principiantes o en los scripts de muestra de Internet, donde suele pre- dominar la forma de escritura “complicada” Pero, por lo que puedo ver, mis trucos son fia~ bles y, ante todo, funcionan de primera. Ademés, no provocan ningtin mensaje de error. RUE ey Aprimera vista, la escritura mediante la nueva sintaxis de arrays se vuelve més complicada. Se- gin la antigua sintaxis, podriamos acceder al si- guiente campo de formulario ‘ : de forma simple y sencilla, y seguir trabajando con él: ‘echo "cla $Nombre1"; ‘No era necesario concatenar las strings con las. variables. Era un idilio perfecto: texto, etiquetas HTML y variable, todo unido mediante un solo par de comillas. Conforme a la nueva sintaxis, las cosas ya no son tan sencillas. Prueba el siguiente c6digo y quedaras admirado: echo "Hola $_POST['Nombre!) 1"; No se muestra el contenido de la variable, sino la string $_POSTI’Nombre']. No sirve de nada tomar en consideracién la regla de utilizar comi- llas desiguales cuando se anidan varias comillas. Para la clave de la array utilicé a propésito comi- llas simples, y las dobles tinicamente fuera. Pero no me sirvi6 de nada. Hay que concatenarlas. echo "Hola " , $_POST['Nombre'] . Nefboi"; {Qué complicado! En aquellos casos en los que haya numerosas variables, el asunto se puede complicar muy répidamente. El truco es el siguiente: El ejemplo anterior pasaria a tener este aspecto: echo “Hola 1"; Esta notacién sin comillas solamente se puede utilizar cuando la propia variable esté contenida dentro de un par de comillas dobles. En todos los demas casos, deberds rodear siempre la key con comillas simples o dobles, segiin prefieras. Y siempre deberds hacerlo tal como te he mostrado en $_POSTI ‘Nombre’. Un segundo truco para las EEN) Hay otro truco més: coloca la variable dentro de un par de signos de lave. De este modo, pode- mos utilizar para la key las comillas simples 0 dobles: ‘echo "Hola {$_POST['Nombre']} 1"; Eneste cuaderno utilizaremos siempre esta no- tacién, y no slo con $_POST, $_GET 0 $_REQUEST, sino también con otras arrays. 10 Trucos de notacién EERE al Rooted La eco Si hay algo que siempre me ha irritado es la complicacién a la hora de escribir el codigo cuando, utilizando PHP, se quieren mostrar pa- sajes largos en HTML con echo. echo "
\n"; *Mail\" value=\"$_POST [Hail] \*>\n"; mmensaje\* values\*$_POSTInensaje] & El truco para hacerlo mas facil es: Este seria el mismo cédigo fuente modificado: echo "\n"; jensaje' value='$_POSTImengajel '>\n"; Si compramos diez productos en el supermerca- do, no los levamos a casa uno a uno, sino que Jos metemos todos en una sola bolsa y “trata- mos” la compra como si fuera una “coleccién’. Lo mismo es aplicable a echo: El c6digo pasaria a tener el siguiente aspecto: '$_POST [Mail] '> \n"; Lo mejor de todo es que podemos ahorrarnos escribir los molestos caracteres \n (new line). Mediante los saltos de linea se creard automati- camente una “instruccién de new line”. (Solamente he sangrado el cédigo para que ten- ga mejor aspecto y para mostrar la correspon- dencia con echo), Pasajes en sintaxis doc éTienes remordimientos de conciencia? ;Quieres seguir usando comillas dobles en los atributos de HTML y tampoco estés preparado para re- nunciar a jas comillas simples 0 dobles alrede- dor de las keys? Trucos de notacion ul} {Tampoco te convence lo de usar un solo echo para varias filas? En ese caso, tengo otra alterna- tiva, que tampoco es muy conocida, asi que seré toda una sensaci6n. {En qué estoy pensando? En echo << FORMULARIO; Sintaxis heredoc a fondo En primer lugar, observarés que de esta forma es posible mostrar pérrafos HTML convencionales, “no editados”. El truco radica en esta estructura peculiar: echo << ):

Agujero de seguridad en register_globals = On

Aqui empieza el area secretac/p>"; t Sin embargo, este ejemplo todavia presenta dos “agujeros de seguridad”: * La contrasefia se puede leer directamente en. el cédigo del archivo PHP. + Elérea secreta también se encuentra en el propio archivo PHP. LY cuél es el problema? Al fin y al cabo, el servi- dor web nunca muestra el cédigo PHP tal cual. El usuario siempre recibe una pagina HTML “montada’, en la que se ocultan todos los pasa- jes secretos. En ese caso, la pagina PHP ya no se interpretaré, sino que se mostraré “directamente”. Y las con- trasefias y los datos secretos no tendran nada de secretos, se podrén ver directamente. Por ese motivo, cualquier programador profe- sional se atiene a una regla basica: las contrase- as 0 datos de acceso deben guardarse en archi- vos externos. Dichos archivos no deben encon- trarse en carpetas accesibles al ptiblico. ‘Comprueba con un archivo HTML si los archi- ‘vos almacenados en dicha carpeta estén real- mente protegidos: jAcceso prohibido! ‘aed one pois pra aces as ec olin Este qevretibdeeacieregetie XAMPP también bloquea el acceso a la carpeta cgi- bin ¢Ha funcionado en tu caso? Fantéstico. Esta car- peta estard cerrada a “personas ajenas”, y cual- quier dato que se guarde en ella no seré accesi- ble directamente para el usuario. Sin embargo, con un script se puede (en la mayoria de los ca- 14 Separar cédigo con include() sos) acceder a los datos almacenados en dicha carpeta. Shoe ME Reo) Hates (19) Y aqui es donde entra en juego la funcién inclu- de(). Gracias a esta interesante funcién es posible vincular datos externos y analizarlos include ("ruta/archivo.ext") Entre paréntesis se debe indicar la ruta de acce- so, el nombre del archivo y la extensién. Rodea toda la string con un par de comillas. Recuerda las siguientes reglas: * Mediante include() se desactiva automatica- ‘mente la notacién PHP. Por tanto, el archivo a vincular se consideraré siempre como un archivo de texto o HTML normal. * Si deseamos vincular parrafos PHP, el archi- vo en cuestién deberd incluir etiquetas de PHP: Aqui no ocurre nada més que la declaracién de la contrasefia, en forma de variable $pw. Guarda este archivo en la carpeta cgi-bin de tu servidor. Normalmente, dicha carpeta (si existe) se encuentra directamente debajo de la raiz, Para probarlo offline, también tendrés que crear una carpeta cgi-bin directamente dentro de la raiz de XAMPP (htdocs). Ruta al archivo include ¢Cuél es la ruta de acceso al archivo include? En mi ejemplo, el archivo inseguro se encuentra dentro de / php2. Por tanto, primero debo subir un nivel (..)y después entrar en la carpeta cgi- bin. La ruta de acceso completa es: /egi-bin/password. inc. php En tu proveedor online puedes utilizar rutas que partan de la carpeta raiz: /egi-bin/paseword.inc.php En mi prueba offline con XAMPP, no ha funcio- nado con este segundo método. El siguiente paso es modificar el cédigo del ar chivo “inseguro”. Vincula el archivo de la con- trasefia y sustituye la contrasefia por la variable $pw: funciona? Encontraras mi solucin en el archivo insegurod. php: Aqui empieza el area secreta

"; Separar cédigo con include() 15 Vincular un archivo HTML Para terminar, todavia falta el “Atea secreta’ Bastard con vincular un archivo HTML conven- cional, pero tinicamente silo guardas en la ca- repta segura cgi-bin. (Ya que, de lo contrario, cualquiera que conozca la direcci6n directa po- dria acceder a los datos). Modifica la segunda consulta if del archivo “in- seguro” de la siguiente forma: se (Sogn) { include (* b La pagina secreto.htm! no contiene ninguna eti- queta en PHP. Basta con utilizar lineas HTML sencillas: chisTop Secret/hi>

Esta es el érea secretac/b>.

Compéralo con el archivo inseguro5:php. /egi-bin/secreto.htm1") ; Mayor seguridad con una extension falsa Puedes probar un truco més para lograr una mayor seguridad. Para ello, tendras que asignar a la pagina secreta una extension distinta de ‘html, por ejemplo gif. ‘Vincula la pagina de la siguiente forma: if ($login) { include (* } Si, por algiin motivo, un usuario puede abrir la pagina directamente, como minimo ésta no se mostrard. Al fin y al cabo, el navegador espera que se trate de un archivo de imagen y se negara a cargar el documento como archivo de texto. Sin embargo, la funcién include() hace caso omi- so de esta extensi6n “incorrect” /egi-bin/secreto.aif") ; Compara el c6digo con el archivo del suplemen- to inseguro6.php. Ejercicio sobre proteccion CoE] Esta parte s6lo contiene un ejercicio. Remodela- remos la proteccién con contrasefia de forma que se pidan tres contrasefias y se muestren tres paginas distintas, De este modo podrds asentar y practicar los conocimientos que ya tienes (del curso anterior), 1m Ejercicio: miiltiples contrasefias Las tres contrasefias del ejemplo son a?ix201, a?ix202 y a?ix203. Para el andlisis del formulario, utiliza la instruc- cién switch. Analizaremos el campo pass, y ade- més he introducido las contrasefias en los pun- tos correspondientes para hacerlo més claro. Como recordatorio, este es el aspecto de una ins- truccién switch clasica awiteh ($_P0sT['pass']) { case "a?ix201" echo “krea secretal"; break; ease "a?in202": echo "Area secreta2"; break; case "a?ix203": echo "Area secreta3"; break; - default: echo "

iIntroduce una contrase- fiat

"; } jSin embargo, no tiene que quedarse asf! 1. Guarda las tres contrasefias en el archivo pw.inc.php dentro de cgi-bin y guardalas en las variables $pw1, $pw2 y $pw3. 2. Vincula este archivo correctamente en la pé- gina de peticién de la contrasefia. 3. Guarda también los tres archivos HTML en la carpeta cgi-bin y vincullalos de forma ex- terna. Llamalos secretol. gif, secreto2.gif y se- creto3 gif. (Extension gif) Encontrards la solucién en el archivo multi- pw.php. 16 Escribir funciones propias Escribir funciones propias ‘Ya has recorrido un buen trecho para convertirte Por lo general, una funcién suele devolver un en un profesional de PHP. En este capitulo ve- valor, que puede ser un ntimero, una cadena 0 remos un tema muy importante, que por moti. _un valor como true o false. vos de espacio no pude tratar en el cuaderno an- : . terior: el de las funciones. ¢Por qué funciones propias? Hay ocasiones en las que PHP no ofrece ninguna funcionalidad ni hay posibilidad de que lo haga en el futuro. En estos casos, deberemos escribir nuestras propias funciones. Ya hemos hablado de muchas de las funciones integradas en PHP. Sabemos comprobar la fecha y la hora con date(), dar formato a cadenas de texto con sprinif) 0 comprobar la versién de Las funciones propias presentan una ventaj mientras que las funciones predefinidas son una especie de “black box” (slo vemos el resultado y no sabemos cémo PHP llega hasta él), en el ca- eres 50 de las funciones propias somos nosotros La funci6n isset($Variable) comprueba si existe quienes definimos con total precisién lo que tuna variable y devuelve true o false en funci6n ——_curre con los argumentos y qué valor se de~ del resultado. vuelve. El objeto que se comprueba se suele denominar _Puedes guardar tus propias funciones a buen re- también argumento. caudo y utilizarlas tinicamente cuando las nece- sites. Sintaxis de las funciones Pero antes de crear nuestra primera funci6n, veamos la sintaxis basica: function Nombrefuncion(argumento[, Argumento] ) { Lineacodigo(n) ; return $Valorvariable; ) Llaves Nombres de las funciones Como se puede observar el bloque dela funcién Lp mismo que ocurre con los nombres de las va- estd contenido entre un par de Haves. riables es aplicable a las funciones: deberemos. evitar los espacios en blanco, los caracteres espe- ciales y diéresis, y no deben empezar por un ntimero. Se distingue entre maytisculas y mi- nusculas. Se suele utilizar mucho el c6digo tipo “camello”. En el caso de funciones cuyo nombre contenga varias palabras, se escribe la segunda (y tercera) palabra en maytiscula, a fin de mejorar la legibi- Tidad. Por ejemplo, escribe mittuevaFuncion(). En este caso, ademés, se trabaja con una sangria del texto de cuatro caracteres. Escribir funciones propias 7 Un ejemplo: de bruto a net Hace muchos afios, hice un ridiculo espantoso en un curso de informatica. Como profesor, na- turalmente. Se trataba de calcular el valor neto partiendo del valor bruto, y en lugar de ello, yo traté el valor bruto como si fuera el neto. Sin embargo, desde entonces ya no he cometido ‘més fallos en este tema. Es la oportunidad per- fecta para escribir una funcién que se encargue de esta imporante conversi6n. La funci6n partiré del valor bruto y calculard el valor neto, redondedndolo dos decimales. (De ello se encargars Ja funci6n sprintf), de la que ya hablamos largo y tendido en el cuaderno an- terior sobre PHP). Para terminar, la funcién de- vuelve el valor modificado (convertido). function brutoaNeto ($2w) { Sew = $2w / 1.16; $2 = sprint ("01.26", Saw); return $2w; En el script, puedes guardar el resultado de la funcién en wna variable, o mostrarlo directamen- te con echo. Y eso mismo es precisamente lo que he hecho yo en el archivo del suplemento bruto- neto.php:
en la pagina resul- fante. Naturalmente, tienes carta blanca para modifi- car mi script para que acepte otros tipos de ar- chivo. Bastara con eliminar la consulta if co- rrespondiente, y sobre todo el médulo de lec- tura. En la pagina siguiente presento el c6digo fuen- te de carga.php, aunque por motivos de espacio sélo he copiado el 4rea comprendida entre . No tengas miedo, analizaremos el cédigo paso a paso. Por el camino aprenderés varias fun- ciones nuevas que yo habré buscado y probado previamente ‘Yhablando de funciones y brisquedas, ya has descargado la tiltima version del manual ofi- cial de PHP? Album de fotos: carga de archivos 19 39 Panu compen del
input types*submit” name-'submit' value="Cargar archivo">
0) { Stamanyonax = 200000; // Indicar tamafio en bytes Snombretemp = $ FILES('archivo'] ('tmp_name'] ; Snombrearchivo = $_FILES['archivo'] [‘name'] ; Stamanyoarchivo = §_FILBS{‘archivo'] ['size'): Stipoarchivo = GetTmageSize (Snombretemp) ; - Af (§tipoarchivo(2) == 1 || $tipoarchivo(2] == 2) { // GIF 0 JPG? if (Stamanyoarchivo <= $tamanyonax) { // Archivo denasiado grande? if (move_uploaded_file($nonbretemp, $ruta . $nonbrearchivo)) { echo "con éxitoc/b>. ‘Tamafio de archivo: $tamanyoarchivo bytes, Nombre de imagen: Snombrearchivo

"; } else { echo "

No se ha podido cargar e1 archivo.

" } } else { echo "

El archivo tiene més de $tamanyomax bytes y es demasiado grande.

"; } } else { echo ""; } echo "
"; } $£ilehandle = opendir(gruta); // abrir archivos while ($file = readdir(§filehandle}) { 20 Album de fotos: carga de archivos 40 if ($file t= "2" ge $file t=.) ( a Stamanyo = GetImageSize (Sruta. $file) ; 2 echo "

\n"; 3 } a} 45 closedir($filehandle); // Fin lectura archivos 46 72> Formulario de carga Las Iineas 3-7 no suponen ningtin enigma. En elas creamos el formulario para cargar el archi- vo. Lo importante es el par atributo-valor adi- cional enctype=" multipart/form-data” de la etique- ta
. Solo gracias a ello se trata de un “formulario de carga autorizado”. El campo para cargar el archivo propiamente di- cho se genera mediante 0, compruebo si realmente se ha cargado un ar- chivo. Para ello, el tamafo del archivo tiene que ser mayor que 0. {Qué es lo que pasa en las lineas 13-15? Aqui transformo estas variables fijas en variables pro- pias, tinicamente para que el cédigo sea mas fa- cil de leer y no me provoque confusion. Asi, por ejemplo, transformo la complicada es- tructura $_FILES[ archivo’ Il'tmp_name'] en la va- riable $nombretemp, etc. Determinar un tamafio maximo Enla fila 12 he fijado un tamafio maximo para el archivo. De este modo me aseguro de que mas tarde no lleguen “peces demasiado gordos” a la pégina. Teéricamente, PHP acepta archivos de hasta 2 MB. Por tu parte, puedes y debes ajustar este valor a tus necesidades. Tipo y tamaiio de archivo {Qué ocurre en la linea 16? Aqui entra en juego la funcién GetlmageSize(). Se trata de una funcién extremadamente intere- sante, ya que reconoce los archivos GIF, JPG, PNG 0 SWF y puede devolver su altura y an- chura. Ademés, también devuelve el tipo de ar- chivo, y precisamente necesitaremos esta pro- piedad mas adelante. El truco radica en que la funcién devuelve una array, concretamente tna matriz de 4 elementos. * Index 0 corresponde a la anchura * Index 1 corresponde a la altura * Index 2 es un mimero en funci6n del tipo de archivo de imagen (1=GIE,2 = JPG,3 = PNG, 4= SWF) «Index 3 contiene la cadena de caracteres co- rrecta en formato width="xxx" height="yyy” Eltiltimo punto es especialmente interesante, ya que podemos incluir esta cadena de caracteres directamente en la etiqueta . SE a a a Pasemos a la linea 16. Aqui leo con GetlmageSi ze) todos los datos del nombre de archivo tem- poral del archivo ya cargado (!) y los almaceno enla variable $tipoarchivo 2Archivo GIF o JPEG? ‘Ahora se aclara la consulta if de la fila 18. El in- dex 2 de la array $tipoarchivo me indica con tan s6lo un ntimero si se trata de un archivo GIF, JPEG, PNG 0 SWE Y, dado que slo queremos permitir archivos GIF 0 JPEG, por eso la consul- ta tiene el aspecto que tiene. “ (Por tanto, este es el punto que deberds eliminar si deseas permitir que se carguen otros tipos de archivo). éSe ha alcanzado el tamafio maximo? La consulta de la fila 19 comprueba si se ha canzado el tamafio maximo de archivo permit do. Siel archivo es demasiado grande, se ejecuta el else de las Iineas 27-30. De lo contrario, el script contintia en la linea 20. é¥ qué ocurre exactamente en la linea 20? Funcion move_uploaded_file Vamos a ocupamos de la funcién mo- ve_uploaded_file(). Se encarga de “trasladar”, tal ‘como nos indica su nombre, el archivo “carga- do” a otra ubicacién que deberemos definir co- mo pardmetro. 22 Album de fotos: carga de archivos Fl primer argumento de la funci6n es el nombre de archivo temporal, el segundo la ruta de acce- so y el nombre de archivo en la ubicacién final. Sila funcidn tiene éxito, presentaremos un par de datos sobre el archivo cargado. Esto ocurre en Jas lineas 21-23. ae we oS ATR Naa eo ‘Todo ha funcionado, ahora hay que hacer clic en OK. Alhacer clic en el botén OK (formulario de las lineas 35-36), desaparece el mensaje de confir- macién. También se vacfa la memoria caché del navegador, ya que de lo contrario el usuario po- dria volver a cargar el archivo al servidor. eke MUM tee) Hasta aqui hemos llegado, y ahora ya sabes c6- mo cargar archivos a un servidor y cémo com- probar que todo ha funcionado. opendir() Por pura diversion, he ahtadido un “médulo de Tectura” al script, que se encuentra en las lineas 38-45, Obsérvalo con atencién: qué ocurre en la linea 38? La funci6n opendir() se limita a abrir una carpeta, y devuelve un “handle”, una espe- cie de apuntador. A continuaci6n, almaceno este indicador de di- rectorio en la variable $filehandle (aunque podria haberla llamado de cualquier otra forma). readdir() ‘Acontinuacién, se ejecuta la siguiente funcion, la funcién readdir(). Esta funcion lee los nombres de archivo del directorio y los devuelve. Para ello solamente necesita el handle del archivo: readdir(Sfilehandle). Y si solo quiero utilizar el nombre de archivo, tengo que guardarlo en una variable: Sfile = readdir(Sfilehandle). Sin embargo, por lo general una carpeta no suele contener un solo archivo. Para contarlos todos, recurro a tun bucle. Necesitaré un bucle que se mantenga activo hasta que readdir() haya “recu- perado” todos los nombres de archivo de la car- peta. Y de esto se ocupa precisamente mi queri- do bucle while, que he transformado en $file = readdir($filehandle) (linea 39) y que se cierra en la linea 44. Excluir los caracteres . y .. La primera vez que probé las funciones opendir() y readdir(), quedé estupefacto. Mi fantéstico echo (ver linea 42) no s6lo devolvia los nombres de archivo, sino también unos curiosos puntos; po- dia ser un punto solo o dos. Con que esas tenemos... ningiin problema, solo tenemos que filtrar estos caracteres en la linea 40 y listos. La linea 42 vincula mis imagenes en la etiqueta y coloca cada imagen en un pa- rrafo propio. La fila 41 lee, con ayuda de la funcién Getlmage- Size() de la que ya hemos hablado antes, el ta- mafio del archivo, para poder evitar el efecto de os graficos “saltarines”. Sorprendido? ONT Chie eRe) Ha llegado la hora de publicar el script en el ser- vidor y comprobar si todo funciona como debe- ria. Ya la hora de la verdad... los posibles men- sajes de error dependeran de tu proveedor. Album de fotos: carga de archivos 23 En mi caso, la funcién move_uploaded_file() ha fa- llado. {Por qué? Sencillo: porque todavia no habia asignado derechos de escritura a la carpeta img. Utiliza tu cliente FTP para acceder a dicha carpe- ta y asignarle un CHMOD 777, es decir, permitir la lectura, la escritura y la ejecucién. Los princi- pales programas FTP pueden hacerlo, incluso WS FTP Limited Edition incorpora esta funcién. Alhacerlo, asegtirate de aplicar el comando CHMOD a la carpeta deseada. Haz clic en el pa- nel derecho con el bot6n derecho del ratén en el nombre de la carpeta. Domainfactory o mas YK) ERR TLL | En la primera edicién de “Introduccién a PHP” publicada en Espaiia en 2002 pasé por alto to- talmente la cuestiGn de los permisos de carpetas. Como cliente de la empresa alemana de hosting, 1&1 no tuve que preocuparme de eso, ya que mis ejemplos funcionaban sin chmod. As{, no me di cuenta de que el ejemplo del libro de visitas y Ja encuesta no funcionaban en otros proveedo- res, Sin embargo, esta vez no dejaremos este te- ma pendiente. Para que no me volviera a ocurrir algo asf, lo que hice fue registrarme con varios proveedores que ofreciesen PHP. Volvamos al script que nos oscupa: la empresa alemana de hosting Do- mainfactory (www.domainfactory.de) me provocé otro problema. La carga de archivos funcionaba, peto las imagenes no se mostraban. La solucién es agregar el siguiente c6digo entre la linea 20 y 21 chnod(Sruta . Snombrearchivo, 0666); El motivo es que el servidor de Domainfactory est configurado de forma que, tras su carga, los archivos no tienen todavia permiso de lectura, Ejercicios: propuestas para Cele) A pesar de lo completo que es el script, siempre hay algo que se puede mejorar. Asi que aprove- charemos esta oportunidad para practicar con un par de ejercicios. Encontrards los resultados a los ejercicios en el suplemento del cuaderno, pero atenci6n: no vale hacer trampas. De lo que se trata es de que aprendas probando, Créeme, la experiencia y los contratiempos te ayudarén a avanzar. '§ Ejercicio 1: anchura maxima Quizés no te parezca tan importante el tamafio méximo y prefieras mostrar en su lugar la anchu- ra maxima del archivo. Enel fondo, tiene sentido: las imagenes dema- siado anchas podrian afectar el disefio de la pa- gina. Haz lo siguiente: * Sustituye la consulta sobre el tamafio en una consulta sobre la anchura. La imagen que se cargue no podra tener més de 600 pixeles. + Ajusta las variables en consecuencia. Mi album de fotos en linea (Cargar archive “Bach seme an tars pence 2600 pres + demiinde c oe * Muestra un mensaje de error descriptivo para elusuario. Consejo: sélo tienes que cambiar ligeramente el script, ya que las variables correspondientes ya estén preparadas. Para comprobar la anchura utiliza la funci6n getlmageSize() y su valor indice 0. Encontrarés mi solucién en el archivo car- -gaancho.php. '@ Ejercicio 2: guardar el archivo de imagen con otro nombre Otro posible problema del script es que, cuando se cargan archivos con el mismo nombre, el ar- chivo nuevo sustituye al anterior. No seria me- jor asignar a cada archivo un nombre nuevo? Tu tarea: completa el script de forma que se asigne a cada archivo un nombre tinico, que cam- bie a cada segundo. 24 Album de fotos: : carga de archivos Consejo: tendras que ampliar el segundo argu- metno de la funcién move_uploaded_file() de la It- nea 20. Y otro consejo més: hay una funci6n que devuelve la cantidad de segundos transcurridos desde el 1 de enero de 1970. Amplia el nombre de archivo utilizando este valor. :De acuerdo? Encontrarés mi resultado en el archivo tiempo- carga php. Espero haberte dado suficientes pistas. [El archivo se ba carzado con éxito. \Tamaiio de archivo: 177982 bytes, Anchura: 427 "Nombre de imagen: 1145815959_MG_6182.jpg Ajusta también la forma en que se muestra el nombre de archivo. '® Ejercicio 3: proteccién con contrasefia Por desgracia, nuestro script todavia tiene un pequefio problema estético. Cualquiera puede cargar archivos, sin mas. Establece una protec- cién mediante contrasefia. Para ello, agrega un campo adicional que pida la contrasefia. Solo las personas que conozcan la contrasefia podran cargar un archivo. ‘También puedes proteger toda la carpeta utili- zando htaccess. En muchos proveedores de hos- ting, se puede hacer facilmente desde el menti de configuraci6n del panel de control. Interfaz grafica phpMyAdmin 25 Comodidad para MySQL — La interfaz grafica phpMyAdmin ‘A partir de este punto empezaremos a tratar MySQL, el practico programa de bases de datos de origen sueco. MySQL es potente, rapido y fiable y es capaz de manejar con soltura grandes cantidades de datos. ‘Aunque, como era de esperar, siempre hay un “pero”: el programa se controla mediante la li- nea de comandos, es decir, escribiendo directa- mente los comandos en una ventana. Seria mucho mas agradable utilizar para ello una interfaz gréfica, como la de Access y otros programas. Y precisamente este hueco és el que llena phpMyAdmin. Pero aqui no se acaba todo, sino que, ademas, XAMPP instala autométicamente la tiltima ver- sign de phpMyAdmin. Para acceder a phpMyAdmin, escribe lo siguiente en Ja ventana del navegador: http: //localhost/phpmyadmin Como recordatorio: el nombre de usuario es roo!, la contrasefia se puede dejar en blanco. Sin duda, si tu proveedor de hosting ofrece mySQL también utilizaré este practico progra- ma. Permiteme que lo repita una vez més, ya que es un punto muy importante: un buen pro- veedor te permitiré acceder a tus bases de datos en MySQLa través de phpMyAdmin, ‘eis (Egg eet eb oa e phpMyAdmin, la interfaz gréfica para MySQL 26 Interfaz grafica phpMyAdmin phpMyAdmin en los distintos proveedores {Cémo se puede acceder a phpMyAdmin? Me resulta muy dificil poner ejemplos de proveedo- res espajioles, ya que principalmente conozco los de la esfera alemana. Sin embargo, te presentaré a modo de ejemplo el fancionamiento de un proveedor de Estados Unidos, Dreamhost (waw.dreamhost.com), que a mi parecer tiene una muy buena oferta de servi- cios por un precio inmejorable. Los servidores de Dreamhost se encuentran en Los Angeles, y su servicio es amigable y de res- puesta rapida. Ademés, su sistema de ayuda ha pasado a ser un wiki colaborativo, y también mantienen un blog en el que explican las tiltimas noticias internas de la empresa blog.dreamhost.com. En cualquier caso, no te conformes con mis ex- plicaciones. En la pagina www.buscahost.com en- contraras informacién sobre los principales pro- veedores de hosting de Espafia. Un ejemplo: Dreamhost Enel caso de Dreamhost, para comprender me- jor como funciona, te mostraré el aspecto del formulario del panel de control de Dreamhost para la creacién de una base de datos: B= En este formulario deberemos indicar tres datos fundamentales: + Un nombre para la base de datos (Database name) = Unnombre de host (Hostname, el equivalen- tea localhost en nuestro servidor local) que estara compuesto por un nombre de libre eleccion seguido de un punto y el nombre de dominio, por ejemplo nombrehost.dominio.com = Unusuario (Username) y una contrasefia (Password) para acceder a la base de datos. ‘Una ver creada la base de datos, s6lo necesita- remos el nombre del host (hostname) y el nom- ‘bre de usuario y la contrasefia que hayamos de- finido. Atenci6n: en dreamhost no se utiliza “local- host” como hemos venido viendo hasta ahora, sino un nombre de host de libre eleccién vin- culado al nombre de dominio. ‘Asi, si creo una base de datos llamada base, en un hostname llamado host.midomtinio.com con un ‘usuario pepe y una contrasefa botella, para acce- der a phpMyAdmin s6lo tendré que escribir: host.midominio.com Y se abrird una ventana emergente para introdu- cir el nombre de usuario y la contrasefa y acce~ der a phpMyAdmin. Es decir, el usuario y la contrasefia de mySQL son los mismos para phpMyAdmin, Recientemente, en Dreamhost han simplificado el procedimiento de administracién y acceso a bases de datos, de modo que es posible asignar multiples bases de datos a un solo hostname. La ventaja es que es posible acceder a todas las ba- ses de datos con el mismo nombre de host ‘mysql, y utilizando siempre la misma URL de acceso a phpMyAdmin, Creacién de subdominios lly Hosted pepe ne rere) bp vero. © i Ota (Bsc wre ncn pistes faecal sao nana wer Cok mae er iia aad Sete, homer eH! “San none samo. nd W/o com me, Oa tenn pm Crear un subdominio en Dreamhost es tan sencillo como crear un dominio. Basta con elegir “Add New Domain / Sub-Domain” en el panel de control. Escribe el nombre del domi- nio sin www (), Una vez creado el subdomi- nio, en la pagina de gestién MySQL el sub- dominio parecer autométicamente en la lis- ‘a para crear una nueva base de datos MySQL. Interfaz gréfica phpMyAdmin Gracias a la flexibilidad que ofrece, es muy sen- cillo utilizar Dreamhost como “banco de prue- bas”. Basta con crear un subdominio para hacer pruebas y probar en él tus scripts de PHP/MySQL. Cuando todo funcione a la per- feccién, bastaré con trasladarlos al dominio principal. Otras opciones Repito que todas estas explicaciones pueden va- riar de un proveedor a otro. Hay proveedores que permiten utilizar el mismo nombre de usua- tio y contrasefia para los servicios de FTP, mySQL y phpMyAdmin, mientras que otros obligan a usar distintas claves de acceso. Ademés, cada proveedor tiene su propio panel de control, organizado de distinta forma, y todos tienen sus particularidades de funcionamiento. Par salir de dudas, lo mejor es que consultes a tu proveedor (seguramente ofrecer algtin tipo de pagina de ayuda). 27 28 Bases de datos y tablas Bases de datos y tablas: una libreta de direcciones Ha llegado el momento de lanzarse a phpMyAdmin. Te mostraré las principales fun- ciones baséndome en una libreta de direcciones, una alternativa fantéstica a la pesada y farrago- sa libreta de direcciones de Outlook. Una nueva base de datos Eres un profesional de SQL? Seguro que toda- Via no, pero pronto lo serés. Preparindonos pa- raese futuro, Ilamaremos a nuestra primera ba- se de datos sql_profi. Este ejemplo funcionaré como minimo offline, ya que algunos provee- ores de hosting no permiten que los usuarios ccreen sus propias bases de datos. Si deseas asignar otro nombre a la base de da- tos, no hay ningtin problema. Sin embargo, pro- cura no utilizar espacios en blanco ni caracteres especiales, incluidos acentos y diéresis. ‘Asi se puede crear una base de datos: 1, Haz clicen el campo Crear nueva base de da~ tos. 2. Escribe sqi_profi. 3. Haz-clicen el botén Crear. 4, La base de datos ya est creada y aparece enseguida en el menti desplegable del mar- co izquierdo de la ventana. Ademés, PhpMyAdmin te mostraré el coman- do SQL que ha ejecutado en realidad. En nues- tro caso, el comando es: CREATE DATABASE sql_profi. Debajo del nombre de la base de datos en la lis- ta desplegable del marco izquierdo se muestra ‘el mensaje No se han encontrado tablas en la base de datos. Una tabla para categorias Esté visto que necesitamos tablas. Para nuestra libreta de direcciones, he pensado en crear dos. Una de ellas contendré las direcciones con nti- meros de teléfono, direccién de e-mail y demas, y la llamaremos: = direcciones La segunda tabla almacenaré las categorias, por Jo que se llamaré: * categorias De este modo podrés ordenar tus direcciones en cajones como Prioado, Amigos, Parientes, Pesados, y lo que se te ocurra, de forma similar a como lo harfamos en Outlook o cualquier otro programa de administracién de direcciones. Empecemos por el principio, con la tabla de ca- tegorfas. En esta ocasi6n, la crearemos a mano. A continuacién, te presentaré tu primer coman- do SQL escrito a mano. Fijate en la sintaxis. Bases de datos y tablas 29 Crear una tabla: CREATE TABLE Elcomando para crear una tabla no podia ser més sencillo: CREATE TABLE nombretabla () Elnombre de la tabla vuelve a ser de libre elec- cién, al igual que ocurria con el nombre de la base de datos (y con las mismas limitaciones) Por tanto, nuestra tabla se lamaré: CREATE TABLE categorias () (sin acento). Los comandos SQL se suelen escri- bir en maytisculas para facilitar su legibilidad. Pero el comando todavia no esta completo. Fal- ta la definicién de los campos, concretamente entre los dos paréntesis. ¢Campos? {Fiitbol? No, en realidad me refiero a Jos campos de la tabla de la base de datos. Para las categorfas tengo pensados dos campos. Dos campos para una tabla Uno de los campos de la tabla sera el id, es de- cir, el ntimero de identificacién. A cada catego- ria le corresponde un ntimero tinico. Al segundo campo lo llamaremos simple y lla- namente Categoria, y lo reservaremos para la denominacién real de cada categoria. Los nombres de campo descriptivios contri- buyen a mantener la visi6n de conjunto. Aqui si se pueden usar acentos. Definiciones de campos También tengo preparadas las definiciones de cada campo: a os ia INT NOT NULL AUTO_INCREMENT PRIMARY KEY. Categoria VARCHAR(25) Veamos en primer lugar la definicién m4s com- plicada. ;Qué son todas esas palabras en inglés que he puesto junto a id? Tipos de datos de campos Ante todo, definamos el tipo de dato del cam- po. El campo id es del tipo INT (de Integer). Es decir, es un ntimero entero. El tipo de dato INT acepta valores entre - 2100 y +2100 millones. Teéricamente, podrias guardar mas de 4000 millones de categorias en tu tabla. Por su lado, hemos asignado al campo categoria el tipo de dato varcuar. Este tipo de dato puede almacenar cadenas de caracteres de longitud variable, hasta 255 caracteres. Por tanto, con VARCHAR (25) fijo una longitud maxima de 25 caracteres. Existen muchos otros tipos de datos, por ejem- plo TEXT para guardar textos de hasta 65.535, carcteres, 0 SMALLINT para la misma cantidad de ntimeros. Un par de paginas mas adelante nos ocupare- mos de los principales tipos de datos. NOT NULL y AUTO_INCREMENT Volvamos al id. El campo NOT NULL significa que el valor no puede ser 0. Por tanto, el re- cuento de categorias debe empezar en 1. Con AUTO_INCREMENT indico que el nimero se incrementaré automaticamente, es decir, au- mentaré en 1 cada vez. Si deseas fijar por ti mismo el orden, puedes eliminar este atributo. El campo clave Elcomando principal, sin embargo, es PRIMA- RY KEY. Nuestro campo iid se convierte en campo clave, en la clave primaria. :Qué signifi- ca eso? Claves primarias * Ta clave primaria es una forma de referirse a una cadena de caracteres de forma univoca, A cada campo se le asigna un valor disstinto. En el ejemplo, cada campo tendra un niimero distinto. Gracias a la instruccién AUTO_IN- CREMENT no tengo que preocuparme de asignar la numeracién manualmente. La cla- ve primaria no tiene que ser un ntimero, también se permiten palabras 0 cadenas de caracteres. Introducir un comando SQ Hasta aqui la teoria, y ahora volvamos a la in- terfaz de phpMyAdmin. Vamos a crear la tabla de una vez. Haz clic en la opcién SQL, introdu- ce el comando y haz clic en OK. 30 Bases de datos y tablas El comando SQL se ha ejecutado con éxito. CREATE TABLE categorias ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, Categoria VARCHAR (25) ‘i Espero que todo haya funcionado a la perfec- cién. A pesar de haber creado la tabla, ésta si- gue estando vacia, pero pronto le pondremos remedio. Introduce un par de datos, esta vez, utilizando directamente phpMyAdmin: 1. Asegtirate de haber seleccionado la tabla. Para ello, haz clic en el nombre de la tabla ‘en el marco izquierdo de la ventana 2. Enel menti de pestafias de la parte superior de la ventana, haz clic en la ficha Insertar. 3. Escribe el primer nombre de categoria, por ejemplo Privado. 4, Rellena varias categorias més, por ejemplo Amigos, Parientes, Comparieros de trabajo. Inserta nuevas categorias a tu gusto. Mostrar la tabla Si tienes curiosidad por ver el aspecto que tiene tu tabla, haz clic en la ficha Examinar. Desde aqui podras visualizar, eliminar, editar e incluso ordenar los datos de la tabla. Si, por el contra- rio, lo que queires es introducir més datos, se- lecciona Insertar. Si todo funciona como deberia, deberias estar viendo un mensaje de confirmacién. De lo con trario, tendrés que buscar algtin error en el co- mando. Por ejemplo, comprueba que cada linea entre paréntesis termine con una coma, a ex- cepcién de la tiltima linea del comando. Desde aqui también tienes la opcién de introducir ‘nuevos datos, seleccionando Insertar nueva fila bla de direcciones Nuestra segunda tarea pendiente es la creacion de la tabla de direcciones. Analizando el co- mando SQL podras deducir los campos que te propongo para la tabla. CREATE TABLE direcciones ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, Tratamiento VARCHAR (10) , Nombre VARCHAR (25), Bpelido VARCHAR (25), Calle VARCHAR (25), CP VARCHAR (5), Localidad VARCHAR (30) , ‘Tel VARCHAR(25), Mévi1 VARCHAR(25) , Mail VARCHAR (35) , Website VARCHAR(35), categoria INT, Notas TEXT ) Bases de datos y tablas 34 ‘También aqui tenemos un campo clave, pero es- ta vez no debes olvidarte de ‘AUTO_INCREMENT. Le siguen Jos campos habituales de cualquier base de datos de direc- ciones: el Tratamiento, que distingue el sexo de Ja persona, y donde podemos indicar Sr o Sra. Los demés campos no tienen ninguna particu- laridad. En el campo Categoria s6lo tienes que introducir el ntimero de la categoria que desees asignar. Es decir, deberas introducir el id de la tabla categorias. Gracias a que es del tipo TEXT, el campo Notas puede aceptar hasta 65.535 caracteres. De esta forma, podrds afiadir notas muy largas sobre cada uno de tus contactos. Introduccién de datos Tu siguiente tarea es sencilla: rellenar la base de datos de direcciones. Escribe los datos de algu- nos de tus amigos, conocidos y parientes. Para empezar puedes utilizar phpMyAdmin, de la parte dificil nos encargaremos més tarde. 32 Tipos de datos de MySQL Principales tipos de datos de MySQL Ha llegado el momento de presentar los prin- cipales tipos de datos de MySQL. Recuerda: En las tablas pequefias este tema seguramente no supondré ningtin problema. Sin embargo, sillegamos a tener varios miles de cadenas de caracteres, un par de bytes mas 0 me- nos pueden jugar un papel muy importante. Pero no hay que preocuparse, no se necesitan todos los tipos de datos. Mis “favoritos” son INT, VARCHAR, DATE y TEXT. Para todo el cuaderno, con estos cuatro tendremos més que suficiente. \VARCHAR(M) Cadena de caracteres de longitud |Acepta entre 1 y 255 caracteres, la longitud ‘maxima se se determina mediante M, es obliga- 1 Byte torio especificar (M) variable ‘Longitud del valor mas CHAR(M) (Cadena de caracteres de longtud |Acepta ene 1 y 255 caracteres, a longitud MBytes | fle ‘méxima se se determina mediante M, es obiga- | tori especifiar (M) | | TEXT (Cadena de caracteres con un No tiene en cuenta maytisculas y mindsculas ‘Longitud del valor mas maximo de 65.535 caracteres (64 (importante para ordenar y compara’) 2Bytes KB) comes BLOB Cadena de caracteres con un _Sitone en cuenta mayisculas y mindsculas(im- Longitud dl valor més ‘maximo de 65.535 caracteres (64 _portante para ordenar y comparar)~adecuado 2 Bytes KB) también para datos binarios | MEDIUMTEXT (Cadena de caracteres con un (16 MB) MEDIUMBLOB Cadena de caracteres con un 'No tiene en cuenta mayisculas y mindsculas ‘maximo de 16.77.2158 caracteres. (importante para ordenar y comparar) ‘i tene en cuenta maydsculas y mindsculas (m- Longitud del valor mas LLongitud del valor més ‘3 Bytes ‘maximo de 16.777.216 caracteres portante para ordenar y comparar)~ adecuado 3 Bytes (16 MB) también para datos binarios. INTo también Numero entero entre -2147 millo-El.atributo adicional UNSIGNED lo limita a valo- 4 Bytes (32 Bits) INT(M) ines y 2147 millones, (M) es opcio- (res positivos. INT UNSIGNED acepia valores en- nal tre 0 y 4300 millones, SMALLINTo Nimero entero entre -32.768 y _|Sise utiliza el atributo adicional UNSIGNED, 2 Bytes (16 Bits) también ‘32.767, (M) es opcional ‘acepta un rango de valores de entre 0 y 65.535 | ‘SMALLINT(M) TINYINT otam- Numero entero muy pequefio entre|Si se utiliza el aributo adicional UNSIGNED, 1 Byte bien 128 y 127, (M) es opcional ‘acepta un rango de valores de entre Oy 255 TTINYINT(M) : FLOAT 'Namero de coma flotante con un En otras palabras: un numero con coma con una 4 Bytes (32 Bits) | rango de valores de entre ‘ran precision detrés de la coma (recuerda que, i ++/-1,175494951E-38 y al introduciro en la base de datos, en lugar de | +/-3,402823466E+38 ‘coma deberds utilizar el punto decimal) DOUBLE [Namero de coma flotante con un [Un niimero decimal con una gran precisién de- 8 Bytes (64 Bits) rango de valores de entre tras de la coma (Double Precision) +/- 2.2250738585072014E-308 y +H- 1.7976931348623157E+308 DATE ‘Campo para almacenar la fecha en Comprueba si se han utlizado menos de 32 dias 3 Bytes (24 Bits) formato YYYY-MM-DD ('2004-12-y 13 meses, rango de valores entre 07.01.1000 y 31') 31.12.9999 Tipos de datos de MySQL 33 ‘También determina la hora, rango de valores en- [6 Bytes (64 Bits) | |1e01.01.1000y 31.12.0900 | [Campo para almacenar la foc la hora en formato YYYY-MM hhhamm:ss (2004-12-31 23:58: DATETIME TIMESTAMP 0. Fecha y hora actuales en formato Se puede controlar mediante M, M puede aceptar 4 Bytes (32 Bits) |TIMESTAMP(M) |YYYYMMDDhhmmss, sirve desde por ejemplo los valores 14, 12, 80 6, en TIME |19700101000000 hasta el afio —_STAMP(12) la fecha sélo tiene dos cifras 2037 |YYMMDDhhmmss, en TIMESTAMP 8 la fecha | tiene cuatro ciras, pero se pierde la hora... 34 Introduccién, actualizacién y eliminacién de datos Introduccion, actualizacion y eliminacion de datos Volvamos a nuestra tabla de direcciones. 7Ya has introducido algunas direcciones con ayuda de phpMyAdmin? Se acabaron las comodidades, hha llegado la hora de dedicarse a SQL. Introduccion de datos: INSERT INTO Para introducir datos, utilizaremos el comando INSERT INTO. La sintaxis es la siguiente: INSERT INTO tabla () VALUES () Naturalmente, deberemos sutituir tabla por el nombre de la tabla de la base de datos, en nues- tro caso, direcciones. Entre el primer par de paréntesis deberemos in- dicar los nombres de campo de la tabla que se de- seen tener en cuenta. En nuestro caso, todos menos el id que se asigna autométicamente. Entre los segundos paréntesis escribiremos los valores de dichos campos. Ten en cuenta que: = Laasignacién y el orden deben coincidir to- talmente. * Cada valor se debe indicar entre comillas simples. * Todos los pares de comillas simples se sepa- ran mediante comas. * El mds minimo error puede provocar un mensaje de error en phpMyAdmin. INSERT INTO direcciones Encontraris el cédigo fuente més abajo en esta misma pagina. Pruébalo. Selecciona el érea SQL y escribe el comando a mano: Excepcionalmente, ha funcionado a la primera: cuan- do se utilizan comandos tan complicados no siempre es asi. (Tzatamiento, Nonbre, Apellido, Calle, CP, Localidad, Tel, Movil, ail, Website, & Categoria, Notas) VALUES Osra.', Narcan ecole UPDATE Si te interesa actualizar un campo, no hay pro- blema. No importa si se trata de un solo campo ode todos los de la tabla. Escribe upDare tabla SET ‘clara’, ‘Martinez', ‘Calle de la pera, 12", ‘es-t234567", 1626-12345, ‘clarasomimartinez.es', '', cena’, oy ‘og0s0", Si Clara Martinez tiene el id 3 y queremos modi- ficar su direcci6n, bastaré con escribir: UPDATE direcciones SET Calle='Calle de 1a pera, 8! WHERE id=3 Introduccién, actualizacion y eliminacién de datos 35 ‘También es posible modificar la calle y el teléfo- no, separando los datos mediante una coma: UPDATE direcciones SET Calle='Calle de 1a pera 6’, Tel='93-8938721" WHERE 1dq3 Eliminacion de datos: pa En la instrucci6n para eliminar datos de la tabla también es necesario utilizar la cléusula WHE- RE. El siguiente comando eliminaria la cadena de caracteres numero 3: DELETE FROM dixecciones WHERE id=3 Y para eliminar toda la tabla de direcciones del disco duro, s6lo hay que escribir: DROP TABLE direcciones 36 Mostrar, filtrar, ordenar y vincular datos Mostrar, filtrar, ordenar y vincular datos Seguro que no s6lo quieres introducir y editar datos, también te interesaré mostrarlos. Pues precisamente de eso nos ocuparemos ahora. En este capitulo, veremos cémo podemos selec- cionar datos; naturalmente, con la instruccion SELECT. No en vano SELECT significa SELEC- CIONAR. Mostrar todos los datos Si deseas mostrar una seleccién completa de to- das las filas de datos, deberds utilizar el asterisco *, El asterisco se utiliza como comodin para to- do. Detras del asterisco, escribiremos FROM y des- pués indicaremos el nombre de la tabla. Para mostrar todos los datos de la tabla direccio- nes, escribe el siguiente comando en el campo SQL: SELECT + FROM dixecciones Alacer clic en OK se mostraran todos los datos. zAcaso te parecié complicado? Mostrar sdlo determinados campos No siempre querremos mostrar a la vez todos Jos campos de una base de datos de direcciones. Quizas s6lo nos interese el apellido. O el apelli- do y el nombre. En cualquier caso, no hay pro- blema. Si solo queremos mostrar el apellido, bastaré con escribir: SELECT Apellide FROM direcciones Pruébalo: solamente se mostrar la columna con los apellidos, mientras que las demas columnas quedaran ocultas. BD Servidor locathost pf} Save de caters agi prot Introduce los comandos SQL directamente en el cam- po SQL. Si, porel contrario, quieres mostrar el apellido y el nombre, sepéralos mediante una coma: SELECT Apellido, Nombre PROM direcciones altars (eee dal ais 2Y si mostrésemos solamente los contactos de Barcelona? ;O los que viven en una determinada calle? Para ello utilizaremos la segunda palabra clave, WHERE, detras de la cual se indican los nombres de los campos de “forma comparati- va, por ejemplo Local idad='Barcelona'. Este seria el aspecto completo de la cléusula WHERE: WHERE Localidad='Barcelona’ El comando completo seria: Naturalmente, es posible limitarlo atin més. Si s6lo queremos mostrar el nombre y el apellido de todos los barceloneses, escribiriamos: SELECT Apellido, Nombre FROM direcciones WHERE Localidad='Barcelona* Dejemos de buscar a los arrogantes barceloneses y busquemos a nuestros amigos del campo 0, mejor atin, de Campolandia. Supongamos que Campolandia estuviera dividida en Campolan- dia Norte, Campolandia Sur y Campolandia Es- te. Mostrar, filtrar, ordenar y vincular datos 37 Con tocalidad='Campolandia' solamente se ‘mostrarian aquellos contactos que vivan en Campolandia, mientras que con Locali- dad='Campolandia sste' solamente encontra- riamos a los habitantes de la zona este. Sin embargo, seguimos sin resolver el enigma: zebmo podemos “agrupar bajo un solo para- ‘guas” a todos habitantes de Campolandia? El operador LIKE Para estos casos, utilizaremos el operador LIKE, que significa COMO. En conjunci6n con el co- modin %, este operador brilla en todo su es- plendor. La siguiente consulta SELECT * FROM dixecciones WHERE Localidad LIKE ‘\Campolandiat devolveré todos los datos en los que el campo Localidad esté relacionado con Campolandia. Personalmente, suelo utilizar el operador LIKE para programar funciones de busqueda mas sencillas, Vincular criterios Naturalmente, también es posible vincular va- rios criterios de seleccién. Para ello utilizaremos los operadores: * AND de Y) * OR (de) En primer lugar, probaremos el operador AND. Si queremos mostrar todas las personas de Bar- ceona que se llamen Martinez, escribiremos: SELECT * FROM dixecciones WHERE Localidad=' Barcelona’ AND apellido- 'martines' Si, por el contrario, queremos ver todas las en- tradas de personas que vivan en Barcelona o que se llamen Martinez: SELECT * FROM direcciones WHERE Tocalidad='Barcelona' OR Apellido='martinez' La btisqueda devolverd todas las personas que vivan en Barcelona y también todos los que se apelliden Martinez que no vivan en Barcelona. Ordenacion ‘También es posible ordenar los datos. Para ello, basta con utilizar el comando ORDER BY. En el siguiente ejemplo, ordenaremos la libreta de di- recciones por los apellidos. La siguiente estruc- tura te ayudaré: ORDER BY Apellido El comando SQL completo serfa: SELECT * FRON direcciones ORDER BY Apellido Los datos se ordenarén automiticamente en or- den alfabético ascendente. Ordenacién segun varios criterios tra posibilidad es ordenar los datos conforme a varios criterios. Asi, por ejemplo, si queremos cordenar por localidades y, dentro de cada locali- dad, por el apellido, la instruccién ORDER-BY correspondiente seria: ORDER BY Localidad, Apellido La ordenacién principal se regiré por la locali- dad. Es decir, se mostrarén las localidades orde- nadas alfabéticamente. Dentro de cada locali- dad, los datos se ordenardn alfabéticamente por el apellido de cada contacto. No esta nada mal esto del SQL... Invertir el orden Silo que quieres es invertir la ordenacic muy sencillo. Basta con agregar al final de la ins- truccién la palabra clave DESC. DESC significa descending, es decir, descendente. 38 Mostrar, filtrar, ordenar y vincular datos Para ordenar todos los datos por el apellido en orden alfabético descendente, escribe lo siguien- te: SELECT * FROM direcciones ORDER BY Apellido phpMyAdmin muestra la ordenacién de forma grafi- ca phpMyAdmin volverd a introducir automatica- mente el comando LIMIT. Consultas con JOIN 39 Consultar dos tablas simultaneamente con JOIN a (oWCot selena 59-956097 S6:-862618 pepeBbaleteson tb s tablas vinculadas Bien, por ahora todo funciona, Pero zrealmente te convence la forma de mostrar los datos de la libreta de direcciones? En lugar de la categoria s6lo se muestra un ntimero, lo cual no es nada indicativo.. ¢No seria mejor que en lugar del ntimero identi- ficador se mostrase directamente el nombre de la categorfa? Vamos all Bases de datos relacionales Por ahora, hemos dividido nuestra libreta de direcciones en dos tablas distintas, ya que es una organizacién mas racional. Entre la tabla direcciones y la tabla categorias hay un vinculo, una relacién. El hecho de almacenar las cate- gorias en una tabla separada nos permite ges- tionarlas més facilmente. Asi, si queremos cambiar el nombre de la categoria Compafieros de trabajo por Trabajo, gracias a que tenemos | dos tablas separadas no supone ningiin pro- blema. Solo tendriamos que aplicar el cambio enla tabla categorias, y listos. Por el contrario, si hubiésemos introducido las categorias di- rectamente en la tabla de direcciones, habria- mos aumentado el riesgo de cometer posibles errores; imagina que la tabla tuviese 10.000 entradas... En los sistemas de compra tam- bién se suelen dividir los datos en una tabla de pedidos y una tabla de clientes. Teese Puta! © acau, 8036 bansone 9-1012908 S96-870509 tne grane De este modo, no es necesario rellenar nue- vamente los datos del cliente por cada nuevo | pedido realizado. Esta divisién en varias tablas se conoce como normalizacién. La regla de oro dice que las tablas grandes deben dividirse en tablas mas pequefas siempre sea posible. No tendria mucho sentido guardar “por sepa- rado” el Tratamiento, por ejemplo. Ya que en gl caso de Sr. y Sra., la normalizacién supone un esfuerzo mayor que la posible recompensa. ‘Tampoco es cuestién de exagerar. BoM Com EL) Eh Como podemos encadenar ambas tablas al mostrar los datos? Para ello se utiliza un join. Basta con escribir un comando SQL que tome las columnas correspondientes de ambas tablas. En- seguida lo vers més claro. Para nuestro ejemplo, necesitamos todos los campos de la tabla direcciones excepto Categoria En lugar de utilizar el niimero identificador, mostraremos el campo mas “amigable” Categoria de la tabla categorias. Para ello es necesario escri- bir los datos de una forma especial, con una no- taci6n con puntos: categorias. Categoria —ya que hemos utilizado el nombre de campo “Catego- ria” tanto en la tabla direcciones como en catego- rias (jAtencién al acento! El nombre de la tabla 40 Consultas con JOIN categorias no lleva acento; el nombre del campo “Categoria” sf) .S6lo mediante esta asignaci6n, el intérprete entiende que nos estamos refiriendo al campo Categoria de la tabla categorias.. Por el mismo motivo utilizamos también la sin- taxis con puntos en direcciones.id. También aqui es necesario evitar cualquier doble sentido. Los. demés nombres de campo no requieren ninguna “indicaci6n de ruta”, por lo que no es necesario especificarlos mediante puntos. En la siguiente linea se seleccionan ambas tablas y se Vinculan mediante “FULL JOIN”: From Qirecciones JOIN categorias Para terminar, mediante la cléusula WHERE de- fino qué datos quiero ver: aquellos cuyo ntimero de Categoria de direcciones coincida con el id de categorias. Y solamente esos, ninguno més. SELECT direcciones.id, Tra iento, Nombre, Apellido, Calle, CP, Localidad, Tel, @ Movil, Mail, Website, categorias.categoria, Notas PROM direcciones JOIN categorias WHERE direcciones.Categoria = categorias.id LEFT JOIN 41 Que no te pase nada por alto: uso de LEFT JOIN Supongamos que en la tabla direcciones quedase un campo de categorfa vacio. Imagina que te has olvidado de introducir una cifra en el campo, 0 que no pudiste decidirte por asignar una deter- minada categoria al contacto. Sin embargo, también podria ser que no se en- cuentre ninguna coincidencia con nuestra lista de categorias porque hubieras introducido un ntimero incorrecto. | Los Itmites de MySQL Desgraciadamente, MySQL no soporta las co- nocidas claves ajenas que se pueden encontrar en otros programas de base de datos. Ein la practica, significa que es posible introducir cualquier ndimero en el campo Categoria MySQL no comprobara si la categoria intro- ducida se corresponde realmente con la cate- ovina lathe eg ras Nea la heer mucha atenci6n al introducir datos, 0 bien, cuando més tarde programes una interfaz pa- ral introduccién de datos, escribir un script que s6lo permita valores correctos. No te pre- ocupes, nos ocuparemos de ello. Nuestro “Full Join” de la pagina anterior tiene un truco decisivo. Solamente nos muestra los datos que tienen asignada una categoria. Haz la prueba: introduce una direccién sin asignarle una categoria. A continuaci6n, realiza nueva- mente la consullta que te he propuesto en la pé- gina anterior. Observarés que el nuevo dato no aparece. Por lo visto, no era tan fantdstico nuestro Join con la cléusula WHERE... | En estos casos se necesita un LEFT JOIN. No me estoy refiriendo a nada relacionado con la politica, sino con la tabla izquierda. Analiza el comando que te muestro al final de este capitulo (pagina siguiente) y comparalo con lavariante “FULL JOIN” del capitulo anterior. ‘Cuando se utiliza un LEFT JOIN, se lee siem- pre por completo la tabla de la izquierda, de modo que nunca falta dato. En nues- ‘tro caso, la tabla de la izquierda es la tabla di- recciones. Es decir, izquierda no es otra cosa que la izquierda del comando LEFT JOIN. A ccontinuacién, con ayuda de la palabra clave ON se “organiza” la comparacién de los campos LEFT JOIN lee la tabla de la izquierda por completo y muestra todos los datos, incluso los que no tienen una categoria Es decir, se mostraran todos los datos de la tabla izquierda, aunque no se encuentre ninguna co- incidencia. En ese caso, en el campo categoria simplemente aparecerd un 0; asi de sencillo. Ejercicios sobre SQL 1m Ejercicio 1 Introduce una nueva fila de datos en la libreta de direcciones (a mano). Utiliza INSERT INTO. m Ejercicio 2 Ordena todas las direcciones por apellido y, dentro de los apellidos, ordénalos por nombre. Muestra tinicamente a las mujeres. m Ejercicio 3 Crea una consulta SQL para una lista de teléfo- nos. Solamente deben mostrarse los campos Ape- llido, Nombre, Tel y Movil. & Ejercicio 4 Amplfa el comando de la lista de teléfonos de modo que también se muestre la categoria como texto. 42 LEFT JOIN @ Ejercicio 5 Introduce un campo de aniversario en la lista de direcciones, utilizando phpMyAdmin. Utiliza el tipo de dato para fechas (DATE). Ten en cuenta que la fecha se debe introducir siguiendo el es- quema 2006-12-03. SELECT direcciones.id, Tra! Mail, Website, categor: iento, Nombre, Apellido, Calle, CP, Localidad, Tel, movil, & ‘Categoria, Notas FROM direcciones LEFT JOIN categorias ON direcciones.Categoria = categorias.id PHP y MySQL 43 PHP y MySQL: mostrar los datos como pagina HTML Aqui empieza realmente la accién, y comproba- 1s que todos estos pasos previos con SQL tenfan su raz6n de ser. A continuacién, mostraremos la libreta de direcciones dinémicamente como pa- gina HTML. Empezaremos con una vista de los datos estruc- turados en filas, y lo iremos complicando hasta una tabla. {Cémo $e puede leer con PHP los datos de una tabla MySQL? Cémo se accede a los datos? En- seguida resolveremos el misterio. le M Velo} Para nuestro primer ejemplo, mostraremos los nombres y apellidos de los contactos de la libre- ta. Los datos aparecerdn uno tras otro, separados por un salto de linea. El resultado tiene este as- ecto: En el primer ejemplo juntamos los nombres y los ape- Tiidos Abajo te muestro el cédigo fuente que he utili- zado para esta consulta. Nuevamente, s6lo he copiado la parte del cédigo contenida entre las etiquetas . Ademés, en el suplemento encontrards el docu- mento, llamado direcciones1 php

Mostrar nombres

\n"; } mysql_close ($4p) ; 2

Cle meld Celt) Antes de nada, aparecer la funcion imysql_connect(). Como su nombre indica, esta funcién se encarga de “conectarse” al servidor de la base de datos. La funcién mysql_conneci() acepta tres argumen- tos. Son los siguientes, de izquierda a derecha: ubicacin de la base de datos, nombre de usuario y contrasefia. "root", 99); 44 PHP y MySQL El nombre de usuario de nuestros ejemplos offline con XAMPP siempre es root, y no se ha asignado ninguna contrasefia: mysql_connect ("localhest", "root", *"); Si deseas probar el script en tu proveedor de hosting, naturalmente tendrés que ajustar estos datos. Variable como identificador de conexién 2 qué significa la variable $dp que aparece al principio de todo? Es una especie de identifica dor de conexién para la conexién con la base de datos. Es importante si nos conectamos a varios servidores de bases de datos. En ese caso, se asigna un identificador propio a cada conexién. Seleccién de la base de datos correcta Después de la conexién, es necesario selecccio- nar la base de datos deseada. Por eso, la siguien- te funcién que aparece realiza una selecci6n. El tinico argumento realmente necesario es el nombre de la base de datos. Como segundo ar gumento se puede utilizar el identificador de la conexién que acabamos de ver, por ejemplo: mysql_select_db(*egl_profi", $ap); ‘Ya estamos conectados a la base de datos, y el siguiente paso es proporcionar las instrucciones ‘SQL deseadas. ‘Comando SQL ‘A continuacién, guardaremos el comando SQL en una variable. Siendo derrochador como soy, para este ejemplo opto por seleccionar todos los datos de la tabla: seq ‘Noes obligatorio llamar a la variable $sql. Lo importante es que recordemos cémo la hemos llamado. “SELECT * FROM direccicnes"; Eee IC) Ejecutar ‘A continuaci6n, realizaremos la consulta, lama- da “query” en inglés. $repultado = mysql_query (Seq); ‘Transmitimos a la funci6n el cédigo SQL que hemos almacenado en la variable $sql, y que es- taba esperando el momento de su salida a esce- na, El resultado de la consulta se guardaré en la va- riable $resultado; (he usado resultado para que fuese més explicativo, pero no es obligatorio lla- marla asi). El efecto final es que se crea una lista de resultados. Estoy seguro de que no habras tenido ningin problema para seguir mis explicaciones hasta es- te punto. Bucle para leer los datos A partir de aqui, las cosas se complican un poco, Lo siguiente que aparece en el cédigo es un bu- dle, vinculado con una funcién. De qué se en- carga exactamente? Como recordatorio, te escribo la sintaxis basica de while: while (condicion) { instruccion; } Al principio del bucle se comprueba si se cum- ple la condicién. Por tanto, se comprueba lo si- guiente: $row = myaql_feteh assoc (Sresultado) {Qué hace esta nueva funcién? Funcién mysql_fetch_assoc La funcién mysql_fetch_assoc() toma nuestra lista de resultados ~es decir, nuestra “tabla virtual’— como argumento. Extrae la primera fila de la tabla virtual y la transforma en una array asociativa. En nuestro caso, la array se llama $row, porque ese es el nombre que he decidido asignar a la variable co- rrespondiente: $row = mysql_fetch_assoc (Sresultado) PHP y MySQL 45 Lo importante aqui es que esta funci6n utiliza los nombres de los campos como key, Para acce- der al campo Apellido, escribiremos $row Apellido’} entre dos claudators $row[Nombre]. Qué te parece? ,A que es practi- co? Cuando la funcién mysql_fetch_assoc() haya ter- miando de leer los datos de la primera fila, salta- 14a la siguiente. Y asi seguiré mientras siga habiendo filas, almacenando su contenido en la array $row. Es decir, mientras existan filas, siem- pre se devolverd true, y el bucle seguird ejecu- tandose y produciendo cédigo HTML. Una vez se hayan lefdo todas las filas, se deten- drén la funcién y el bucle. ;Capito? Cerrar la conexién con MySQL Para terminar, cerraremos nuevamente la co- nexién con MySQL, y para ello podemos utilizar nuestro indicador de conexién: mysql_close ($4p) ; 46 Cadenas de datos en forma de tabla Mejor atin: presentar cadenas de datos en una tabla ‘Nuestro siguiente objetivo es dar forma a todos los datos de que disponemos, y lo haremos en forma de tabla HTML. Al fin y al cabo, lo que nos interesa es aprovechar todas las venttajas del HTML. ¢To- davia recuerdas cémo se crea una tabla? En esta ocasi6n, te presento primero el resultado grafico se- guido del cédigo fuente, y lo analizaremos en profundidad después. [Bistaniso emt] Cale [GF [vane] Tor_[_ Miwa ‘Wabiie Espa Noss [Sve Crete Cae pen 1800 en T2150 1256 ie | i is __ Poe Pas ana ‘Baebes 58076-8567 peda com piv baetncas|? sam onbee my fo Daremos forma de tabla a los datos. La primera fila de la tabla queda resaltada en negrita. He guardado el archivo del suplemento como direcciones2.php. Como siempre, solamente copio aqui la parte del cédigo contenida entre las etiquetas 2 2 $filas

\n"; 10 echo "\n"; // Smpezar tabla 31 echo "Snonbrecampo 1s} 16 echo "\n"; // Cerrar fila a 18 while ($row = mysgl_fetch_assoc($resultado)) { as echo ""; // Crear fila “ 20 foreach ($row as $key => $value) { 21 echo ""; 22 ) 23 echo "\n"; // Cerrar fila 2} 25 echo *
¢valuesnbsp;
\n"; // Cerrar tabla 26 mysql_close (Sap) ; 27 2 Cadenas de datos en forma de tabla 47 jos y filas Lo primero que hacemos es determinar la canti- dad de campos y de filas. Esto ocurre en las li- neas 7 y 8, donde las estrellas invitadas son las. funciones: + mysql_num_fields() y + mysql_num_rows() Estas funciones toman la lista de resultados de la variable $resultado y la analizan. El resultado del andlisis se almacena en las va- riables respectivas Scampos y $filas. En la nea 9 encontramos el primer uso de esta variable, que me permite mostrar la cantidad de filas de da- tos. En la linea 10 empezamos a crear la tabla, con la etiqueta inicial . Dicho sea de paso, para que los bordes de la tabla sean bien finos, utilizo los pares atribu- to-valor border='1' cellspacing= Enla fila 11 empiezo la primera fila de la tabla, {pero qué ocurre después? Mostrar los nombres de los eel ery Acontinuacién recuperamos los nombres de los campos, es decir, id, Apellido, Nombre, etc. De ello se encarga esta linea: + mysql_field_name(Sresultado, indice) Como podemos ver, como primer argumento volvemos a utilizar nuestra querida lista de re- sultados $resultado. Sin embargo, ¢qué papel juega el valor indice que se utiliza como segundo argumento? La funcién no devuelve todos los nombres de cam- pode una sola vez. Solamente muestra los nom- bres de campos que se ajusten al valor indice in- dicado. Siescribimos un 0 como indice, la funcién de- volverd el primer nombre de campo, en nues- tro caso id. Seguro que recordarés el concepto del bucle for... de no ser asi, te recomiendo que consultes de nuevo el cuaderno anterior, “PHP 5”. En ese titulo hablé largo y tendido sobre los distintos tipos de bucles. Mostrar las filas Ya tenemos los nombres de cada campo, que gracias a las etiquetas quedarén re- saltados con respecto al resto de celdas de la ta- bla. Hemos cerrado toda la fila en la linea 16 con la etiqueta Acontinuacién, presentaremos cada uno de los datos, y con ellos, las siguientes filas de nuestra tabla HTML. El procedimiento que he utilizado en la linea 18, deberia resultarte familiar. Ya conocemos el bu- cle while del ejemplo anterior. La linea 19 tam- poco tiene ningtin misterio, ya que en ella crea- ‘mos una nueva fila de la tabla. Pero después aparece un nuevo bucle, para qué? Soy demasiado perezoso como para escribir ‘una linea echo con todos los cédigos ‘ sin este _ espacio en blanco protegido. Es cierto, pero este espacio en blanco “me protege” frente a posibles campos vacios. De lo contrario, las ‘celdas vacias aparecerian “vacias” y “sin mar- co”. Por tanto, necesitamos un bucle que recorra to- dos los campos de la tabla y extraiga la informa- én. Las siguientes lineas de cédigo cierran la fila de la tabla y después la propia tabla 48 Cadenas de datos en forma de tabla eS Merlcle (ic Reel tilo) texto jUn momento! No deja de ser un poco tonto que en la columna Categoria siga apareciendo un cerfptico ntimero identificador. Para qué sino hemos aprendido antes a utilizar LEFT JOIN... Desplazate hasta la Iinea 6 del cédigo y cambia el valor de la variable $sql por el c6digo de la pégina 41. Funcionard a la perfeccién: $sql = "SELECT direcciones.id, ‘Tratamiento, Nombre, Apellido, Calle, 7 cP, Localidad, Tel, M6vil, Mail, & Website, categoriae.Categoria, Notas FROM dizecciones LEPT JOIN categorias ON dizecciones.categoria = categorias.id"; Encontrards el resultado en el archivo direccio- nes3.php. Mas seguridad para la conexion MySQL 49 Mas seguridad para la conexi6n MySQL Aunque nuestro sistema para crear una tabla ha funcionado, todavia no es demasiado profesio- nal. Ha llegado el momento de solucionar un par de problemillas. TIC OM UST) cee Mace g El primer problema es muy fécil de simular. Basta con introducir unos datos de usuario erré- neos en la linea de cédigo Sdp = mysql_connect... Si, por algtin motivo, la conexién con él servidor MySQL no funciona, apareceria una ventana lle- na de mensajes de error: an rt name en ot tn mace RO panto actos an et A ee pment Lk Sombie mmytncpptnecao nwt. gens At tb OC Pk pant Nia Caguetnayle paneer La conexién no funciona: mensajes de error. Sin embargo, estos mensajes no son de mucha ayuda, ni para uno mismo ni para los usuarios. Lo que haremos es desactivarlos. Laarroba permite evitar que se muestren los mensajes de error de la mayoria de funciones. En nuestro ejemplo, las “lineas de acceso” ten- drian este aspecto; observa la parte superior de la columna derecha de esta pagina: $dp = @nysal_connect ("localhost", & Neoet a hy enysgl_select_db("sqi_protir, $4p); Recordatorio: la primera funcién establece la co- nexién con el servidor MySQL, y la segunda se- lecciona la base de datos deseada. Desactivar todos los mensajes de error no tiene ningiin sentido, necesitamos controlar exacta- mente lo que ocurre cuando se interrumpe la ejecucién del cédigo. Control de errores con or die Para detener un script, podemos utilizar las pa- labras clave exit y die(). A diferencia de exit, die() permite mostrar en pantalla un mensaje perso- ~ nalizado. Es decir, escribe lo siguiente: Sdp = @mysql_connect (*localhost", "root", "") or die("

No se ha podido establecer ¢ 1a conexién con MySQL.

"); mysql_select_db(*sql_profi*, $dp) or die("

No se ha podido establecer® Ya conexiGn con 1a base de datos.

"); Sino se logra ejecutar mysql_connect(), se mos- traré el mensaje No se ha podido establecer la co- nexién con MySQL y se detendré el script. Mostrar nombres Nose ha podio esublecr la conesin con MYSQL. {Un problema al conectarse con el servidor? Si, por el contrario, la base de datos tiene algiin problema, PHP mostraré el mensaje personali- zado correspondiente. Pruébalo, funciona muy. bien. Sin embargo, no me doy por satisfecho con esto. Por algo hemos hablado en la pAgina 13 so- bre la forma de almacenar los datos del usuario de forma externa... 50 Mas seguridad para la conexién MySQL Guardar los datos de acceso de forma externa Para terminar, te recomendaré que guardes las. dos lineas con los datos de acceso de las que aca- bamos de hablar en otra ubicacién, por ejemplo en un archivo llamado acceso.inc.php. No te olvi- des de incluir las instrucciones antes y después de ambas lineas de cédigo. Para vincular los datos de acceso externos al ar- chivo, bastard con incluir esta linea de cédigo: include(".. /egi-bin/acceso. inc.php") ; Encontrards la soluci6n en el archivo del suple- mento direcciones.php. Introduccién de datos mediante formularios 51 Introduccién de datos: formulario con campo de consulta A continuacién te mostraré cémo crear un for- mulario sencillo para la introduccién de datos. Incluiré un mensaje de éxito, una comprobacién rudimentaria de los datos introducidos e incluso la recuperacién automética de los datos de la ta- bla de categorias. os Introduccién de datos mediante un formulario Encontrards el cédigo fuente correspondiente a este ejemplo en la pagina siguiente, donde he copiado el cddigo contenido entre las etiquetas . El documento del suplemento se llama introduccion.php. Analisis del codigo e ‘Todo empieza en la linea 3, dqnde vinculo los datos de acceso a MySQL almacenados de forma externa. El script contintia en la linea 4. con una larga consulta if que se divide en la linea 25 en else. La condicién else se mantiene practicamente hasta el final, hasta la linea 57. Podrés identifi- carlo facilmente gracias al sangrado del codigo. Qué comprueba la consulta if? Comprueba si se ha enviado el formulario, ya que s6lo entonces se establece la variable $_POSTI'submit']. Esta variable se crea con el botén st 53-54, al que he llamado nar to, la parte if s6lo se activa una vez enviado el formulario; de lo contrario entra en accién else. Es decir, la primera vez que se llama la pagina solamente se activa else. Preparar el campo de categoria En las lineas 26-31 preparo el campo para las ca- tegorias. El bucle while creara mediante pares de etique- tas el menti despeaaeie de categorias. Dichos campos \n' a1 } 32 echo << 34
$rowlid)$rowl Apellido] Srow[Nombre} ete. Con el bucle foreach recorremos toda la array $row y podemos acceder a todos los $values al- macenados en ella, es decir al campo id, Apellido, Nombre, etc. Si tienes dudas sobre la sintaxis de este bucle, puedes resolverlas en el cuaderno an- terior. nbsp; como comodin Para qué utilizo realmente el “non breaking. space”, es decir el caracter HTML   de Ja linea 21? Seguramente también podria haber escrito $ualueénbsp;
35 Tratamiento: 39. 40.
Nombre: La tabla gb_tabla Naturalmente, todavia nos falta crear la tabla de la base de datos, que en nuestro caso se llamara ‘gb_tabla, Puedes extraer los campos, nombres de ‘campo y su significado analizando el cédigo: CREATE TABLE gb_tabla( ia INT NOT NULL AUTO_INCREMENT oF PRIMARY KEY, Name VARCHAR (40) , Mail VARCHAR (50) , Homepage VARCHAR (50) , Imagen VARCHAR (35) , Fecha VARCHAR (30) , Entrada TEXT ) Sino te apetece crear la tabla a mano, te he pre~ parado un archivo llamado setup.php. Antes de nada, asegtirate de configurar correctamente las Proyecto: libro de visitas con fotos 65 primeras 4 variables de edit.incphp. A continua- Abajo he copiado el cédigo fuente completo del cién, ejecuta el archivo setup php abriéndolo enel —_ archivo principal del proyecto, index.php. Des- navegador. De esta forma, se crear autométi- pueés te explicaré paso a paso c6mo funciona. camente la tabla gb_tabla. Codigo fuente completo de index.php 1 14 15. 16 Libro de visitas 17 «meta http-equiv="content-type" content="text/html; charset=iso-8859-1"> 18 19 20 21 22, "; = "ediv>( Eliminar filac/a> 1 - 54 [ Desconectar ]"; 55 } 56 $output .- "

knbsp;

\n"; 57 } // fin de while 58 output .= "

[ arribac/a> ]

"; 59 echo navi_page($start, $step, $filas); 60 echo output; 61 62 mysql_close (); 63 64 echo ""7 65 66 7 67 68 7 72 73 74. Vincular los datos de acceso A primera vista, debemos fijarnos en las lineas 7 y 8, donde se vinculan los datos de acceso. ‘Ademés, el archivo acceso.inc php de la linea 8 utiliza a su vez algunas variables de edit.inc.php. ‘Acontinuacién, copio répidamente el cédigo de ‘acceso.inc.php. Este archivo se encarga de la co- nexién con el servidor de la base de datos y de , seleccionar la base de datos deseada. 69. Cédigo SQL para datos Detengémonos un momento en la linea 32. Aqui empiezan los “preparativos” para mostrar las entradas del libro de visitas. La linea 32 selec- ciona todos los registros de la tabla, lo que per- mite determinar la cantidad total de entradas y presentar este dato en la Iinea 37. {Qué hace la consulta de la Iinea 33? Ordena las entradas de forma descendente por id, de modo que las tiltimas entradas aparecen las primeras de la pagina. Limito la cantidad de datos que se muestran, un detalle importante para nuestra funcién para “pasar paginas”. He inicializado la variable $start en la linea 2 con 0, por lo que inicialmente la cantidad de entradas es 0. De la variable Sstep me he ocupado en el archivo edit.ine php. Si la has establecido como yo en 2, se mostrarén dos Proyecto: libro de visitas con fotos 67 entradas seguidas. Pruébalo, cambia el valor de Sstep en el archivo edit.inc-php. Mostrar los datos La forma de mostrar y presentar los datos no deberia suponer ningtin misterio. De ello me he ocupado entre las Iineas 38 y 52. Mediante la funcién mysql_fetch_assoc() recu- pero las entradas de la tabla y las presento con HTML. Laimagen se muestra en la linea 43, después de determinar en la linea 41 sus dimensiones. (Sino deseas incluir la imagen, sélo tienes que elimi- nar estas dos filas). De la linea 46 a la 51 nos ‘ocupamos de presentar la direcci6n de correo electrénico y la pagina web. Dado que considero estos dos campos como opcionales, compruebo antes de mostrarlos si estan vacios. Légicamen- te, s6lo deben mostrarse si no estan vacios. ] "; } if (Sstart2 $output . mis recientes >> ]\n"; } // i£-Bnde $output = "

$output

"; veturn $output; { // Inicio if 0 { La funcién recibe tres parémetros: el valor ini- cial, la cantidad de registros a mostrar y el total de registros. La funcién analiza estos tres datos y,en funcién del resultado, devuelve el texto En- tradas anteriores, Entradas mds recientes ambas cosas juntas. Las lineas 52-55 estan reservadas al 4rea de ad- ministracin. Solamente se mostrarén si el pro- pietario del libro de visitas se conecta con el nombre de usuario y la contrasefia correctas, y se crea una cookie. Después volveremos sobre ello. $output y navi_page() Te has fijado en que almaceno toda la string de los registros en la variable $output? He inicializado la variable en la linea 3. Sin em- bargo, no guardo datos en ella hasta la linea 42. Yes en la linea 60 cuando muestro su contenido utilizando echo. De este modo puedoe mostrar los vinculos para “hojear” el contenido encima de las entradas propiamente dichas, ya que apa- recen en Ja linea 59. Ha llegado el momento de ocuparnos de esta funci6n, de sus argumentos y, en consecuencia, del archivo function.inc:php. Cédigo fuente de function.inc.php ‘Observa el cédigo fuente del archivo func- tion.ine.php, que he vinculado a la pagina princi- pal (index.php) en la linea "[ elt;elt; & "[ Entradas & Cantidad de entrada 31 entradas mis recente >> 1 Si hay varias entradas, podemos “hojear” hacia ade- lante y hacia atras. 68 Proyecto: libro de visitas con fotos Para ello se utilizan célculos y comparaciones. La funci6n no es complicada, estoy seguro de que podras aclararte con la programacion de la misma. Si hojeamos una pagina hacia atrds, la funcion puede agregar, por ejemplo, start=4 al vinculo. [ << Entradas anterigres Entradas El agregado a la URL se aprecia en la linen de estado La direccién completa seria: index.php?etart=4 La variable $_GETT'start’)] ‘Aqui entran en juego las Iineas 4-6 de index.php, donde el script comprueba si el parametro de la URE llamado start existe. :Existe la variable $GET|start]? ;Tiene el valor 4? ;Fantastico! Se guardard el valor en $start y en lugar de 0 habremos cambiado dindmicamente el valor de start a 4. Myers er mR) Hasta aqui todo suena bien, pero... gc6mo se puede introducir una entrada al libro de visitas? Utilizando un principio muy parecido. Observa Ia linea 30 de index.php. También he agregado un parémetro a la URL del vinculo, en este caso: pentrada=true {Esté establecida la variable $_GETI'entrada’]? De ser asi, se visualiza el formulario y se pueden recibir los datos. ‘Y eso ocurre precisamente en introduc- cion.ine:php. Ya he vinculado este archivo en la linea 26, debajo de la linea del
: echo "
, ya que el contenedor div asegura una anchura exacta de 700 pixeles. Empieza en la linea 25. ‘A continuacién, veamos el codigo fuente com- pleto del archivo intraduccion.ine.php: 2 6 “beanchura maxima de {Sancho} pixeles.
8 Con respecto al tamafio de 1a inagen, recuerda: cb>small is 0 beaut iful!

" 9 30 Nombre y apellido:
11
12 Direceién de e-mail:
13 15
16 Imagen:
ext" name="Mail*>
17
18 Eecribir texto:
19 cbr> 21 Proyecto: libro de visitas con fotos 69 22 23 24 25 26 27 28 29 64 Paciencia al cargar!

l Cancelar entrada ]

Af (Lempty($_PosT{*Nonbre']) && !empty($_POSTI*Entrada'])) { // Cargaz foto, después introducir datos Supload = false; if (isset($ FILES['archivo']) s& $_FILES['archivo'] ["size'] > 0) { Snonbretenp = $_FILES['archivo'] {‘tmp_nane']; $nonbrearchivo = $_FILBS['archivo"] [‘name'] ; Stamanyoarchivo = § PILES['archivo'] ['size']; Stipoarchivo = Get ImageSize (Snonbretemp) ; if (Stipoarchivo(2] == 1 || $tipoarchivo[2] == 2) { // GIF 0 JPG? $extension = (Stipoarchivo(2] == 1? "gif" : "jpg"); Snuevonombre = time() . ".Sextension"; Sanchoinagen = $tipoarchivo[0] ; if (Sanchoimagen <= §ancho) { // Imagen demasiado ancha? if (move_uploaded_file(§nonbretemp, "img/" . $nuevononbre)) { chmod ("img/* . §nuevonombre, 0666) ; echo "ch2>Mensaje de aviso para la carga:

Bl archivo se ha cargado .
Tamafio de archivo: $tamanyoarchivo bytes;
Antiguo nonbre de imagen: Snombrearchivoc/b>
Nuevo nombre de imagen: $nuevonombre
"; $upload = true; jeise { echo "ch2>No ha funcionado. "; } } else ( echo "ch2>Atencién:

Bl archivo tiene una anchura superior a $ancho pxfeles y ~ es demasiado ancho.

"; } } else ( echo "ch2>Atencién:

No es un archivo GIF © ORG valido.

"; 4 } else ( echo "

Falta algo.

Indica un archivo .

Se ha podido introducir 1os datos en 1a base de datos.

"; 80 } else { a echo "epsebsNoc/b> se ha podido introducir los datos en 1a base ded datos.

"; 82 } 83 echo *ch3>{ iNo te 7 olvides de desconectarte! 1 o4 <> 85 a9

i 90 } 91 } else if (isset($_PosT{*submit'})) { 92 echo "ch2>;Todavia falta algo! 93

Deben rellenarse los campos.

94
"; 96 ) 97 98 2 {Te parece complicado? Qué va. Ya conoces la campos Nombre y Entrada. De ser asi, se ejecuta mayoria de cosas que aparecen de ejemplos an-_el script para cargar la imagen, y después el teriores. script para introducir los datos en la base de da- tos. Todo este bloque se alarga hasta la Iinea 90. Lo primero que se hace es crear el formulario. En la linea 27 compruebo mediante una com- probacién rudimentaria si se han rellenado los Identificate y carga tu foto. Por Faver, utiliza el formato GIF 0 2PG y respeta la anchura maxima de 200 pixeles. ‘Con respecto al tamafio de la imagen, recuerda: small is beautiful! Para el libro de visitas se exige también una foto. Proyecto: De lo contrario, el script salta a la condicién else- if dela linea 91, donde compruebo si existe la variable $_POST|’submit']. Solamente seré asi si se ha enviado el formulario. Las lineas siguien- tes muestran una advertencia y ofrecen un botén para que el usuario pueda volver atrés. Uso de JavaScript Como se puede ver, para el botén de retroceso de las lineas 94-95 he utilizado JavaScript; tam- bién encontraras esta técnica en otros sitios. La instruccién onclick="jaoascript! encarge de dar el salto hacia atras, istory.back()’ se Sin embargo, por lo general no suelo trabajar con JavaScript, porque cada vez son mas los usuarios que desactivan este lenguaje en su na- vegador. De ser asi, lo tinico que pasaré es que el botén “volver” no funcionaré. En ese caso, el usuario tendra que retroceder una pagina utilizando el botén de navegacién del propio navegador. Informacién para usuarios que desactiven JavaScript Si quieres ofrecer un trato mejor a los usuarios que hayan desactivado JavaScript, puedes ampliar el c6digo con un par de etiquetas

You might also like