Está en la página 1de 562

Instalando Apache 2.2.17 Qu es un servidor WEB?

Podramos definir un servidor WEB como una aplicacin que permite acceder a los recursos contenidos en algunos de los directorios del ordenador que la alberga a usuarios remotos que realizan sus peticiones mediante el protocolo HTTP. Por tanto, instalar un servidor web no es otra cosa que instalar y configurar un programa en una unidad o directorio de un ordenador cualquiera.

Qu es Apache?
Bajo este nombre suele hacerse referencia a Apache Software Foundation, organizacin norteamericana que se autodefine con el objetivo de ... facilitar ayuda organizativa, legal y financiera para los proyectos de desarrollo de software tipo Open Source (cdigo abierto). Uno de los proyectos ms populares de Apache es el desarrollo y suministro -de forma gratuita y libre- de un software de servidor HTTP, conocido tambin como el servidor Apache.

La corta historia de Apache


Apache Software Foundation tiene su origen en febrero de 1995. Hasta ese momento el software ms popular de servidores de HTTP era el desarrollado por Rob McCool, miembro del Centro Nacional para Aplicaciones de Super computacin (NCSA), de la Universidad de Illinois. El desarrollo de aquel primitivo software de servidor de NCSA (software de dominio pblico y cdigo abierto) tuvo algunos problemas a mediados del ao 1994. Esta circunstancia oblig a que muchos de los webmasters que utilizaban aquella aplicacin tuvieran que desarrollar sus propias extensiones y corregir de forma individual los fallos de funcionamiento de la aplicacin original. Un pequeo grupo de aquellos webmasters entr en contacto va e-mail con el objetivo de coordinar y conjuntar sus trabajos de correccin y mejora de la aplicacin original de NCSA. Fueron Brian Behlendorf y Cliff Skolnick quienes a travs de una lista de correo coordinaron el trabajo y lograron establecer un espacio compartido de libre acceso para quienes participaran en el proyecto en un ordenador instalado en California. En febrero de 1995, ocho colaboradores del primitivo proyecto decidieron aunar sus esfuerzos de forma organizada y fundaron lo que fue conocido como Grupo Apache. Usando como base el HTTPD 1.3 de NCSA y aplicando los patchs desarrollados hasta ese momento, lanzaron la primera versin oficial (versin 0.6.2) del software de servidor de Apache en abril de 1995. Aquella primera versin entr en un rpido e intenso proceso de mejoras y alcanz una gran implantacin como software de servidor inicialmente era slo para UNIX para diferentes plataformas, una de las cuales es la versin para Windows que nosotros utilizaremos y que frente a otras alternativas de servidor HTTP tiene las ventajas de ser gratuita y muy eficaz.

Instalacin de Apache
En el sitio de descargas de Apache o en el mirror espaol puedes encontrar un fichero llamado httpd-2.2.17-win32-x86openssl-0.9.8o.msi (es la versin que he incluido en el autoinstalador) o parecido. Digo parecido porque las versiones van evolucionando y en esas direcciones tienes la ltima de las versiones y es posible que cuando accedas ya se haya actualizado. En cualquier caso si tienes inters por una versin especfica de Apache puedes encontrarla en esta especie de repositorio histrico. Una vez descargado el programa instalador bastar con que hagas doble clic sobre su icono para que te aparezca una pantalla como esta:

Si en vez de esta pantalla apareciera un mensaje de error, es muy probable que se deba a que no tienes instalada la aplicacinWindows Installer Redistributable necesaria para ejecutar los ficheros con extensin .msi. Las versiones modernas de Windows a partir de Windows98 la tienen incorporada, pero si por cualquier circunstancia usando Windows98 no dispones de ella, puedes descargarla desde este enlace. Al pulsar Next en la ventana anterior se llega a esta otra en la que es preciso tener seleccionada la opcin I accept the terms in the license agreement para que se active el botn Next y poder continuar la instalacin.

Al llegar a esta otra ventana las anteriores solo requieren ir pulsando en el botn Next es imprescindible rellenar los camposNetwork Domain, Server Name y Administrator's e-mail adress.

Como Network Domain y como Administrator's e-mail adress puedes poner nombres cualesquiera siempre que no contengan espacios ni caracteres especiales y en el caso de la direccin e-mail sta debe contener el smbolo @. Como Server Name escribelocalhost. La instalacin recomendada de Apache For All Users, on port 80, as a Service contempla el uso del servidor como un servidor de red de rea local accesible desde el resto de los ordenadores de esa red. Es lgico que en esas circunstancias el servidor se configure conautoarranque y que se inicie automticamente en el momento en que se arranca el ordenador Si piensas utilizar el servidor para probar y depurar tus propios scripts PHP seguramente vas a ocupar en ello slo una pequea parte del tiempo de uso del ordenador, por lo que parece ser ms eficaz la opcin de arrancarlo nicamente cuando sea necesario y, de esa forma, ahorrar esos recursos del sistema que podran ralentizar el uso de otros programas cuando no necesites usar el servidor. Por esa razn te sugiero elegir la opcin only for the Current User, on port 8080, when started manually y pulsar de nuevo Next. En la pantalla que aparece inmediatamente despus de la anterior se permite elegir el modo de instalacin: Typical Custom. Elige la opcin Custom y pulsa nuevamente sobre Next.

Te aparecer esta nueva pantalla en la que el instalador te indica el directorio por defecto en el que pretende instalar el servidor Apache.

En este caso aunque no es necesario hacerlo te sugiero pulsar sobre Change y cambiarlo nicamente por razones de comodidad. La idea es agrupar todos los programas relacionados con PHP en un solo directorio (es la razn de definir c:/ServidoresLocales para ese fn) y dentro de l asignar un nombre fcilmente identificable para cada uno de los programas (Apache, en este caso). Despus del Change de la ventana anterior aparecer esta otra. Ponla con la misma configuracin que aparece en la imagen inferior, es decir, con Look in : (ServidoresLocales) y deja como Folder name: C:/ServidoresLocales/Apache/

Como podrs leer en la propia pantalla de instalacin, es muy importante poner la barra invertida (\) detrs del nombre de la unidad al indicar el Folder name. No te olvides de hacerlo.

Una vez hayas pulsado OK volver a aparecer la ventana que permite cambiar el directorio de instalacin. Comprueba que ahora digaInstall to: C:/ServidoresLocales/Apache/ y pulsa Next en esa ventana y en las siguientes. Aparecer una ltima ventana donde dice Installation Wizard Completed y una vez que hayas pulsado el botn Finish la instalacin de Apache habr terminado.

Desactivar el monitor

Durante el proceso anterior se instala automticamente el icono del monitor de servicio en la barra de tareas tal como puedes ver en esta imagen. Puedes cerrarlo pulsando con el botn derecho del ratn sobre el icono y eligiendo la opcin exit. Durante el proceso de instalacin de Apache se incluye en el men iniciode Windows un enlace al Monitor de Apache. Ello significa que cada vez que reinicies el equipo se instalar en la barra de tareas el icono del monitor. Para desactivarlo de forma definitiva bastar con eliminar tal acceso directo de la forma que puedes ver en la imagen inferior.

Arrancar Apache
Contemplando la opcin de arranque manual, cada vez que quieras poner en marcha el servidor tendrs que acceder al icono Start Apache in console, que podrs encontrar en la localizacin de la imagen que ves aqu debajo.

Cuando se inicia Apache se abre siempre la consola de MS-DOS. En los primeros arranques es posible que aparezca en ella un mensaje como el que ests viendo en la imagen inferior.

Este mensaje de advertencia no afecta a las pruebas ni al funcionamiento de servidor. No obstante, en el esquema del proceso de configuracin que tienes un poco ms abajo puedes ver cmo hacer una modificacin en la configuracin del servidor que evita su aparicin. Otra forma de efectuar el arranque sera ejecutar directamente el programa httpd.exe que se encuentra en:C:/ServidoresLocales/Apache/bin. Haciendo doble clic sobre su icono o tecleando el comando desde el smbolo del sistema de la consola de Windows aparecer una ventana de MS-DOS tal como la que ves en la imagen de arriba. No la cierres nunca! Si lo haces slo conseguiras apagar el servidor y adems lo haras de una forma muy poco ortodoxa. Si te resulta incmoda minimzala pero no la cierres.

Una pgina de prueba


Con el servidor arrancado y funcionando, bastar con que abras tu navegador y escribas en la barra de direcciones una de las siguientes: http://localhost:8080 o http://127.0.0.1:8080. para que, si la instalacin de Apache es correcta, se abra una pgina similar a la ves en la imagen. S eso ocurre, es la prueba de que el servidor est funcionando correctamente.

Pgina de prueba del servidor Apache. Observa la direccin:http://localhost:8080 Si te ests preguntado por qu esas direcciones localhost 127.0.0.1 o por qu no hemos escrito el nombre de ninguna de pgina web, ten un poco de paciencia! Trataremos de ello cuando configuremos Apache.

Apagar Apache
Aunque se puede desconectar cerrando la ventana de MS-DOS, el mtodo correcto es: establecer esa ventana como ventana activa, pulsar las teclas Ctrl+C y esperar unos pocos segundos. Transcurrido ese tiempo la ventana MS-DOS se cerrar automticamente y se habrapagado Apache.

Desinstalacin de Apache
El servidor Apache se desinstala como cualquier otro programa de Windows. Bastar con acceder a Paneles de control, opcin deAgregar o quitar programas elegirlo en la lista de programas instalados y desinstalarlo. Antes de ejecutar ese proceso es necesario que el servidor est apagado y saber que quedarn algunos restos de la instalacin que si fuera necesario habra que eliminar manualmente. El desinstalador de Apache no eliminar ni el directorio raz C:/ServidoresLocales/Apache/ ni los subdirectorios conf y htdocs del mismo. La razn es la seguridad. El directorio conf contiene los archivos de configuracin del servidor en pginas posteriores veremos que hay que modificar sus valores por defecto y al no eliminarlos nos estar dando la opcin de poder reutilizarlos (sin tener que empezar de cero) en futuras instalaciones. Lo mismo ocurre con htdocs. En ese directorio ser donde se almacenen los documentos que vayamos creando pginas web, imgenes, etctera y, como es lgico, un error en el proceso de desinstalacin podra provocar su prdida. Esa es la razn de que se conserven. Por idnticas razones, si al reinstalar Apache ya existieran esos directorios no seran sobrescritos mantenindose las configuraciones y documentos de la versin anterior.

Configuracin de Apache
El correcto funcionamiento del servidor Apache requiere efectuar una serie de modificaciones en su fichero de configuracin (httpd.conf). Las modificaciones propuestas y su justificacin son las que se resumen en la siguiente tabla. httpd.conf
(est en C:/ServidoresLocales/Apache/conf)

Fichero inicial Guardar como (*) Guardar como

httpd.orig httpd.conf
Cambios Donde dice:

Guardaremos el fichero modificado con dos nombres distintos. Uno de ellos para hacer la primera prueba del servidor (httpd.conf) y el otro (httpd.orig) para utilizarlo como base de las modificaciones posteriores.

Modificaciones en el fichero inicial Lnea Justificacin Mediante esta modificacin evitaremos que el servidor escuche el puerto 8080 y le obligaremos a utilizar el puerto por defecto (80). Observa que en la pgina de prueba anterior habamos escrito:http://localhost:8080 (para utilizar el puerto 8080 que era el que escuchaba el servidor) y una vez hecha esta modificacin bastar poner: http://localhost ya que 80 es el puerto por defecto y no es necesario especificarlo. Al descomentar (quitar #) esta lnea evitaremos el mensaje de error que apareca en la consola de MS-DOS al realizar las pruebas anteriores. Una vez omitamos el valor :8080 ya no ser preciso especificar el puerto de acceso al servidor al pedir las pginas desde el navegador. Las peticiones se canalizarn por el puerto por defecto, el puerto 80.

Listen 8080 46
cambiar por:

Listen 80
Donde dice:

172

#ServerName localhost:8080
cambiar por:

ServerName localhost

Nombres de dominio en un servidor local


Est opcin no es necesaria pero es posible que te apetezca tener tu propio dominio local para poner utilizar una direccin personalizada, alternativa a localhost, como nombre de dominio. Si utilizas Windows98 encontrars un fichero con el nombre hosts o hosts.sam en el directorio Windows. Si tu sistema operativo esW2000, NT XP , Vista o Windows 7 tendrs que buscar ese fichero en un subdirectorio, del directorio de sistema, llamado\system32\drivers\etc\ Al editar ese fichero hosts.sam o hosts- encontrars algo similar a esto:

# For example: # # 102.54.94.97 # 38.25.63.10 127.0.0.1

rhino.acme.com x.acme.com

# source server # x client host

localhost

Si aades una lnea como la sealada en rojo la IP 127.0.0.1 ha de mantenerse y pones cualquier nombre de dominio (mispruebas.as) en el caso del ejemplo

# For example: # # 102.54.94.97 # 38.25.63.10 127.0.0.1 127.0.0.1

rhino.acme.com x.acme.com

# source server # x client host

localhost mispruebas.as

bastar con que guardes el fichero con los cambios con el nombre hosts (sin ninguna extensin y en el mismo directorio). A partir de ese momento, ya podrs escribir en el navegador -con Apache en marcha- cualquiera de estas direcciones: http://localhost o http://127.0.0.1 ohttp://mispruebas.as

Nombres de dominio en redes locales


Cuando se utiliza un servidor a travs de una red de rea local, lo habitual es acceder a l escribiendo como direccin la IP de ordenador en el que se encuentra instalado el servidor. Mediante un proceso similar al descrito ms arriba, se puede modificar el fichero HOSTS de uno (o varios) de los equipos de la red aadiendo una lnea con el nombre del dominio ficticio precedida de la direccin IP del servidor. Si la IP del servidor local fuera 168.0.12.234, al incluir en el fichero hosts una lnea diciendo: 168.0.12.234 mispruebas.as podramos acceder a l tanto mediante: http://168.0.12.234 como a travs de: http://mispruebas.as

Cuidado! Esta versin de Apache de 32 bits funciona sin problema aparente en Windows XP, Vista y W 7 tanto en sus versiones de 32 bits como en las de 64 bits.

Instalacin de PHP 5.3.8


Qu es PHP y que requiere para ser usado
El lenguaje PHP acrnimo de Hypertext Pre Processor suele definirse como: interpretado y de alto nivel. Es un lenguaje de script cuyo cdigo va insertado dentro de las pginas HTML y es interpretado, siempre, en el servidor. Se trata un lenguaje de estilo clsico, multiplataforma y cercano en su sintaxis a C++. Creado por Rasmus Lerdorf en 1994; siendo su labor continuada por diversos desarrolladores, entre ellos Andi Gutmans y Zeev Suraski que fueron quienes propiciaron la aparicin de la versin PHP 3.0. Actualmente la implementacin principal de PHP (el estndar defacto), es producida por The PHP Group y se publica bajo la PHP License, a la que la Free Software Foundation considera una licencia desoftware libre. Para trabajar con PHP es necesario tener instalado un servidor HTTP en nuestro caso, Apache para Windows y configurarlo de tal manera que sea posible la interaccin entre ambas aplicaciones.

Instalando el PHP

En el sitio oficial de PHP podrs encontrar, bajo el epgrafe VC9 x86 Thread Safe, un fichero llamado php-5.3.8-Win32-VC9-x86.zip. Igual que ocurra en el caso de Apache las versiones pueden haber evolucionado. Por si tienes capricho por una versin concreta aqu tienes el museo del PHP dnde puedes encontrar cualquiera de las versiones que ya han pasado a formar parte de la historia. Si tienes instalado Winzip, al hacer doble clic sobre el icono se te abrir la ventana de este descompresor y al pulsar sobre el icono Extract se te abrir una ventana como la que aparece en la imagen. Si has seguido los pasos indicados en la pgina anterior para la instalacin del servidor Apache, tendrs en tu ordenador un directorio llamado C:\ServidoresLocales. Selecciona como directorio de descompresin C:/ServidoresLocales/php53 tal como ests viendo en la figura y realiza la extraccin.

Una vez concluida la descompresin se habr creado el directorio C:/ServidoresLocales/php53 que contendr a su vez una serie de subdirectorios necesarios para el correcto funcionamiento de PHP. El proceso de instalacin de PHP habr terminado. Solo resta la configuracin de Apache y PHP para poder empezar a utilizarlo. Esto ser lo que veremos en la pgina siguiente.

Podemos probar ahora PHP?


Si ya has realizado el proceso de instalacin tal como lo hemos descrito en los prrafos anteriores, puede que te preguntes si como hemos hecho al instalar Apache es posible hacer ahora una prueba de su funcionamiento. La respuesta es NO. Analiza con un poco de detenimiento el proceso que hemos seguido y observars que no hemos hecho una instalacin sino que nos hemos limitado a descomprimir una serie de ficheros colocndolos en un directorio determinado. Lo hemos hecho as porque lo que acabamos de instalar no es una aplicacin que pueda funcionar de forma autnoma, sino elintrprete de un lenguaje de scripts del lado del servidor que requiere ser invocado por medio de un software de servidor. As que, antes de que pueda ser utilizado, tendremos que indicarle al servidor Apache el sitio dnde ha de buscarlo y cundo debe utilizarlo.

Configuracin de Apache 2.2.17 para PHP 5.3.8


Para facilitar las cosas
A lo largo de este proceso y en otros sucesivos vas a encontrar ficheros que tienen el mismo nombre y que se diferencian slo por la extensin. Sera una buena idea tener Windows configurado de forma que se visualicen siempre las extensiones de todos los tipos de ficheros. Si nunca has usado esa opcin de Windows bastar con que hagas doble clic en el icono Mi PC y vayas a la opcin Ver (en el caso deWindows2000, XP o Vista habrs de ir a la opcin Herramientas) de la ventana que se abre. Cuando se trate de Windows7 habrs de ir aPaneles de Control->Opciones de carpeta en el submen de esa opcin elige Opciones de Carpeta. Una vez en Opciones de Carpeta debes elegir la opcin Ver de la nueva ventana y buscar la lnea en la que dice Ocultar extensiones

para los tipos de archivos conocidos y,desmarcando su casilla de verificacin y pulsando sobre Aplicar y Aceptar ya podrs visualizar las extensiones de todos los ficheros.

Modificacin del fichero httpd.conf para configurar PHP


Tal como comentbamos en la pgina anterior la utilizacin de PHP requiere introducir algunos cambios en la configuracin de Apache. En el momento en el que se instala este servidor se crea automticamente en el subdirectorio C:/ServidoresLocales/Apache/conf unfichero llamado httpd.conf que contiene la configuracin por defecto del servidor Apache. Como recordars lo hemos modificado durante el proceso de instalacin para que el servidor utilice el puerto 80. Tendremos que hacer algunas modificaciones ms. Pero, como precaucin por si tenemos algn problema y necesitamos volver a utilizar el fichero de la configuracin por defecto, vamos a hacer una copia de seguridad. Abriremos el documento httpd.conf con un editor de textos cualquiera lo ms cmodo ser utilizar Notepad ++ u otro editor que seale los nmeros de lnea y con la opcin guardar comocrearemos una copia con el nombre httpd.orig

Cuidado! Si has utilizado el bloc de notas de Windows es probable que en el proceso anterior no te haya guardado comohttpd.orig sino como httpd.orig.txt. Comprueba los ficheros del directorio C:/ServidoresLocales/Apache/conf y si te ha ocurrido lo que comentamos tendrs que recurrir al conocido mtodo de pulsar sobre el icono del fichero con el botn derecho del ratn, elegir la opcin Cambiar nombre y quitar el .txt que aparece al final del nombre del archivo.

Una vez hecho esto ya podremos hacer las modificaciones con toda tranquilidad, as que volveremos a abrir el fichero httpd.conf para hacer los cinco cambios siguientes:

Fichero inicial Guardar como Lnea

httpd.conf httpd.conf
Cambios Donde dice:

No es necesario modificar el nombre de este fichero. Ya debemos de tener una copia previa llamada http.orig

Modificaciones en el fichero inicial Justificacin Hemos de indicar a Apache que cargue el mdulo que se encuentra en el sitio que indican la ruta y el nombre del fichero. Este mdulo especfico para Apache 2.2 (php5apache2_2.dll) es el que permite que el servidor Apache interacte con PHP 5.

129

(lnea en blanco)
cambiar por: Donde dice:

LoadModule php5_module C:/ServidoresLocales/php53/php5apache2_2.dll Options Indexes FollowSymLinks


cambiar por: Evita que se visualice la lista de ficheros contenidos en un directorio de servidor si se intenta acceder a una pgina inexistente

219

Options -Indexes FollowSymLinks MultiViews


Donde dice:

241

DirectoryIndex index.html
cambiar por:

Permite indicar que ficheros y en que orden han de buscarse cuando en la peticin se indique el nombre del directorio pero no se especifique ninguna pgina.

DirectoryIndex index.html index.htm index.php


Donde dice:

384

(lnea en blanco)
cambiar por:

AddType application/x-httpd-php .php


Donde dice:

Le indica a Apache que los nicos ficheros susceptibles de contener scripts que deban ser ejecutados por el intrprete de PHP son aquellos que tienen como extensin .php. Si un fichero con extensin distinta contuviera scripts PHP stos no seran ejecutados. La inclusin de la lnea PHPIniDir (una novedad respecto a versiones anteriores de Apache y PHP) permite indicar la ruta de acceso al fichero de configuracin de PHP (php.ini) En la pgina siguiente trataremos la configuracin de PHP.

385

#
sustituir por:

PHPIniDir "C:/ServidoresLocales/php53"

Una vez efectuados estos cambios ya podremos guardar el fichero, sin cambiar su nombre original httpd.conf, y tendremos lista la nueva configuracin de Apache. Solo nos falta reiniciar el servidor para que los cambios sean efectivos

Algunos detalles importantes sobre httpd.conf

La directiva de configuracin de Apache, DirectoryIndex, tiene particular inters para comodidad del usuario. A travs de ella le estaremos diciendo a Apache que cuando reciba una peticin dirigida a uno cualquiera de los directorios accesibles a travs de HTTP en la que no se especifique ningn nombre de pgina, debe comprobar si en ese directorio existe alguna pgina llamada index.html. En caso de que dicha pgina existiera la mostrara y en caso contrario volvera a comprobar para ver si existe alguna otra llamadaindex.htm (el segundo nombre de pgina contenido en esa lnea). Si tampoco se diera esa coincidencia continuar viendo si existe index.php. En el caso de que no encontrara ninguna que coincida con los nombres indicados en esta directiva dara un mensaje de error del tipo: File not found. Esta opcin de configuracin de Apache es la que nos permite escribir direcciones del estilo www.boe.es en las que sin especificar ningn nombre de pgina nos aparece en pantalla el mismo contenido que si hubiramos escrito: www.boe.es/index.php Si con la configuracin descrita en la tabla anterior intentamos acceder a la direccin: http://localhost/images/ nos aparecera un mensaje como este:

Esto ocurre como consecuencia de haber puesto el signo menos delante de Indexes (cuidado! debe ir pegado a Indexes sin ningn espacio intermedio) en la lnea Options -Indexes FollowSymLinks MultiViews. El subdirectorio images no contiene ficheros con nombre index.html, ni tampoco index.php ni index.htm (los especificados en la directiva DirectoryIndex) y el signo menos lo que hace es denegar el acceso (en el caso de no indicar el nombre de algn documento en la direccin) a los directorios que no los contengan. Si no hubiramos modificado esa directiva nos aparecera una lista con todos los ficheros contenidos en ese subdirectorio, tal como puedes ver en esta imagen.

La configuracin de Apache permite mltiples opciones y ofrece muchas posibilidades. Tantas, que justificaran todo un curso dedicado al estudio de este servidor y sus opciones de configuracin. No entraremos en ese mbito pero, aunque no vamos a modificarlos, es conveniente conocer algunos otros elementos importantes de httpd.conf. DocumentRoot "C:/ServidoresLocales/Apache/htdocs" Esta lnea que se ha incluido automticamente al hacer la instalacin indica la ruta y el nombre del directorio en el que,obligatoriamente, han de estar los documentos y los subdirectorios susceptibles de ser servidos a travs del protocolo HTTP. Cualquier documento que estuviera fuera de este directorio sera inaccesible, por lo tanto todos los documentos PHP que vayas creando debers guardarlos dentro de este directorio htdocs. Como es lgico, bastara cambiar esa lnea de la configuracin para utilizar como raz del servidor otro directorio cualquiera. ServerName localhost Esta otra lnea tambin contenida en httpd.conf es la que determina el nombre del servidor y a travs de ella se identifican las peticiones que el navegador realiza a ese servidor. Por esta razn, cuando probbamos la instalacin de Apache, escribamos como direccin http://localhost.

Configuracin de PHP 5.3.8 Un directorio importante


Antes de comenzar la configuracin de php es conveniente que creemos dentro de C:/ServidoresLocales/ un subdirectorio con nombre tmp que ser utilizado para contener las eventuales variables de sesin que fuera necesario manejar por parte de PHP y cuya ubicacin ha de ser especificada en la configuracin de este. No es preciso que utilicemos ni este nombre ni este directorio ni tampoco es necesario que se incluya en ningn directorio concreto del servidor. La eleccin del directorio ServidoresLocales obedece nicamente a la razn ya comentada de intentar incluir all todo lo relativo al PHP.

Configuracin de PHP
Con la configuracin de PHP ocurre lo mismo que en el caso de Apache. Tambin existen un montn de posibilidades de configuracin iremos viendo algunas de ellas a medida que vaya siendo necesario a travs de las cuales se puede modificar de forma sustancial el comportamiento de PHP. El elemento clave de la configuracin de PHP es un fichero denominado php.ini que debe estar contenido en el directorioC:\ServidoresLocales\php53 dado que fue esa la ubicacin que hemos incluido en la directiva PHPIniDir cuando configurbamos Apache en la pgina anterior.

Antes de empezar la configuracin


Si abrimos nuestro directorio: C:/ServidoresLocales/php53 encontraremos dentro de l tres ficheros que deberemos copiar a nuestro sistema tal como se indica en la siguiente tabla.
Ficheros originales S.O.

php5ts.dll
Directorio

libeay32.dll

ssleay32.dll

Copiar en el subdirectorio que se indica (dentro del que contiene el S.O.)

Windows98 W2000 Windows NT Windows XP Windows Vista W 7 32 bits W 7 64 bits

\system

\system32

\SysWOW64

Si ya tuviramos un fichero con ese nombre en el directorio de destino habramos de sobrescribirlo sustituyendo el preexistente por el que tenemos en C:/ServidoresLocales/php53. Con ello estaramos asegurndonos de que las versiones de estas libreras son las correspondientes a la versin de PHP que pretendemos utilizar.

Configuracin de PHP
En el directorio C:/ServidoresLocales/php53 tenemos un fichero llamado php.ini-development. Lo abriremos con un editor de textos por ejemplo el Notepad ++ y haremos estas modificaciones:
Fichero inicial Guardar como Lnea

php.ini-development php.ini
Cambios Donde dice:

El fichero php.ini no viene incluido en las distribuciones de PHP. Por esa razn debemos crearlo partiendo, en este caso, de su versin de desarrollo

Modificaciones en el fichero inicial Justificacin Asignaremos como valor de doc_root una ruta que, como observars, apunta el directorio htdocs. En otras palabras, le estamos diciendo a PHP en qu sitio del ordenador fjate que incluimos una ruta absoluta se ubicarn los ficheros cuyos scripts debe interpretar. Con esta modificacin le sealamos al intrprete de PHP en qu sitio debe buscar las extensiones que pueda necesitar para la ejecucin de sus scripts. Estas extensiones, que vienen con la instalacin de PHP, se descomprimen por defecto en un subdirectorio llamado ext y esa es la razn por la que la ruta incluida en esta modificacin apunta a un directorio con ese nombre. Descomentaremos (quitamos el punto y coma que lleva delante) la lnea alusiva a la librera php_gd2 con lo cual estamos activando la opcin de que PHP pueda ejecutar instrucciones relativas a imgenes dinmicas.

798

doc_root =
cambiar por:

doc_root=C:/ServidoresLocales/Apache/htdocs
Donde dice:

; extension_dir = "ext" 809


cambiar por:

extension_dir ="C:/ServidoresLocales/php53\ext\"
Donde dice:

950

;extension=php_gd2.dll
cambiar por:

extension=php_gd2.dll
Donde dice:

951

;extension=php_gettext.dll
cambiar por:

extension=php_gettext.dll
Donde dice:

Descomentaremos la lnea alusiva a la librera php_gettext.dll con lo cual estamos activando la opcin de incluir soporte para GNU gettext la API del NLS (Native Language Support) que permite internacionalizar las aplicaciones PHP Descomentaremos la lnea alusiva a la librera php_mbstring.dll con lo cual estamos activando la opcin que permite utilizar caracteres multibyte lo cual evita la restriccin de uso exclusivo de idiomas con un mximo de 256 carcteres

957

;extension=php_mbstring.dll
cambiar por:

extension=php_mbstring.dll
Donde dice:

959

;extension=php_mysql.dll
cambiar por:

Descomentaremos la lnea alusiva a la librera php_mysql.dll con lo cual estaremos habilitando la posibilidad de usar las funciones MySQL

extension=php_mysql.dll
Donde dice:

1085

SMTP= localhost
cambiar por:

Asignamos la direccin IP que utilizaremos para el proceso Simple Mail Transfer Protocol cuando PHP se utilizado conjuntamente con un servidor de correo para el envo de emails

SMTP = 127.0.0.1
Donde dice:

1091

;sendmail_from= me@example.com
cambiar por:

Es la direccin del remitente que utilizaremos para el envo de mensajes de correo electrnico

sendmail_from= admin@mispruebas.as
Donde dice:

1471

;session.save_path = "/tmp"
cambiar por:

session.save_path = C:/ServidoresLocales/tmp
Donde dice:

Cuando PHP utiliza sesiones es necesario establecer un lugar del servidor en que almacenar informaciones temporales relativas a ellas. Para esa finalidad hemos creado el directorio tmp e incluimos aqu la ruta absoluta hacia ese directorio

997

;date.timezone =
cambiar por:

Las ltimas versiones de PHP requieren que especifiquemos la zona horaria correspondiente al lugar donde est ubicado nuestro servidor

date.timezone ='Europe/Madrid'

Donde dice:

short_open_tag = Off 226


cambiar por:

short_open_tag = On

El caso de short_open_tag resulta particularmente interesante. En versiones anteriores se inclua la opcin ON por defecto. A partir de esta versin parece que aparecer como OFF y ser preciso cambiar su configuracin (tal como hacemos en nuestro caso) o tener en cuenta las restricciones que impone su modo OFF. Si est en modo OFF NO PERMITE la sintaxis <? ?> para incluir el cdigo PHP siendo obligatorio hacerlo mediante <?php ?> Cuando su estado es ON interpreta ambas formas de sintaxis.

Cuidado!
Es posible que no residas en Espaa. S fuera as no hay ninguna razn para que configures la zona horaria espaola en tu servidor. Qu como configuras la de tu pais? Mira aqu seguro que encuentras el valor que necesitas para tu configuracin personalizada.

Comprobacin de PHP
Una vez que hayamos modificado los apartados anteriores y guardado el fichero con el nombre php.ini en el directorio C:/ServidoresLocales/php53 llega el momento de comprobar si PHP funciona correctamente.

Un script de prueba
Para hacer esta comprobacin deberemos escribir nuestro primer script PHP. Abriremos nuestro editor Notepad++ y escribiremosexactamente esto:

<?php phpinfo(); ?>


Ahora lo guardaremos en C:/ServidoresLocales/Apache/htdocs recuerda que este es el que hemos configurado como directorio raz de servidor con el nombre info.php Recuerda tambin que es probable que el bloc de notas haya aadido la extensin .txt y que el fichero puede haber sido guardado como info.php.txt. Lo comprobaremos mirando el directorio htdocs y cambiando el nombre si fuera necesario.

Probando el primer script


Una vez instalados y configurados Apache y PHP y creado el fichero info.php, ha llegado el momento de comprobar si hemos hecho correctamente las configuraciones y si todo funciona bien. Arrancaremos el servidor Apache y una vez que tengamos la ventana de MS-DOS abierta, deberemos visualizarla sin ningn mensaje (completamente en negro). Eso significara que Apache est funcionando correctamente con el mdulo PHP. Si apareciera algn mensaje de error sera necesario corregir la lnea del fichero de configuracin a la que se aluda en el propio mensaje. Solo faltara abrir el navegador y escribir una de estas dos direcciones: http://localhost/info.php o http://127.0.0.1/info.php y aparecera en pantalla una pgina como esta:

De ser as, el proceso de instalacin y configuracin habra terminado y esa pgina nos estara facilitando toda la informacin relativa a la configuracin actual de nuestro PHP.

Cuidado!
En la configuracin de PHP (php.ini) bajo Windows debemos usar siempre la barra invertida ( \ ) a la hora de escribir los paths. Cuando tratamos la configuracin de Apache (httpd.conf) tambin bajo Windows lo hemos hecho al revs, hemos escrito todos los paths utilizando la barra normal ( / ). Ten muy presente que estas sintaxis son distintas y cuando efectes modificaciones de configuracin utiliza la adecuada a cada uno de los ficheros.

Cuidado!
Aunque nuestra configuracin de short_open_tag = On nos permite utilizar como delimitadores del cdigo PHP tanto<?php ?> como <? ?> resulta ms aconsejable inclinarse por la primera opcin ya que nos garantizara que nuestros scripts podrn ejecutarse sea cual fuere la configuracin de esta directiva. Hemos de tener en cuenta que en nuestro servidor de pruebas tenemos posibilidades de modificar la configuracin pero puede haber casos en los que no tengamos acceso a esas opciones (servicios de hosting ajenos, por citar un ejemplo) y nos surjan dificultades que nos obliguen a modificar todo nuestro cdigo. Puede resultar un poco ms incmodo agregar la coletilla php pero seguramente es lo ms aconsejable.

Instalar MySQL 5.1.56 y/o MariaDB Proceso de instalacin ySQL


En esta pgina podrs encontrar el enlace de descarga del fichero mysql-essential-5.1.56-win32.msi que contiene el fichero de instalacin de MySQL. Para descargarlo va a ser necesario que te registres como usuario. Al hacerlo te enviarn a la direccin de correo que facilites una contrasea que te permitir acceder a la descarga. Tal como hemos comentado en el caso de programas anteriores es posible que la versin que encuentres all sea ms reciente que la que he incluido en el autoinstalador. Las versiones ms antiguas de MySQL puedes encontrarlas en este enlace. Al hacer doble clic sobre su icono comienza el proceso de instalacin cuya secuencia de pantallas sucesivas puedes ir viendo en la imagen que tienes aqu debajo.

Usaremos el directorio C:/ServidoresLocales/mysql para hacer la instalacin del servidor. Configuraremos el directorio que ha de contener las bases de datos como un subdirectorio (con nombre data) del anterior.

Pulsando sobre la flechas de la imagen podrs visualizar los diferentes pasos del proceso

Arrancar MySQL
Puesta en servicio desde la consola de MS-DOS
Una vez finalizado el proceso de instalacin ya podremos poner en marcha el servidor. Lo haremos desde el smbolo del sistema usando los comandos de MS-DOS. Para poner en marcha MySQL basta con situarnos en C:/ServidoresLocales/mysql/bin (subdirectorio bindel directorio en el que se efectu la instalacin de MySQL) mediante el comando: CD C:/ServidoresLocales/mysql/bin (subdirectorio bin y una vez all ejecutar:

A partir de ese momento el servidor MySQL ya estar activo y ya podramos gestionarlo tanto desde PHP como desde la propia consola MS-DOS.

Cuidado! En algunas versiones de Windows es posible que, al arrancar el servidor, se quede el cursor intermitente en la ventana de MS-DOS sin que regrese al prompt. Basta con cerrar la ventana Smbolo del Sistema y reabrirla. El servidor seguir activo y ya ser posible la ejecucin de comandos desde esta consola.

Apagar el servidor MySQL


Para poder apagar el servidor es necesario utilizar un nombre de usuario. En este caso utilizaremos el nombre de usuario root (el usuario que se crea por defecto). La sintaxis sera la siguiente:

Acceso a las bases de datos

Al instalar el programa se crea dentro del directorio mysql un subdirectorio llamado bin que es el que contiene los programas que gestionan las bases de datos en MySQL. Otro subdirectorio, denominado data, es destinado a contener todas las bases de datos. Cada una de ellas estar contenida en un subdirectorio diferente que tendr el mismo nombre que de la base que contiene. El instalador de MySQL crea de forma automtica dos bases de datos con los nombres: mysql ytest. No debes borrarlas! La denominada test es una base de datos que permite chequear la instalacin y la configuracin de MySQL mientras que la denominada mysql contiene, entre otros, los datos relativos a usuarios y si no est presente MySQL no funcionar. El acceso a las bases de datos MySQL requiere que los usuarios estn identificados mediante un nombre (login) y opcionalmente una contrasea (password) de acceso. El propio instalador de MySQL incluye, por defecto, un usuario con nombre root, que utiliza como password una cadena vaca. A cada usuario se le pueden asignar privilegios de modo que, por ejemplo, solo pueda realizar consultas, o acceder a tablas concretas. El usuario root goza de todos los privilegios posibles y podra ser usado para todos los supuestos. No obstante, como en situaciones reales es un usuario desaconsejable por el riesgo que entraa utilizar usuarios por defecto, vamos a crear un nuevo usuario con contrasea y con todos los privilegios que ser el que utilizaremos en los ejemplos relativos a MySQL.

Creacin de un nuevo usuario


Al nuevo usuario al que aludimos en el prrafo anterior vamos a darle los mximos privilegios (ALL PRIVILEGES) de modo que pueda gestionar cualquier base de datos, tabla y que adems pueda crearlas, borrarlas o modificarlas sin restriccin alguna. Es importante que lo creemos con la sintaxis exacta, ya que los ejemplos de los temas relacionados con MySQL estn desarrollados considerando el usuario pepe con contrasea pepa (ambas en minsculas).

Ejecutar instrucciones MySQL


El primer paso para poder ejecutar sentencias MySQL ser tener el servidor activo. Para ello habr que seguir el proceso descrito anteriormente. El paso siguiente sera especificar qu usuario va a manejar MySQL. Dependiendo de sus privilegios tendr accesos a parte o a todas las funciones. Para especificar el usuario root debemos escribir lo siguiente:

Si se tratara de un usuario con una contrasea distinta de la cadena vaca habra que aadir p detrs del nombre de usuario tal como puedes ver en esta imagen. En este caso el sistema nos pedir que escribamos la contrasea del usuario en cuestin.

Este mensaje de bienvenida y el cambio de directorio (observa que ahora el prompt ha cambiado y apunta hacia mysql) nos indican que MySQL est listo para recibir instrucciones.

Lo nico que haremos desde aqu ser crear un usuario. En adelante nos comunicaremos con MySQL a travs de la web y usando como herramienta de comunicacin el PHP.

Creacin del usuario pepe


Para crear el nuevo usuario utiliza exactamente la sintaxis que ves en la imagen.

Cuidado! El pulsar Enter en MySQL no significa como ocurre en DOS que se vaya ejecutar el comando. Si observas la imagen, hemos pulsado Enter detrs de la palabra localhost de la primera lnea y lo que ha ocurrido es que el cursor ha saltado hasta la segunda incluyendo automticamente > que significa que contina la instruccin anterior. En MySQL la ejecucin de una instruccin requiere que se haya tecleado ; inmediatamente antes del pulsar Enter.

Salir del interface de usuario


Para abandonar la interface de usuario basta con escribir exit tal como ves en la imagen. El sistema escribir su mensaje de despedida de forma automtica y el prompt regresar a C:/ServidoresLocales/mysql/bin.

Cuidado! Independientemente de que puedas crear otros usuarios con otras contraseas es imprescindible crear el usuariopepe con contrasea pepa. Todos los ejemplos que incluimos requieren este usuario.

Desinstalacin de MySQL
MySQL se desinstala desde la opcin Agregar o quitar programas como cualquier otro programa de Windows. El proceso de desinstalacin no elimina ni los ficheros ini ni tampoco el subdirectorio data. Este ltimo se conserva como medida de seguridad ya que contiene todas las bases de datos y de eliminarlo se perdera la informacin. Si en algn momento tratas de desinstalar para hacer una nueva instalacin, lo aconsejable sera mantener el directorio data y buscar y eliminar todos ficheros my.* (los ini de la instalacin anterior) antes de realizar la nueva instalacin.

Instalacin de MariaDB
Segn su pgina web oficial MariaDB es un servidor de base de datos que ofrece una alternativa funcional de reemplazo para MySQL. MariaDB est construido por algunos de los autores originales de MySQL, con la ayuda de la comunidad ms amplia de desarrolladores de software libre y de cdigo abierto. Adems de la funcionalidad principal de MySQL, MariaDB ofrece un rico conjunto de funciones mejoradas, incluyendo motores de almacenamiento alternativo, optimizacin del servidor, y los parches. Desde el punto de vista operativo podramos decir que MariaDB es a MySQL lo que LibreOffice es a OpenOffice. Es decir, son forks o derivaciones de aquellas, bajo licencia GPL (General Public License), cuyo nacimiento se justifica en los temores de lo que en un futuro pueda derivarse de las adquisin por parte de Oracle de Sun Microsystems que a su vez en propietaria de MySQL. Aunque se ofrece actualmente bajo la GNU GPL para cualquier uso compatible con esta licencia, MySQL es patrocinado por una empresa privada, que posee el copyright de la mayor parte del cdigo. Esa circunstancia es radicalmente distinta a lo que ocurre con otros proyectos como Apache, donde el software es desarrollado por una comunidad pblica y los derechos de autor estn fragmentados ya que cada porcin del cdigo es propiedad de su autor individual.

Especulaciones futuristas aparte, MariaDB est disponible en este enlace en su versin 5.3. Entre las mltiples opciones de descarga disponibles sugerimos marcar las casillas de verificacin correspondientes a Windows y a zip-file ya que no van a requerir ningn proceso de instalacin y, adems, van a permitirnos mantener en un mismo equipo una versin de MariaDB junto con otra de MySQL. Una vez hayamos descargado el fichero .zip bastara con descomprimirlo en cualquier lugar del equipo y ya estara disponible para su uso. Bastara con arrancarlo y pararlo utilizando exactamente los mismos comandos ya descritos para MySQL. La nica diferencia estara en que antes de ejecutar el comando MS-DOS mysqld de puesta en marcha de servidor habra que situar el prompt apuntando a subdirectorio bin del directorio en el que hayamos descomprimido MariaDB. El uso de una u otra base de datos slo requerira elegir el directorio bin de una u otra para ejecutar desde l los comando de puesta en marcha y parada. Respecto a la utilizacin desde PHP no hemos podido constatar diferencia funcional alguna. Es decir, todo lo descrito en estas Memorias para MySQL es absolutamente vlido, sin modificacin alguna, para el caso de que optes por usar la base de datos MariaDB.

Cuidado! Puede ocurrir que en un momento determinado no funcione correctamente MySQL (o MariaDB) y que al intentar acceder a la direccin http://localhost/phpMyAdmin/ lees un mensaje de error similar a este: #2002 - El servidor no est respondiendo (o el socket del servidor MySQL local no est configurado correctamente). Algunas veces el problema puede producirlo un exceso de limpieza. Algunas aplicaciones del tipo Ccleaner o similares pueden estar configuradas para que al ejecutarlas se borren los ficheros cuyo tamao sea cero bits. Esa accin podra eliminar algunos ficheros de ese tamao contenidos el subdirectorio /data/mysql y su inexistencia puede ser la causa del problema. Para comprobarlo podemos editar un fichero con extensin .err que suele tener el mismo nombre que el equipo y que est en el subdirectorio /data de mysql. Se identifica facilmente porque es el nico con esa extensin. Si vemos que contiene lneas similares a estas: [ERROR] Fatal error: Can't open and lock privilege tables: File '.\mysql\host.MYD' not found (Errcode: 2)n> File '.\mysql\plugin.MYD' not found (Errcode: 2 File '.\mysql\time_zone_leap_second.MYD not found (Errcode: 2) File '.\mysql\servers.MYD' not found (Errcode: 2) bastara con crear ficheros nuevos (desde el mismo bloc de notas) en blanco (sin ningn contenido) y guardarlos con esos nombres en el subdirectorio /data/mysql. Reiniciaramos el servidor y MySQL (o MariaDB) volvera a funcionar correctamente.

Instalando phpMyAdmin
Qu es PHPMyAdmin?
PHPmyAdmin es simplemente un conjunto de utilidades y scripts escritos en lenguaje PHP que permiten gestionar bases de datosMySQL a travs de una pgina web. Mediante esta herramienta, sin conocer el lenguaje MySQL, podremos modificar, consultar, crear y borrar tanto bases de datos como tablas y registros contenidos en ellas incluyendo la gestin de usuarios recuerda que MySQL requiere claves y contraseas y susprivilegios de acceso. La versin de MySQL para Windows no dispone de una interface propia que permita gestionar sus bases de datos a travs de Windows. La nica posibilidad de gestin es a travs de MS-DOS y eso requiere que el usuario sepa utilizar los comandos propios de las funciones MySQL. Sin esos conocimientos de SQL, tendramos como recurso la posibilidad de gestionar las bases de datos a travs de nuestros propios scripts PHP, pero eso nos exigira conocer con una cierta profundidad a medida que avancemos lo iremos logrando las funciones que PHP posee para este tipo de labores. Es por eso que este conjunto de herramientas resulta muy cmodo y fcil de utilizar y est convirtindose de hecho ya lo es en el soporte estndar que la mayora de los hosting facilitan a sus usuarios para gestionar las bases de datos alojadas en sus servidores.

Instalacin de PhpMyAdmin

En el sitio http://www.phpmyadmin.net/ hay un enlace para la descarga del fichero phpMyAdmin-3.3.10-all-languages.zip. Tal como venimos comentando en pginas anteriores es posible que ya se hayan producido actualizaciones y la versiones que veas no coincidan exactamente con la que aqu te referimos. No suele tener mayor transcendencia. Las versiones histricas de phpMyAdmin puedes encontrarlas en este sitio. El fichero zip obtenido en la descarga tenemos que descomprimir obligatoriamente (contiene scripts de PHP) en el directorioC:/ServidoresLocales/Apache/htdocs. Al hacerlo se crear un directorio llamado phpMyAdmin-3.3.10-all-languages al que vamos a cambiar el nombre por otro ms cmodo y fcil, dado que al utilizar phpMyAdmin tendremos que escribir el nombre de ese directorio con bastante frecuencia. Vamos a renombrarlo como phpMyAdmin. Ser necesario editar el fichero Config.class.php (contenido en el subdirectorio libraries de phpMyAdmin) y modificar la lnea n 25. Dnde dice: var $default_source = './libraries/config.default.php''; deberemos poner: var $default_source = './libraries/config.inc.php'; En el mismo subdirectorio libraries hay un fichero llamado config.default.php. Abrmoslo con nuestro editor Notepad ++, guardmoslo (sin hacer ninguna modificacin) con el nombre config.inc.php y, ya en este ltimo fichero, hagamos los cambios que se detallan en la tabla siguiente.

Fichero inicial Guardar como Lnea

config.default.php config.inc.php
Cambios Donde dice:

Modificaciones en el fichero config.inc.php

40

$cfg['PmaAbsoluteUri'] = '':
cambiar por:

$cfg['PmaAbsoluteUri'] = 'http://localhost/phpmyadmin/';
Donde dice:

177

$cfg['Servers'][$i]['auth_type'] = 'cookie';
cambiar por:

$cfg['Servers'][$i]['auth_type'] = 'config';
Donde dice:

227

$cfg['Servers'][$i]['nopassword'] = false;
cambiar por:

$cfg['Servers'][$i]['nopassword'] = true;
Donde dice:

363

$cfg['Servers'][$i]['AllowNoPasswordRoot'] = false;
cambiar por:

$cfg['Servers'][$i]['AllowNoPasswordRoot'] = true;

Hechas las modificaciones en ambos ficheros ya estaremos en condiciones de probar su funcionamiento.

Prueba de funcionamiento de phpMyAdmin


Arranquemos Apache dejando minimizada su ventana MS-DOS y arranquemos tambin MySQL. Con ambos servidores activos escribamos en el navegador la direccin: http://localhost/phpmyadmin/. Deber abrirse una pgina como esta:

Explorando los enlaces de la parte izquierda de la pantalla -mysql(23)- podremos visualizar los contenidos de la tabla user que nos dar una imagen como esta:

dnde podemos ver la lista de usuarios actuales y sus privilegios. Vemos el archi mencionado usuario root y tambin al nuevo usuariopepe con su contrasea encriptada. Las columnas marcadas con Y/N contienen las tablas de privilegios de cada usuario. Observa que tantoroot como pepe tienen todos los privilegios, mientras que, el tercer usuario (con nombre en blanco y creado durante la instalacin de MySQL) no tiene ninguno.

Instalacin del servidor FileZilla FTP Qu es un servidor FTP?


Conceptualmente un servidor FTP no difiere en nada de un servidor HTTP. Las diferencias entre los diversos tipos de servidores estriban en los programas que usan software de servidor en el tipo de peticin que aceptan y en el protocolo que requieren las peticiones que atiende.

En el caso de Apache se trata de un servidor HTTP porque slo acepta peticiones a travs de ese protocolo. Al hablar de servidores FTP nos referimos a aquellos que nicamente aceptan peticiones realizadas por medio del protocolo conocido como FTP (File TransferProtocol). Como en todos los dems casos, la comunicacin cliente-servidor requiere el uso por parte de ambos del software adecuado a su protocolo concreto.

Clientes FTP
Para hacer una peticin FTP, igual que en cualquier otro caso de peticin, necesitamos disponer del software adecuado para realizarla. Recuerda que, en realidad, un cliente no es otra cosa que el programa que se utiliza para realizar un determinado tipo peticin a unservidor. Existen varios clientes FTP en el mercado. Si no dispones de ninguno descargar FileZilla Client desde el sitio de FileZilla. Las versiones ms modernas de algunos navegadores tambin permiten realizar peticiones mediante este protocolo. Si escribimos en la barra de direcciones del navegador se requiere la versin 5 superior de Internet Explorer :ftp://super:superi@localhost y un servidor FTP con nombre localhost est activo, veremos que aparecen en la ventana del navegador los iconos de los ficheros contenidos en el directorio root del servidor y que, a la vez, se nos ofrece la posibilidad de: borrar archivos; crear subdirectorios; copiar ficheros (desde el servidor a cualquier otro directorio de nuestro ordenador o viceversa) sin ms que seguir mtodos idnticos a los que se utilizan habitualmente en Windows. El acceso a un servidor FTP salvo que permita el acceso de forma annima requiere del cliente tres datos: nombre del servidor,nombre de usuario y contrasea, que son los que aparecen en azul un poco ms arriba. En esa direccin aparecen marcados en rojo:(ftp://) que indica el tipo de protocolo que se utiliza en la peticin; (:) cuya finalidad es la de actuar como separador entre el nombre de usuario y la contrasea; y, (@), que hace tambin funcin de separador, en este caso entre la contrasea y el nombre del servidor. An a riesgo de parecer reiterativos, queremos insistir en que para que una peticin, como la que comentamos, pueda ser atendida se requiere, de forma imprescindible, que exista un servidor FTP activo. Hay una posibilidad aadida. Mediante funciones de PHP tambin es posible gestionar servidores FTP sin necesidad de recurrir a ningn cliente especfico. Lo trataremos en los contenidos de programacin relativos a las funciones FTP.

Instalacin de un servidor FTP


Se trata del instalador de un servidor FTP, que puedes descargar desde FileZilla_Server-0_9_37.exe y que tambin puedes encontrar en esta pgina. Igual que en pginas anteriores las versiones ms antiguas podemos encontrarlas aqu. Una vez descargado el instalador ya podemos seguir la secuencia de instalacin que puedes ir viendo en esta imagen.
Pulsando sobre la flechas de la imagen podrs visualizar los diferentes pasos del proceso

Arrancar y apagar el servidor

Despus de instalar el servidor aparecern en Programas un grupo con unos iconos como estos. Como resulta obvio, el sealado con Start permite la puesta en marcha del servidor y el sealado con Stopsirve para detener su funcionamiento. La opcin Server Interface para usarla es necesario que previamente hayamos puesto en marcha el servidor permite configurar del servidor y controlar su funcionamiento. Nos valdremos de l para llevar a cabo la configuracin de nuestro servidor FTP y nos permitir visualizar el estado del servidor y el registro todas las acciones que se realicen en l. Si has optado por la instalacin automtica de todos los programas bastar con que pulses sobre el icono correspondiente al servidor FTP desde la ventana de Gestin de Servidores.

Cuidado! Sobre Windows Vista y/o Windows 7 es necesario ejecutar este programa con privilegios de administrador. En vez de doble clic tpico pulsa con el botn derecho del ratn y elige la opcin de ejecutar como Administrador.

Definicin de los servicios

La imagen que tienes a la izquierda representa la forma ms compleja de la configuracin que pretendemos desarrollar en esta instalacin. Empezaremos por su forma ms sencilla. Para ello crearemos el directorio C:\servidorFTP que ser el directorio raz (o root) de nuestro servidor FTP. Igual que ocurra en el caso de Apache podra ser un directorio cualquiera de los existentes en el ordenador en el que tengamos instalado el software de servidor. Supongamos que nuestra intencin ofrecer tres servicios que requieren crear los subdirectorios:C:\servidorFTP\Alumnos, C:\servidorFTP\Documentacion y C:\servidorFTP\Gestion. Por el momento nos resultar suficiente con estos tres directorios. Ms adelante, para una configuracin ms avanzada, deberamos crear toda la estructura que puedes ver en la imagen con la excepcin de juan (sombreado en rojo) que se generara de forma automtica. Crearemos tres usuarios bsicos. A uno de ellos le llamaremos super (usuario que administra el sistema) y permitiremos que pueda acceder sin restriccin alguna a todo el contenido del directorioC:\ServidorFTP y de todos sus subdirectorios. Un segundo usuario llamado webmaster habr de tener iguales privilegios en el Document Root del servidor Apache (C:/ServidoresLocales/Apache/htdocs). El tercer usuario, secre, podr acceder tambin sin restricciones a los directoriosC:\ServidorFTP\Documentacin y C:\ServidorFTP\Gestion.

Cada usuario ha de disponer de un directorio raz (su root) que ha de contener todos los directorios a los que va a tener acceso aunque el hecho de que un directorio sea el root de un usuario no implica que pueda acceder a todos sus contenidos ya que para hacerlo es necesario que tenga -adems- permisos de acceso. Tal es el caso del usuario secre cuyo root ha de ser C:\ServidorFTP\ pese a que no va a tener privilegios de acceso al directorio Alumnos.

Privilegios de los usuarios


Esta ser la manera en la que asignaremos contraseas y privilegios a cada uno de los usuarios. Usuario super con contrasea superi. Sus privilegios en los diferentes directorios sern: Todos los privilegios en C:\servidorFTP. Al ser el usuario super parece razonable concederte el mayor grado de libertad. Usuario webmaster con contrasea superi. Tendr los privilegios siguientes: Todos los privilegios en C:/ServidoresLocales/Apache/htdocs. Las razones son idnticas al caso anterior. Usuario secre con contrasea superi. Va a tener los siguientes privilegios: List en c:\ServidorFTP. Al concederle este privilegio podra visualizar (al acceder a su root mediante un cliente FTP) la lista de directorios y documentos que contiene. Si no incluyramos esta opcin el cliente FTP nos dara un mensaje de error al acceder al root (no tendra permiso alguno) y obligara al usuario secre a establecer como root alguno de los directorios para los que tiene permiso de acceso. Todos los privilegios en Documentacin. Se entiende que este usuario es quien realiza la gestin completa de este directorio. Todos los privilegios en Gestin. Las razones son idnticas a las del caso anterior. En este enlace tienes el detalle y la justificacin de los diferentes privilegios que hemos establecido para cada uno de los restantes usuarios y grupos de usuarios que conforman la opcin ms compleja de nuestra propuesta.

Configuracin de FileZilla Server


Server Interface
Al activar el Server Interface por primera vez aparece una ventana como la que tienes aqu debajo. Si marcas la casilla de verificacin y pulsas OK ya no aparecer en posteriores arranques.

Aparecer una nueva ventana como la que puedes ver en esta otra imagen.

El primero de los iconos permite arrancar y detener el servidor desde esta consola. El segundo (en forma de candado) permite bloquear y desbloquear el servidor sin necesidad de detenerlo. Desde el tercero podremos hacer modificaciones generales en la configuracin. Optaremos por dejarlas con las opciones por defecto. Desde el cuarto, uno de los ms interesantes para nuestros propsitos, podremos crear cuentas de usuarios as como realizar su configuracin. El quinto de los iconos muy similar al anterior permite acceder a la configuracin de grupos de usuarios.

Creacin de cuentas de usuario


Empezaremos creando las tres cuentas de los usuarios bsicos: super, webmaster y secre utilizando las contraseas que hemos definido anteriormente. La forma de hacerlo es la que ves en la imagen inferior. Se pulsa en el icono user de la ventana Server interface (el cuarto de los iconos de la imagen que tienes aqu arriba) y aparece la ventana que ves en la parte inferior. La secuencia de creacin de un usuario es la siguiente: Selecciona general (1). Pulsa en el botn Add de la ventana de usuarios (2). Se abrir una nueva ventana. Se escribe -en la nueva ventana- el nombre de usuario(3). Se deja la opcin None (por defecto) en el men de opciones User should.. (4) y se pulsa el botn OK (5).

Al pulsar ok se cierra y se la ventana Add user account. Se marca las opcin Enable account (6). Se marca la casilla de verificacin Password (7) y se escribe la contrasea de usuario (8).

Repetiremos el proceso hasta crear las cuentas de los dos usuarios indicados al comienzo de este prrafo y acabaremos pulsando el botn OK que est situado en la parte inferior izquierda de la ventana de usuarios.

Eleccin de los roots los directorios accesibles y privilegios de cada usuario


A definir los servicios hemos decidido que al usuario webmaster se le va a permitir nicamente el acceso aC:/ServidoresLocales/Apache/htdocs (para la gestin del servidor Apache) por tanto su root ha de ser el directorioC:/ServidoresLocales/Apache/htdocs. Para el caso de super (el usuario que controla en su integridad el servidorFTP) hemos optado por c:\servidorFTP como root y cuando se trata del usuario secre hemos dicho que vamos a permitrle el acceso a c:\ServidorFTP\Documentacion y a c:\ServidorFTP\Gestiony que por ello hemos de establecer como root el directorio c:\ServidorFTP (nivel superior a ellos y que, por tanto, los contiene a ambos). El caso del usuario secre no es tan particular como pueda parecer ya que es bastante frecuente el hecho de que un usuario no deba acceder a los contenidos de todos los subdirectorios de su root. Cada uno de los directorios accesibles para un usuario (Shared folders) puede gozar de privilegios distintos. Al seleccionar un directorio se activan las casillas de verificacin que ves en la imagen y desde ellas se pueden conceder privilegios a dos niveles: ficheros ydirectorios. A nivel de ficheros cuenta con las opciones Read (descargar), Write (escribir, subir), Delete (borrar) y Append (aadir a un fichero preexistente cuando la transferencia ha sido interrumpida). Cada una de ellas puede configurarse como opcin permitida no permitida. Cuando se trata de directorios las opciones (tambin puede configurarse cada una de ellas como permitida/no permitida) son: Create(Crear), Delete (borrar), List (ver una lista de los contenidos) y +SubDirs (Cuando est activado asigna automticamente a todos los subdirectorios que contenga los mismos privilegios que al directorio actual). El proceso de establecimiento de la accesibilidad de un directorio (y la concesin de privilegios) es la que se detalla en la imagen. Se accede desde el icono users de la ventana Server Interface siguiendo la siguiente secuencia: Se elige Shared Folder en la ventana de la izquierda (1). Se elige un usuario User en la ventana de la derecha (2). Se pulsa en el botn Add en la parte central de la ventana (debajo de Shared Folders) (3) con lo que se abre automticamente la ventana Buscar carpeta. Se elige un directorio (4) y se pulsa sobre el botn Aceptar (5).

Se establecen los privilegios -marcando o desmarcando las casillas de verificacin correspondientes- para el directorio elegido (6). Se pulsa OK para guardar los cambios de configuracin (7). El proceso puede repetirse cuantas veces sea necesario.

Directorios accesibles por los usuarios super y webmaster


Esta es la configuracin del usuario super.

Para el usuario webmaster procederamos de forma idntica. La nica diferencia sera el directorio (C:/ServidoresLocales/Apache/htdocs) sobre el que estableceramos los mismos privilegios que se ven en la imagen para el usuario super.

Directorios accesibles por del usuario secre

La razn de estas asignaciones es posibilitar la eleccin de uno de los dos directorios Documentacion y Gestion con todos los privilegios. Como quiera que existe otro directorio del mismo nivel (Alumnos) al permitirle nicamente listar el que los contiene este ltimo le resultara inaccesible.

Observars que el directorio raz est marcado con la letra H. Para cambiarlo bastar con seleccionar otro cualquiera y pulsar sobre el botn que ves en esta imagen.

Acceso de usuarios
La direccin localhost apunta siempre hacia el directorio root de usuario. Eso quiere decir que si utilizando el FileZilla Client escribimos esa direccin y nos identificamos como secre (indicando la contrasea de usuario) veramos algo como esto:

que como puedes observar no es otra cosa que la visualizacin de los contenidos del directorio C:\ServidorFTP (el root de este usuario. Si nuestro equipo estuviera conectado a una red de rea local podramos acceder al servidor FTP escribiendo en vez de localhost la direccin IP del equipo en el que tuviermos instalado el servidor.

Cuidado! Es posible que el firewall de Windows nos bloquee el acceso al servidor FTP sin darnos ningn mensaje de advertencia. Lo ms conveniente para evitar problemas de esta ndole sera abrir Paneles de Control -> Firewall de Windows -> Excepciones y, una vez all, pulsar el botn Agregar Programas y aadir Filezilla Server.exe

Utilizacin de alias
Este servidor tambin permite ser configurado para la utilizacin de Alias. Pulsando con el botn derecho del ratn sobre el nombre de uno de los directorios aparece un men como este:

al elegir la opcin Edit Aliases se abre una ventana como la que ves aqu debajo. Si introducimos en ella la ruta absoluta completareemplazando el nombre del ltimo directorio por una palabra distinta (en el ejemplo hemos incluido web) estaremos creando un alias. Podremos crear tanto como deseemos, es cuestin de incluirlos (completos) uno a continuacin de otro separados por el carcter |.

Una vez creados los alias podremos utilizarlos para acceder a los espacios (sustituyendo el nombre del directorio por el alias). Aqu tienes imgenes del ejemplo. Observars que localhost/ServidoresLocales/Apache, localhost/servidor y localhost/indio nos conducen al mismo sitio.

Una configuracin ms compleja


Creacin de grupos de usuarios
La configuracin de grupos de usuarios es una opcin que ofrece bastante inters. Mediante esta opcin se pueden establecer privilegios comunes a una serie de usuarios. Ello facilita la configuracin cuando se trata de grupos numerosos que van a compartir directorios y privilegios. Sigue un proceso muy similar al que hemos descrito para el caso de usuarios. Las diferencias ms sustanciales son: Se accede a travs del icono groups (el quinto de la ventana Server Interface). No requiere insertar contraseas. Estas sern privilegio exclusivo de los usuarios del grupo. Requiere activar la casilla de verificacin Enable access for users inside group. En nuestro ejemplo, crearemos cuatro grupos: ingles (grupo de los profesores de Ingls), infor (profesores de Informtica), ciclo1(alumnos de primer ciclo) y ciclo2 alumnos de segundo ciclo.

Directorios accesibles y privilegios del grupo


La configuracin de los directorios accesibles y de los privilegios en cada uno de ellos es idntica a la descrita para el caso de usuarios no pertenecientes a un grupo. Al avanzar en esta configuracin ya sera necesario tener disponible la estructura de directorios y subdirectorios que se refleja en la imagen que tienes un poco ms arriba. La nica diferencia estriba en que aade una nueva e interesante posibilidad a travs de la opcin Autocreate. Supongamos que pretendemos que cada uno de los alumnos de nuestro supuesto disponga de un subdirectorio propio para podersubir y gestionar sus propios trabajos de cada materia. Aparte de la ventaja de tener separadas sus actividades con la posibilidad de borrar,aadir, modificar, etctera dentro de su propio espacio y a la vez impedir que pueda efectuar esos procesos en materiales ajenos. Eso requerira ir creando esos directorios para cada uno de los usuarios y esa podra ser una tarea lenta y pesada. Mediante la opcinAutocreate se puede configurar un directorio de forma que durante el primer acceso del usuario se cree de forma automtica un subdirectorio con el mismo nombre que el del usuario. El uso de esta opcin requiere: Incluir en Shared folders la ruta del directorio base (en el que pretenden crearse los subdirectorios de cada uno de los usuarios pertenecientes al grupo) acabada con /:u

Asignacin de usuarios a un grupo


Una vez creado un grupo (o grupos) es necesario asignar los usuarios a ese grupo. El proceso es muy similar al de creacin de usuarios no adscritos a ningn grupo. La nica diferencia est en el punto (4) del proceso, ya que ahora hemos de elegir el grupo al que va a pertenecer el usuario (antes elegamos none). En el ejemplo hemos incluido dos usuarios por cada uno de los grupos: profe_ingles1 y profe_ingles2 en el grupo ingles. profe_infor1 y profe_infor2 en el grupo infor. ciclo1_alumno1 y ciclo1_alumno2 en el grupo ciclo1. ciclo2_alumno1 y ciclo2_alumno2 en el grupo ciclo2. En todos los casos hemos incluido una contrasea idntica al nombre de usuario.

Los miembros de un grupo recogen automticamente todos los privilegios del Shared Folder del grupo al que pertenecen. No obstante, es posible aadir nuevos directorios y privilegios (aadidos a los especficos del grupo al que pertenecen) incluyndolos en elShared Folder del usuario. En este enlace tienes el detalle y la justificacin de los diferentes privilegios que hemos establecido para cada uno de los grupos de usuarios.

Cuidado! En este fichero, servidorftp.rar, tienes la estructura de directorios aqu descrita. Bastar con que la descomprimas en el directorio raz de tu equipo para que puedas utilizarla con los ejemplos aqu descritos.

Fichero de configuracin de Filezilla Server


Dado que, por el nmero de usuarios y por la complejidad de la estructura, la labor de configuracin y creacin de los diferentes usuarios aqu propuestos puede resultarte lenta y tediosa hemos incluido un fichero que puedes obtener http://www.rinconastur.com/php/filezilla.zip Si descomprimes su contenido -FileZilla Server.xml- en el directorio de instalacin de Filezilla Server (por defecto sera un directorio con ese mismo nombre dentro de Archivos de programa) sobrescribiendo el existente ya dispondrs de todos los usuarios y grupos aqu descritos junto con sus configuraciones respectivas.

Cuidado! En el enlace que figura en el prrafo anterior y aqu tienes la configuracin de los diferentes usuarios tal como se describen en esta pgina y en sus anexos.

Instalacin de un servidor de correo


Instalacin de Mercury Mail
El software de servidor de correo Mercury Mail est disponible en http://www.pmail.com donde puedes elegir la descarga de Mercury mail transport system for win32 and NetWare systems v.4.73 o bien directamente desde aqu. El proceso de instalacin es el que describen las imgenes siguientes:
Pulsando sobre la flechas de la imagen podrs visualizar los diferentes pasos del proceso

Los aspectos ms significativos de este proceso son los siguientes: Elegiremos como direccin local la IP 127.0.0.1 pensando exclusivamente en servidor para pruebas. Si quieras utilizarlo como servidor de correo en una red local habrs de sustituir la IP 127.0.0.1 por la correspondiente al ordenador en el que est instalado el servidor Para poder trabajar con cuentas externas a nuestra instalacin local hemos de tener en cuenta que en la ventana dnde dice:Address of host via which to send mail tenemos que incluir la direccin del servidor SMTP a travs del que se enviaran los mensajes a direcciones de correo externas. En las pruebas hemos utilizado varias (los SMTP de nuestras cuentas de correo) aunque, como ves en la imagen, la prueba definitiva la hemos hecho utilizando la direccin del servidor de usuarios de Educastur (smtp.educastur.princast.es), ya que su proceso de configuracin tiene la forma ms compleja dado que ese servidor requiere autentificacin del usuario.

Configuracin de PHP
Para que nuestro servidor de correo pueda ser utilizado mediante funciones de PHP es necesario que el fichero de configuracin de PHP, (php.ini) contenga los cambios ya propuestos al hablar de la configuracin de PHP. All habamos modificado concretamente las dos directivas: SMTP = 127.0.0.1 y sendmail_from=admin@mispruebas.as . Como es lgico, en el caso de optar por la instalacin de una red de rea local la IP asignada a SMTP habra ser la del equipo en el que estuviera instalado el servidor.

Arrancar y parar el servidor


Para arrancar el servidor hay que ejecutar el programa Mercury Loader. Lo encontrars en el directorio en que hayas instalado el servidor de correo (C:/ServidoresLocales/Mercury). Sabremos que est en marcha porque aparecer una ventana nueva. Si la minimizamos aparecer en la barra de tareas un icono como este.

Este icono solo aparece al minimizar la ventana. Si la cerramos se parar el servidor y desaparecer el icono. Aparte de la opcin anterior, desde el men del servidor tienes acceso a esta opcin que ve en la imagen.

Cuando est funcionando el servidor para pararlo aparece un texto como este. Si estuviera parado, se podra activar desde la misma opcin. Ahora aparecera con el texto: Leave offline mode

Configuracin del servidor de correo


Aadir usuarios y crear un dominio local
Esta imagen describe paso a paso el proceso de creacin de usuarios y configuracin de un dominio local. Crearemos dos dominios locales llamados localhost y mispruebas.as y aadiremos los usuarios juan, perico y andres a quienes pondremos contraseas idnticas a los nombres respectivos.
Pulsando sobre la flechas de la imagen podrs visualizar los diferentes pasos del proceso

Un script de prueba
Este es el cdigo fuente de un script que nos permitir comprobar si hemos configurado correctamente el servidor de correo. El contenido que aparezca en la pgina nos dir lo que ha ocurrido. No te preocupes si an no entiendes el cdigo! Ya hablaremos de l ms adelante.

<?php if( mail("juan@mispruebas.as", "Una prueba definitiva","Bienvenid@ a PHP", "From: Administrador de mispruebas.as <admin@mispruebas.as> Reply-To: juan@mispruebas.as Cc: perico@mispruebas.as Bcc: andres@mispruebas.as X-Mailer:PHP/" . phpversion())){ print "Mensajes enviados con exito"; }else{ print "Se ha producido un error"; } ?>

Configuracin del cliente de correo


La configuracin del cliente de correo Outlook Express o similar no plantea problemas. El proceso es muy similar a la configuracin de cualquier otra cuenta de correo. Los nicos detalles a tener en cuenta son los relativos a la configuracin de los servidores SMTP y POP3. En ambos casos se escribe la IP con la que hemos configurado el servidor, es decir: 127.0.0.1 o la del equipo que soporte el servidor en el caso de una red local. Como nombre de cuenta pondremos el mismo con el que las hemos creado (juan, perico, andres) sin aadir la @ ni el nombre del dominio.

Pruebas del servidor


Una vez configuradas las cuentas en el cliente de correo bastar con enviar mensajes a las direcciones de usuarios locales (con el servidor Mercury activo) y comprobar que son recibidos en las cuentas destinatarias.

La segunda de las pruebas el funcionamiento a travs de PHP podremos hacerla arrancando ambos servidores (Apache y Mercury) pulsando en el enlace que tienes un poco ms arriba y comprobando despus, a travs del cliente de correo, que se ha recibido el mensaje en las cuentas de los tres usuarios de pruebas.

Leer mensajes de cuentas externas


Puede resultarte interesante configurar el servidor de correo de forma que puedan recibirse en una cuenta local los mensajes enviados a una -o varias- cuenta externas. Se trata de el servidor local compruebe y descargue los eventuales mensajes que pudieran haberse recibido en una cuenta externa. En esta imagen tienes, a modo de ejemplo, la descripcin de la configuracin de este servidor para que el usuario juan pueda leer desde su cuenta local los mensajes recibidos en la de educastur.
Pulsando sobre la flechas de la imagen podrs visualizar los diferentes pasos del proceso

Enviar mensajes a cuentas externas


Mercury permite enviar mensajes (a travs del servidor configurado como Address of host via which to send mail ) a direcciones de correos correspondientes a dominios externos. La configuracin de esa opcin requiere el proceso que puedes ver aqu debajo. All tiene la forma de configurar el servidor para que permita el envo de mensajes a direcciones no locales a travs del servidor smtp externo que hemos configurado al efectuar la instalacin. Al enviar mensajes desde una cuenta local hacia una cuenta externa la direccin de respuesta por defecto sera la local. Eso, obviamente, planteara problemas al destinatario ya que sus respuestas no encontraran ese dominio en la red. Bastara con modificar la configuracin del cliente de correo incluyendo como direccin de respuesta la de una cuenta externa.
Pulsando sobre la flechas de la imagen podrs visualizar los diferentes pasos del proceso

Cuidado! La gestin de mensajes externos puede plantear problemas derivados de los filtros antispam de los servidores de correo de la red que pueden bloquear el envio o recepcin de los mensajes enviados utilizando este servidor.

Desinstalacin del servidor de correo


Durante la instalacin de Mercury no se escribe nada en el registro de Windows. Por ello, el proceso de desinstalacin no existe. Basta con borrar del directorio de instalacin y habremos desinstalado el servidor.

Cifrado con clave simtrica


Comunicacin segura
El objetivo de la comunicacin segura es que la confidencialidad de informacin transmitida evitando tambin el riesgo de que pueda ser modificada o manipulada durante el proceso de intercambio. Por medio del protocolo SSL Secure Socket Layer (una de las opciones ms populares) se puede ocultar a ojos de teceros la informacin que fluye, de forma bidireccional, entre el servidor y el cliente. Para lograr tales propsitos es necesario recurrir a alguno de procedimientos criptogrficos que describiremos a continuacin.

Cifrado simtrico
Supongamos que A y B convienen enviarse mensajes cifrados y acuerdan reemplazar las vocales por los nmeros 1 al 5. De esa forma cuando uno de ellos pretenda escribir la palabra poetisa utilizar la grafa: p42t3s1. El receptor del mensaje podr reemplazar los nmeros por su vocal equivalente y recomponer el mensaje. Este sera un ejemplo muy simple de cifrado simtrico o con clave privada.

El grado de inseguridad de un sistema de cifrado simtrico est condicionado por dos factores. Uno de ellos, comn a todos los sistemas de cifrado, es la mayor o menor resistencia que pueda presentar a los intentos de descubrir la clave a base de ensayo y error(fuerza bruta). Normalmente, un aumento del tamao de la clave representa un incremento la seguridad. El otro problema, el ms grave, es la falta de certeza sobre la identidad de remitente. No hay nada que nos de garantas sobre quienha cifrado el documento. De todas formas veremos un poco ms adelante como subsanar estos inconvenientes ya que este es el mtodo de cifrado que se utiliza habitualmente cuando se navega por pginas seguras. Existen varios algoritmos de cifrado simtrico. Uno de los ms populares es el conocido como DES adoptado como un estndar, para comunicaciones no clasificadas, por el Gobierno de los EE.UU. en 1976. Su grado de eficiencia qued muy cuestionado cuando, en 1998,Electronic Frontier Foundation logr fabricar una mquina capaz de descifrarlo en tres das. Esta circunstancia forz la aparicin de versiones mejoradas tales como el DES mltiple y otras que han logrado paliar en gran medida sus deficiencias iniciales y hacer de DES mltiple un algoritmo de uso bastante frecuente. El algoritmo IDEA (International Data Encryption Algorithm) es otro de los que aperecen, en este caso en 1992, como opciones alternativas al uso de DES mltiple. No fu el nico. En octubre de 2000 el National Institute for Standards and Technology (NIST) adopt del algoritmo RIJNDAEL como nuevo Estndar Avanzado de Cifrado (AES) para su empleo en aplicaciones criptogrficas no militares. PHP5 dispone de funciones de cifrado para una gran variedad de algoritmos. Aqu tienes una lista de los algoritmos de cifrado que soporta actualmente.

Adems de los distintos algoritmos de cifrado hay otro elemento diferenciador. Se trata de lo conocido como modo de cifrado. Los algoritmos de cifrado suelen trabajar con bloques de longitud fija. La cadena objeto del cifrado es descompuesta en bloques de igual tamao y tratada de diferentes modos. En los llamados ECB (Electronic CodeBook) cada bloque es cifrado de forma independiente. En otros modos, por ejemplo el CBC (Cipher Block Chaining), a cada bloque de texto plano se le aplica una operacin que requiere el uso del texto de bloques anteriores. En estos casos, para hacer cada mensaje nico ha de utilizarse un vector de inicializacin. Aqu tienes la lista de los modos de cifrado soportados por tu versin de PHP.

Funciones PHP de cifrado simtrico


Configuracin de PHP
PHP dispone de funciones que permiten efectuar algunos tipos de cifrado. Antes de nada y como siempre en estos casos es conveniente comprobar en el fichero info.php si estn activadas estas opciones.

En el caso de la versin PHP 5.3.6 para Windows esta opcin viene activada por defecto. Igual ocurre en el caso de PHP 5.3 en Ubuntu 10.10. Por el contrario, en versiones anteriores de PHP es necesario, adems de seguir el proceso de configuracin que se indica en el enlace, descomentar de su fichero php.ini, quitando el punto y coma (;) que por defecto lleva delante la extension=php_mcrypt.dll. Si en alguna versin de Ubuntu no viniera configurado por defecto podra instalarse ejecutando desde la consola el siguiente comando:

sudo apt-get install php5-mcrypt

Proceso de cifrado y descifrado


Los procesos de cifrado y descifrado mediante PHP son muy similares y requieren, en ambos casos, la siguiente secuencia de funciones: $identificador=mcrypt_module_open(algoritmo, ubicacion, modo, directorio) Abre un nuevo mdulo de cifrado identificado por el valor la variable $identificador. Requiere estos parmetros: algoritmo es una cadena que ha de contener, entre comillas, el nombre del algoritmo que pretendemos utilizar. Ser uno de los nombres de la lista antes mencionada y que puedes ver nuevamente desde este enlace. El parmetro ubicacion permite especificar el directorio con la eventual ubicacin del algoritmo de cifrado en el caso de que se usara uno distinto a los incluidos en la distribucin de PHP. Lo habitual ser que pongamos como valor una cadena vaca de la forma "". El parmetro modo ser una cadena en la que se especifique el modo de cifrado que pretendamos utilizar y habr de contener uno de los valores (escrito entre comillas) que tenemos en este enlace. Por ltimo, el parmetrodirectorio ser habitualmente una cadena vaca "" ya que est definida para establecer el modo del directorio eventualmente establecido en el parmetro ubicacion. Iniciado el mdulo de cifrado y segn el modo de cifrado establecido puede resultar necesario crear un vector de inicializacin cuya longitud se determina por medio de la funcin: $longitud=mcrypt_enc_get_iv_size($identificador)

en la que $identificador es el identificador de recurso establecido por la funcin anterior y $longitud la longitud de del mencionado vector de inicializacin. Conocida la dimensin $longitud del vector de inicializacin (puede ser cero en el caso de que no sea requerido su uso) debemos crearlo invocando la funcin: $vector=mcrypt_create_iv($longitud, constante) donde $longitud es resultado de la funcin anterior y constante es la constante MCRYPT_RAND que debemos incluir sin comillas. El resultado, $vector, ser el vector de inicializacin. El paso siguiente ser iniciar todos los buffers necesarios para el posterior proceso de cifrado o de descifrado. De esa labor se encarga la funcin: mcrypt_generic_init($identificador, clave, $vector) en la que $identificador es el identificador del recurso, clave es una cadena que se usar como CLAVE DE CIFRADO y $identificador el identificador del recurso y $vector es el vector de inicializacin. El ltimo paso ya ser el cifrado o descifrado propiamente dichos. Si se trata de cifrar utilizaremos: $cifrado=mcrypt_generic($identificador, texto) donde texto es una cadena (o variable) que contiene el texto que pretendemos cifrar y donde $identificador sigue siendo el identificador del recurso. El resultado del cifrado es recogido en la variable $cifrado Si se trata de descifrar la funcin anterior debe ser sustituida por $descifrado=mdecrypt_generic($identificador, $cifrado) siendo $cifrado la variable (ocadena) cifrada que pretendemos desencriptar y $descifrado el resultado de la desencriptacin. Llegados a este punto, solo nos restara liberar los buffer reservados para el cifrado y cerrar el recurso mediante las funciones: mcrypt_generic_deinit($identificador) y mcrypt_generic_close($identificador) De esta forma se consigue un mtodo de cifrado y descifrado aplicable con cualquiera de los algoritmos y modos de cifrado disponibles.

Ejemplos de cifrado y descifrado simtrico


Un ejemplo de como puede cifrarse con clave simtrica podra ser este:

<?php # establecemos la clave y la cadena a encriptar $clave = "clave"; $texto ="Esta es una cadena de prueba"; /*creamos un identificador de encriptado en el que indicamos el tipo de cifrador (cast-128) y el modo de cifrado (ecb) */ $ident = mcrypt_module_open('cast-128', '', 'ecb', ''); /* dado que algunas funciones requieren de un vector de inicializacion acorde con sus especificaciones esta funcin determina el tamao de ese vector atendiendo al tipo de identificador */ $long_iniciador=mcrypt_enc_get_iv_size($ident); /* crea el vector de inicializacin con valores aleatorios y dndole la dimensin precalculada en la funcin anterior */ $inicializador = mcrypt_create_iv ($long_iniciador, MCRYPT_RAND); /* hacemos algunas comprobaciones innecesarias para ejecutar el script. Simplemente son descriptores de algunas funciones complementarias */

/* comprobamos el tamao maximo (en bytes) que puede tener la clave para este algoritmo de cifra*/ print "La clave no puede sobrepasar los "; print mcrypt_enc_get_key_size ($ident)." bytes<br>"; /* escribimos el tamao del bloque del algoritmo que estamos usando*/ print "El tamao del bloque de cifrado es "; print mcrypt_enc_get_block_size($ident)." bytes<br>"; print "El modo de cifrado es "; print mcrypt_enc_get_modes_name($ident)."<br>"; print "El algoritmo de cifrado es "; print mcrypt_enc_get_algorithms_name($ident)."<br>"; print "El tamao del vector de inicializacin es "; print mcrypt_enc_get_iv_size ($ident)."<br>"; /* Contimuamos la secuencia de encriptado incializando todos los buffer necesarios para llevar a cabo las labores de encriptado */ mcrypt_generic_init($ident, $clave, $inicializador); /* realiza el encriptado proopiamente dicho */ $texto_encriptado = mcrypt_generic($ident, $texto); /* libera los buffer pero no cierra el modulo */ mcrypt_generic_deinit($ident); /* esta instruccion es necesaria para cerrar el modulo de encriptado*/ mcrypt_module_close($ident); # imprimimos el resultado de la encriptacin # en este caso aadimos una codificacin de ese resultado en base 64 print "La cadena encriptada es: ".base64_encode ($texto_encriptado); /* guardamos la cadena encriptada en un fichero con nombre encriptado */ file_put_contents('encriptado',$texto_encriptado); print "<br> est codificada en base 64"; ?>
Ejecutar ejemplo de encriptado

El proceso inverso, la desencriptacin de una cadena codificada puede hacerse de la forma que se indica en el siguiente ejemplo.

<?php /* hemos de usar la misma clave con la que ha sido encriptado */ $clave = "clave"; /* leemos el fichero encriptado creado por el script anterior */ $texto_encriptado =file_get_contents('encriptado'); /*creamos un identificador de encriptado que ha de ser el mismo con el que hemos realizado la encriptacin */ $ident = mcrypt_module_open('cast-128', '', 'ecb', ''); /* dado que algunas funciones requieren de un vector de inicializacion acorde con sus especificaciones esta funcin determina el tamao de ese vector atendiendo al tipo de identificador anterior*/ $long_iniciador=mcrypt_enc_get_iv_size($ident); /* crea el vector de inicializacin con valores aleatorios y dndole la dimensin precalculada en la funcin anterior */ $inicializador = mcrypt_create_iv ($long_iniciador, MCRYPT_RAND); /* incializa todos los buffer necesarios para llevar a cabo las labores de encriptado */ mcrypt_generic_init($ident, $clave, $inicializador); /* realiza el desencriptado proopiamente dicho. Realmente es la unica diferencia bsica entre este script y el ejemplo anterior */ $desencriptado = mdecrypt_generic($ident, $texto_encriptado); /* libera los buffer pero no cierra el modulo */ mcrypt_generic_deinit($ident);

/* esta instruccion es necesaria para cerrar el modulo de encriptado*/ mcrypt_module_close($ident); # imprimimos el resultado de la encriptacin # en este caso aadimos una codificacin de ese resultado en base 64 print $desencriptado; ?>
Ejecutar ejemplo de descifrado

Cuidado! Si al intentar ejecutar el ejemplo anterior sobre Ubuntu observas slo una pgina en blanco comprueba que el directorio en el que ests ejecutando el script tenga permisos de lectura/escritura. De no disponer de ellos no se guardara el fichero con los datos encriptados y por es misma razn tampoco se visualizara.

El protocolo de Diffie-Hellman
Una de las debilidades del cifrado con clave simtrica reside en la necesidad de que ambas partes intercambien su clave de cifrado de forma confidencial. Esa confidencialidad puede conseguirse, incluso en comunicaciones de forma no segura, mediante una tcnica conocida como protocolo de Diffie-Hellman.

Nmeros y sus races primitivas


Este protocolo requiere la utilizacin de dos nmeros que llamaremos p y g. El nmero p habr de ser un nmero primo, por lo general muy grande, mientras que g ha de ser una raz primitiva de p. Sin abundar en aspectos demasiado tcnicos podemos decir que g es raiz primitiva de p si el conjunto de los restos de dividir entre p cada de las sucesivas potencias de g desde 1 hasta p1 1 2 3 p-1 1 (g , g , g , g , ... g ) contiene a todos los naturales {1,2,3,4..., p-1}. Eso significara que para cualquier entero b menor que p y una raz primitiva g del nmero primo p, se puede encontrar un nico i exponente ital que b = g (mod p) donde 0 i (p-1). El exponente i se conoce como el logaritmo discreto o ndice de b para la base g, mod p. Este valor se representa como indg,p(b). En la tabla que tienes a continuacin puedes ver el proceso de comprobacin de raices primitivas desarrollado para dos supuestos. Observa que en el caso de g=13 los restos de las divisiones se repiten (lo cual significa que hay valores que no aparecen) y por tanto 13 no es raz primitiva de 23. Por el contrario, al comprobar el comportamiento de g=7 puedes ver los restos son, de forma no ordenada, los nmeros naturales comprendidos entre 1 y 22. Por tanto g=7 si es raz primitiva de 23.

Comprobacin de las races primitivas


z 1 2 3 4 5 6 7 8 9 p=23, g=7 (7 ES raz primitiva de 23) gz 7 49 343 2401 16807 117649 823543 5764801 40353607 Cociente entero gz/p 0 46 322 2392 16790 117645 823538 5764789 40353592 282475236 1977326721 13841287185 96889010387 678223072847 4747561509929 33232930569595 232630513987188 p=23, g=13 (13 NO ES raz primitiva de 23) Resto gz/p gz 7 3 21 9 17 4 5 12 15 13 22 16 20 2 14 6 19 13 169 2197 28561 371293 4826809 62748517 815730721 10604499373 137858491849 1792160394037 23298085122481 302875106592253 3937376385699289 51185893014090757 665416609183179841 8650415919381337933 Cociente entero gz/p 0 161 2185 28543 371289 4826803 62748508 815730719 10604499370 137858491833 1792160394036 23298085122468 302875106592245 3937376385699277 51185893014090739 665416609183179837 8650415919381337927 Resto gz/p 13 8 12 18 4 6 9 2 3 16 1 13 8 12 18 4 6

10 282475249 11 1977326743 12 13841287201 13 96889010407 14 678223072849 15 4747561509943 16 33232930569601 17 232630513987207

18 1628413597910449 19 11398895185373143 20 79792266297612001 21 558545864083284007

1628413597910431 11398895185373132 79792266297611993 558545864083283997

18 11 8 10

112455406951957393129 1461920290375446110677 19004963774880799438801 247064529073450392704413

112455406951957393120 1461920290375446110675 19004963774880799438798 247064529073450392704397

9 2 3 16

22 3909821048582988049 3909821048582988048 1

3211838877954855105157369 3211838877954855105157368 1

Obtencin e intercambio de claves


Intecambiados de forma pblica dos nmeros p y g tales que g es raz primitiva de p, cada uno de los dos usuarios que x y pretenden encontrar una clave comn y secreta genera sendos nmeros XA=g (mod p) y XB=g (mod p) donde x e y son nmeros cualesquiera (secretos, ya que no sern intercambiados), menores que p. Ambos usuarios intercambian sus nmeros. A facilita a B su XA y B proporciona a A el valor XB. Cada usuario eleva a su clave secreta el valor pblico recibido del otro usuario y obtiene el resto de dividir el resultado entre el x y nmero p. Es decir, el usuario A efecta la operacin: KA=(XB) (mod p) mientras que B calcula: Kb=(XA) (mod p). Ambos resultados son iguales dado que se verifica que: KA= (XB) (mod p)= (g ) (mod p)=(g )(mod p), y tambin que: KB= (XA) (mod p)= (g ) (mod p)=(g )(mod p) confirmdonse por tanto que ambos resultados han de ser iguales y que su valor ser la clave simtrica buscada. La prctica imposibilidad de que un tercero pueda obtener la clave radica en el hecho de que para calcularla es necesario conocer, al menos, uno de los nmeros que hemos llamado secretos (x y) y aunque es cierto que pueden ser conocidos XA, XB, p y x g (se transmiten o pueden transmitir de forma no segura) para romper la clave sera preciso buscar la solucin a XA=g (mod p) (logaritmo discreto de XA para la base g mdulo p) tarea de muy alta dificultad (nada resulta imposible) cuando se trata de valores de p muy grandes. En esa dificultad radica precisamente la robustez de este protocolo desarrollado en 1976 por Whitfield Diffie y Martin Hellman. Este es un ejemplo del procedimiento de clculo de una clave de cifrado simtrico mediante el protocolo de Diffie-Hellman.
y x y xy x y x yx

Obtencin de una clave comn y secreta para cifrado simtrico Usuario A Usuario B
Acuerdan, de forma pblica, un nmero y una de sus races primitivas clave y un generador. Establezcamos esos nmeros como:

p=23 y g=7
Elige un nmero natural secreto (puede hacerlo al azar) Elige un nmero natural secreto (puede hacerlo al azar)

9
Eleva g al numero elegido, lo divide entre p y determina el resto de esa divisin

3
Eleva g al numero elegido, lo divide entre p y determina el resto de esa divisin

Resto de 79 entre 23 =15


Enva el nmero anterior a B Eleva el valor recibido (21) a su clave secreta y calcula el resto de dividir ese resultado entre p (23).

Resto de 73 entre 23 =21


Enva el nmero anterior a A Eleva el valor recibido (15) a su clave secreta y calcula el resto de dividir ese resultado entre p (23)

Resto de 219 entre 23=17

Resto de 153 entre 23=17

Ambos obtienen el mismo resultado. Ese valor, solo conocido por ellos, ser la clave de cifrado simtrico La identidad del comunicante como problema de seguridad
Admitiendo la invulnerabilidad (que nunca lo es del todo) del protocolo de Diffie-Hellman y la robustez de los algoritmos de cifrado simtrico tendramos una ms que aceptable seguridad del carcter confidencial (e incluso la integridad) de la informacin intercambiada. Pero queda en el aire una pregunta muy importante. Qu garantas nos ofrecen estas tcnicas de que los comunicantes son los que dicen ser? Quien nos garantiza que no han sido suplantadas sus identidades? Podemos evitar que uno de los comunicantes pueda negar, an habindolo hecho, haber enviado una determinada informacin?. Por el momento la respuesta es no. Sern necesarios otros recursos para solventar ese problema. Tenemos pendiente resolver la autentificacin ( que cada parte de la comunicacin pueda asegurarse de que la otra parte es realmente quien dice ser) y el no repudio (permite a cada uno de los comunicantes probar de forma fehaciente que el otro ha participado en la comunicacin de forma que el remitente

del mensaje no pueda negar haberlo enviado o (caso de no repudio de destino), el destinatario del mensaje no puede negar haberlo recibido. Para resolver esos problemas hemos de recurrir a procedimientos bastante similares a los de la vida cotidiana. Lo primero de todo sera firmar la informacin de la misma forma que se firma un cheque, una carta, un certificado o una solicitud. Esa accin no sera otra cosa que firmar digitalmente nuestros mensajes. Ni en la comunicacin cotidiana ni en la digital resulta de suficiente garanta la firma de un documento. Todos sabemos que puede ser ms o menos hbilmente imitada. La firma manuscrita puede ser falsificada. Necesitamos algn tipo de garanta ms. Cuando en un centro de enseanza se expide un certificado lo habitual es que vaya con la firma del secretario, el visto bueno del director y el sello del centro. Es decir, la firma del director es una garanta de la fidelidad de la del secretario. Puede que no confiemos lo suficiente en la firma del director Autoridad Certificadora y que demandemos la legitimacin notarial de la firma del secretario. La nica diferencia sera el mayor rango de la Autoridad Certificadora. Desde luego siempre podemos seguir desconfiando. De estos asuntos trataremos en los temas siguientes.

Cifrado con clave asimtrica Cifrado asimtrico


El protocolo de Diffie-Hellman que hemos visto en la pgina anterior es un claro ejemplo de lo que se conoce como cifrado asimtrico. A la hora de convenir la clave de cifrado cada uno de los intelocutores utilizaba dos claves. Una de carcter pblico (poda ser conocida sin riesgo) y otro de carcter privado dado que el usuario la mantena en secreto. El primero de los nmeros sera el conocido como clave pblica y el segundo de ellos la clave privada. El cifrado asimtrico, tambin llamado cifrado de clave pblica se fundamenta la utilizacin conjunta de esas dos claves. En el esquema puedes ver las posibilidades que ofrece el uso de este algoritmo en sus dos opciones. Lo cifrado con la clave pblica de un usuario puede ser descifrado con su clave privada. De igual forma, lo cifrado con la clave privada ser descifrado con su clave pblica.

A partir de esas premisas y tal como se ve en el esquema es factible establecer la estrategia para garantizar la confidencialidad y, en cierta medida (hablaremos de esto ms adelante) la autenticidad del remitente.

El algoritmo RSA
El algoritmo de cifrado asimtrico ms popular en este momento es el conocido como RSA (acrnimo de los apellidos de los criptlogos Ronald L. Rivest, Adi Shamir y Leonard Adleman que fueron quienes lo desarrollaron en 1977). La aplicacin de este algoritmo requiere tres pasos:

Generacin de claves
Es un proceso que sigue la siguiente secuencia: Cada usuario elige aleatoriamente dos nmeros primos distintos p y q, pero con longitudes en bits parecidas. La fortaleza de la clave est condiciona en gran medida por el tamao de estos dos nmero que suelen ser muy grandes alcanzando actualmente el 200 orden de 10 y con previsin de aumento de forma simultnea a la capacidad de clculo de los ordenadores. Se calcula el valor n = p*q al que se conocer como mdulo. Se calcula el valor Z=(p-1)*(q-1). Se elige un entero positivo e conocido como exponente de la clave pblica que ha de ser menor que n, que sea coprimo de l. Se determina un valor d, al que se llama exponente de la clave privada, que cumpla a condicin de que d*e (mod Z)=1. Obtenidos esos valores, el par (n,e) ser la clave pblica y (n,d) la clave privada de carcter secreto. Los tamaos habituales de las claves son actualmente de 1024 2048 bits de longitud. En el cuadro que tienes a continuacin intentamos ejemplificar, con valores minsculos, los mecanismos de generacin de claves utilizando este algoritmo.

Algoritmo asimtrico RSA Nmero Ejemplo p 3 q 11 n=p*q 3*11=33 Z=(p-1)*(q-1) (3-1)*(11-1)=20

d Par (n,e) Par (n,d)

Proceso de clculo Primo muy grande. Aleatorio Primo muy grande. Aleatorio Se calcula el producto p*q Producto Calculado Se calcula un nmero que sea: - Primo 7 - Coprimo de Z. Es decir, MCD (e,Z)=1 cumple la condicin - Positivo - <Z 3 Ha de cumplirse que cumple la condicin - d*e (mod Z)=1 Resto de (7*3)/20=1 Par (33,7) Clave pblica- Mdulo y exponente Par (33,3) Clave privada- Mdulo y exponente

Cifrado y descifrado
En este cuadro tienes un ejemplo de funcionamiento del cifrado/descifrado de un nmero. Hablamos de nmeros porque cuando se utiliza este procedimiento las cadenas de caracteres se convierten en bloques numricos (utilizando los cdigos ASCII de los caracteres) agregando al resultado un mtodo de camuflaje conocido como Paddings Schemes que consiste en aadir algunos bits al mensaje de forma que el proceso de cifrado incluya esos bits aadidos que minimizan riesgos de vulnerabilidad de propio proceso.

Cifrado con clave privada y descifrado con clave pblica numero=5 Para cifrar se eleva el nmero a cifrar al valor de la clave privada y se 53(mod 33)= determina el resto de dividir el resultado entre n (numero)d (mod Resto de n) (53)/33=26 53=125; cociente entero 125/33=3; resto de la divisin=26 cifrado=26 ya que: 3*33+26=99+26=125 Para descifrar eleva el nmero cifrado al valor de la clave pblica y se cifrado=26 determina el resto de dividir el resultado entre n 267(mod 33)= e (cifrado) (mod Resto n) 267=8031810176; cociente entero 8031810176/33=243388187; (267)/33=5 resto de la divisin=5 numero=5 ya que: 243388187*33+5=8031810171+5=8031810176 Cifrado con clave pblica y descifrado con clave privada numero=5 Para cifrar se eleva el nmero a cifrar al valor de la clave pblica y se 57(mod 33)= determina el resto de dividir el resultado entre n (numero)e (mod Resto de n) (57)/33=14 57=78125; cociente entero 78125/33=2367; resto de la divisin=14 cifrado=14 ya que: 2367*33+26=78111+14=78125 cifrado=14 Para descifrar eleva el nmero cifrado al valor de la clave privada y se 143(mod 33)= determina el resto de dividir el resultado entre n (cifrado)d (mod Resto de n) (143)/33=5 143=2744; cociente entero 2744/33=83; resto de la divisin=5 numero=5 ya que: 83*33+5=2739+5=2744
Obviamente los ejemplos anteriores no son otra cosa que muestras simplificadas de los procedimientos aritmticos de cifrado y descifrado.

Limitaciones del algoritmo RSA


El cifrado asimtrico presenta algunos problemas operativos tales como: Para una misma longitud de clave y mensaje se necesita mayor tiempo de proceso. Las claves deben ser de mayor tamao que las simtricas
Tabla comparativa de tamaos de claves de similiar resistencia a ataques de fuerza bruta

Simtrica 64 bits 80 bits 112 bits 128 bits

Asimtrica 512 bits 768 bits 1792 bits 2304 bits

Certificados digitales
Certificado digital
Cuando recibimos informacin cifrada con clave asimtrica pueden darse varias situaciones. Entre ellas estas:

Cifrado con nuestra clave pblica

Solo nos garantiza la confidencialidad de la informacin dado que solo nosotros podremos descifrarlo pero nos oculta la verdadera identidad del remitente ya que cualquiera que haya tenido acceso a nuestra clave pblica (cualquier usuario de la red podra haber tenido acceso a ella) pudo haberlo enviado.

Cifrado con clave privada


Tampoco nos garantiza la identidad del remitente. Slo nos asegura que ha sido enviado por la misma persona que nos facilit la clave pblica. Eso no garantiza en ningn modo la identidad. Slo prueba la concordancia entre la clave privada y la clave pblica. Es evidente que se requiere algo ms y eso puede ser un certificado digital.

Qu es un certificado digital?
Es un documento digital mediante el cual un tercero confiable garantiza la vinculacin entre la identidad de un sujeto o entidad y su clave pblica. Podramos considerarlo como algo muy similar al documento nacional de identidad espaol (en otros pases seguramente existe un documento equivalente). El D.N.I. requiere que sea expedido por una entidad confiable (la Direccin General de la Polica) que garantiza que los datos que figuran en l corresponden a la persona fsica cuya fotografa, datos, firma y huella dactilar aparecen impresos.

Tipos de certificado digital


Dependiendo de la informacin que contiene cada uno y la finalidad con la que se emiten existen diferentes tipos de certificado digital. Para nuestro propsito resultan de particular inters:

Certificados personales
Acreditan la identidad del titular que ha de ser una persona fsica. Su finalidad es la firma electrnica de documentos con garantade: la identidad del emisor, el no repudio de origen, la integridad y, si se requiere, la confidencialidad del contenido. Tambin pueden ser usados para la autentificacin de usuarios en sistemas que requieran un control de acceso sustituyendo los clsicos nombre de usuario y contrasea. En Espaa, las muestras ms genuinas de este tipo de certificado son el el DNIe o el CERES - FNMT que emite de forma gratuita a peticin de cualquier ciudadano espaol la Fbrica Nacional de Moneda y Timbre. En el primer caso necesitamos un lector de tarjetas integrado en el propio teclado o accesible a travs de una conexin USB externa el certificado va incluido en el propio DNIE que tiene caractersticas de tarjeta criptogrfica y en el segundo puede obtenerse mediante la descarga de un fichero a travs de internet o adquiriendo en la FNMT una tarjeta criptogrfica que lo contenga.

Certificado de servidor seguro


Son certificados destinados ser instalados en los servidores para asegurar su identidad frente a los usuarios que acceden.Garantizara que el sitio web es el original, que no ha sido suplantado y que nadie ajeno al titular ha podido alterar la informacin publicada. Este tipo de certificados no suelen ser gratuitos son los emitidos por Autoridades Certificadoras (CA) tales como: Verisign, Thawte, RSA Security o GeoTrust por mencionar solo algunos de los ms conocidos internacionalmente. Normalmente su precio vara dependiendo del plazo de validez y del prestigio de la entidad certificadora.

Certificado de autoridad certificadora


Una Autoridad Certificadora (CA) es una entidad en la que confan el emisor y el receptor de una comunicacin. La confianza del emisor y del receptor en ella implica que ambos confan en los documentos firmados por la Autoridad Certificadora de su confianza. Los certificados de estas entidades llamados certificados raz las CA se certifican a si mismas tienen por nica finalidad permitir que sean verificables los certificado de terceros (servidores y/o clientes) expedidos por ella. Suelen tener carcter pblico son descargables como ocurre con el del DNIe.

Emisin de certificados
Tcnicamente resulta sumamente fcil crear certificaciones de todo tipo y tambin convertirse en autoridades de certificacin. El propio PHP dispone de funciones capaces de crear ese tipo de documentos y existen, adems, aplicaciones gratuitas OpenSSL, por citar la herramienta que nosotros vamos a utilizar que realizan la misma funcin en cuestin de muy pocos segundos. El problema est en laconfianza.

Por poner un ejemplo. Cualquiera podra disear un bonito diploma acadmico y emitir ttulos de doctor en Medicina en cualquier mercadillo callejero. Puede que incluso uno de esos ttulos pudiera llegar a manos de un facultativo de acreditadsimo prestigio. El problema sera, desde el punto de vista de la certificacin, que ningn hospital la aceptara como vlida. Estara fracasando la confianza, por un NO reconocimiento de autoridad certificadora. Pongamos un segundo ejemplo. Nadie en Espaa ni en la Comunidad Europea pondra en cuestin nuestra identidad si mostranos nuestro DNI. La autoridad certificada de la Direccin General de la Polica sera reconocida en toda Europa pero tendra la misma validez en China o en USA?. Seguramente no. All solo reconoceran el pasaporte como documento acreditativo de nuestra identidad. De igual forma, una autoridad certificadora (CA) podr tener un mayor o menor reconocimiento (vinculado a las garantas de veracidad y seguridad que ofrece). De ese grado de reconocimiento, entre otras cosas, suele depender el precio. Las CA deben prestar especial atencin a garantizar que nadie ms que ellas pueden realizar su firma. Esa es la razn por la que ha de convertirse en algo casi obsesivo la custodia e inaccesibilidad de su clave privada. Si un tercero pudiera hacerse con ella estara en disposicin de emitir certificaciones falsas con la misma calidad que si permitieran a un falsificador hacer uso de las instalaciones y materiales de la FNMT.

Proceso de firma de un certificado


Cuando un entidad certificadora recibe una peticin de certificado lo procesa de la forma siguiente: Elabora el certificado incluyendo la informacin relativa a solicitante y entidad certificadora. Aplica un algoritmo de hash que no es otra cosa que una funcin matemtica que procesa los datos contenidos en el documento y obtiene a partir de ellos una cadena corta de caracteres huella digital que tiene la peculiaridad de que su valor resultara alterado por la ms mnima modificacin del documento original. Cifra con su clave privada la huella digital y la incluye dentro del certificado del cliente.

Comprobacin de un certificado
Para comprobar la validez de un certificado debemos seguir un proceso inverso al anterior. Se separa la firma digital de la entidad certificadora del documento. A partir de ah, mediante la clave pblica de la entidad certificadora, puede desencriptarse la huella digital contenida en la firma del certificado. Paralelamente se aplica el algoritmo de hash al documento y se determina su huella digital. Si su valor coincide con el extraido de la firma digital ya tendramos la certeza de que el certificado no ha sufrido modificacin alguna. Es un documento autntico.

Por otra parte el descifrado con clave asimtrica de la huella incluida en el certificado nos garantiza que, adems de no haber sido alterado, ha sido firmado realmente por la autoridad certificadora y no por otros. En la pgina siguiente veremos como configurar un servidor seguro y como establecer comunicaciones seguras utilizando este tipo de certificados.

Certificados auto firmados


Vamos a ver el procedimiento de creacin de certificados digitales auto firmados. Para ello disponemos de una aplicacin conocida como OpenSSL que nos va a permitir crearlos sin otra limitacin que nuestro escaso prestigio como Autoridad Certificadora.

Configuracin de OpenSSL
Tanto la versin de Apache que te he sugerido en pginas anteriores como la de nuestra instalacin automtica ya incluyen OpenSSL pero debemos configurar PHP para poder utilizarlo adecuadamente. Bastar con descomentar la lnea 963 del fichero php.ini que tienes en el subdirectorio php53 y donde dice: ;extension=php_openssl.dll quitar el punto y coma, guardar los cambios y reiniciar el servidor Apache. Al acceder a http://localhost/info.php debers visualizar algo como esto:

Si tu sistema operativo es Ubuntu debers instalar primero y habilitar despus el mdulo SSL ejecutando desde la consola los siguientes comandos: sudo apt-get install apache2 libapache-mod-ssl sudo a2enmod ssl

Si eres usuario de Windows habrs de hacer una modificacin en las variables de entorno del sistema. Para ello debes acceder a: Inicio-> Configuracin-> Paneles de control--> Sistema -> (configuracin Avanzada*)-> Opciones avanzadas ->botn Variables de entorno

y comprobar si existe una variable del sistema (parte inferior de la ventana)con nombre OPENSSL_CONF y como valorC:/ServidoresLocales/Apache/conf/openssl.cnf. En caso de que no existiera tendramos que pulsar sobre la opcin Nueva y rellenar una ventana como esta que ves en la imagen:

Una vez hayas pulsado Aceptar debers reiniciar el equipo para que el cambio de configuracin surta efectos.

Cuidado! El valor de la variable del sistema OPENSSL_CONF ha de ser la ruta absoluta hasta el fichero openssl.cnf que se incluye por defecto en directorio conf de Apache cuando se instala la versin que incluye openssl (en nuestro casohttpd-2.2.17-win32-x86-openssl-0.9.8o.msi). El fichero se identifica por su icono (no se visualiza su extensin que es .cnf)

Si eventualmente necesitsemos editarlo habramos de recurrir al shell de la consola de windows y ejecutar el comanto: edit C:/ServidoresLocales/Apache/conf/openssl.cnf

Creacin de certificados digitales


Mediante la aplicacin OpenSSL que suele venir configurada por defecto en la versiones de Ubuntu y cuya versin para Windows puede encontrarse en en este enlace podemos crear nuestros propios certificados digitales desde la consola de Ubuntu o desde el cmd.exe de windows siguiendo un proceso como el que se describe en las diferentes ventanas de esta imagen.
Pulsando sobre la flechas de la imagen podrs visualizar los diferentes pasos del proceso

Siguiendo el proceso descrito en la imagen, y para facilitarte la labor hemos incluido aqu un fichero llamado certificados.zip que contiene, entre otros, los siguientes ficheros: CA_privada.key, CA_solicitud.csr, CA_certificado.crt son la clave privada, la solicitud de certificado y el certificado digital autofirmado de una Autoridad Certificadora ficticia creada a modo de ejemplo. Servidor_privada.key, Servidor_solicitud.csr, Servidor_certificado.crt son la clave privada, la solicitud de certificado y el certificado digital de un servidor ficticio. Han sido expedidos por la Autoridad Cerficadora ficticia mencionada en el prrafo anterior. Cliente_privada.key, Cliente_solicitud.csr, Cliente_certificado.crt y Cliente_certificado.p12 son los nombres de los documentos correspondientes a la clave privada, solicitud y certificados digitales expedidos a un usuario ejemplo (cliente) por la Autoridad Cerficadora ficticia. Todos ellos han sido creados siguiendo el proceso descrito grficamente en las imgenes anteriores.

Manejo de certificados digitales de cliente


Una vez dispongamos de un certificado digital de cliente habremos de instalarlo en el navegador de nuestro equipo. En las imgenes se describen los pasos de las diferentes opciones de manejo de este tipo de certificados digitales.
Pulsando sobre la flechas de la imagen podrs visualizar los diferentes pasos del proceso

Qu hay dentro de un certificado digital?


Si abrimos el fichero que contiene el certificado de cliente que hemos creado anteriormente nos encontraremos con una cadena de texto resultante de un proceso de codificacin en base 64. Esa informacin es algo ms transparente si recurrimos al uso de la funcin PHPopenssl_x509_parse tal como puedes ver en los ejemplo siguiente:
Certificado original Ver cdigo fuente Contenido certificado Ver cdigo fuente

Podrs observar que contiene (y se puede visualizar) informacin relativa al titular del certificado, perodo de validez, identidad del emisor, etctera. Algo bastante parecido a un DNI tradicional. Hay entre toda la informacin un campo relevante. Observa que hay un valor llamado hash que es la huella digital resultante de aplicar la funcin hash durante proceso de emisin del certificado digital. Es un elemento decisivo para poder comprobar la autenticidad del certificado. Su verificacin ser realizada de forma automtica por el navegador del cliente.

Servidor seguro en Windows


Comunicacin en modo seguro
Una comunicacin en modo seguro mediante el protocolo HTTPS se desencadena de la forma siguiente:

Al iniciarse, por parte del cliente, una sesin (una peticin https://) el navegador enva al servidor un saludo (HELLO) compuesto por una cadena de texto generada de forma aleatoria y la informacin relativa a las versiones de SSL y algoritmos de cifrado que puede soportar. El servidor responde informando de la versin de SSL y mtodo de cifrado aceptados (el ms robusto de los soportados por ambos) y enva otra cadena de texto tambin generada de forma aleatoria. El servidor facilita al cliente su certificado digital y su clave pblica de cifrado. El cliente verifica el certificado digital del servidor y opta por aceptar o rechazar la comunicacin. Cuando el cliente trata de acceder a reas en las que se exige disponer de algn tipo de certificado el servidor le solicita ese certificado digital. Cuando el cliente, atendiendo a un requerimiento del servidor, facilita su certificado digital el servidor inicia un proceso de verificacin de cuyo resultado depende la aceptacin o rechazo la comunicacin. Finalizado de forma favorable el proceso de identificacin el cliente genera una clave aleatoria, la encripta con la clave pblica del servidor y se la enva. El servidor recibe la clave, la desencripta con su llave privada (cifrado asimtrico). Si este proceso resulta fallido ser sntoma de que existe discordancia entre la claves y que no hay certeza de que el servidor sea quien dice ser. Por el contrario, si todo va bien, se confirma la identidad de servidor y contina el proceso El cliente notifica al servidor que, en adelante, toda la informacin que facilite ser encriptada con la clave acordada. Adems, utilizando esa misma clave, encripta una hash (una huella digital) de toda conversacin mantenida hasta el momento y la enva al servidor. Si el servidor puede desencriptar el hash anterior es sntoma de que la clave es correcta y si, adems, el valor de ese hashcoincide con el que crea el servidor con los mismos datos (la informacin intercambiada hasta el momento) se confirma que todo funciona correctamente. Como ltima comprobacin el servidor enva, tambin encriptado con la clave acordada, su hash junto con el aviso de cambio a modo cifrado. El cliente desencripta, compara ambos hash y de resultar coincidentes confirma de forma definitiva que ambos comparten la misma clave (simtrica) y que estn en condiciones de comunicarse en forma segura. Al finalizar la sesin segura se destruye la clave que ambos compartan.

Configuracin del servidor Apache en modo seguro


Area segura del servidor
Es bastante frecuente que los servidores dispongan de dos reas. La zona no segura a la que se accede mediante el protocolo HTTPy la zona segura en la que ser imprescindible utilizar el protocolo HTTPS. Nuestro propsito es que el servidor web tenga una configuracin tradicional no segura en la que el directorio raz seaC:/ServidoresLocales/Apache/htdocs y restringir nicamente a modo seguro el acceso a uno de sus subdirectorios. Para ello, crearemos un subdirectorio de C:/ServidoresLocales/Apache/htdocs ponindole como nombre zona_segura. El paso siguiente ser acceder a http://localhost/info.php y comprobar que tenemos activo el mdulo SSL. Deberemos ver que OpenSSL supportaparece en modo enabled.

Si no lo estuviera deberemos activar ese mdulo tal como se describe en esta pgina.

Certificados de servidor

El primer paso mantener una comunicacin segura es tener la certeza de que realmente estamos en comunicacin con quien pensamos que lo estamos haciendo. Como hemos descrito ms arriba, el protocolo HTTPS requiere con carcter ineludible que el servidor disponga de un certificado digital. Estos certificados puedes extraerlos del fichero certificados.zip o crearlos siguiendo el proceso descrito enesta pgina Una vez dispongamos de los certificados digitales hemos de colocarlos en algn lugar del equipo que alberga el servidor Apache sin que sea en ningn caso necesario ubicarlos dentro del root de servidor. Crearemos un subdirectorio con nombre certificados enC:/ServidoresLocales/Apache/ siendo, por tanto, su ruta absoluta C:/ServidoresLocales/Apache/certificados e incluiremos en l los documentos servidor_certificado.crt (certificado digital del servidor) y Servidor_privada.key (clave privada).

Modificaciones en el fichero httpd.conf


Una vez hayamos creado los directorios zona_segura y certificados e incluido en este el certificado y la clave privada del servidor ya estaremos en disposicin de poder modificar la configuracin del servidor Apache para su uso en modo seguro. Las modificaciones requeridas son las siguientes:

Fichero inicial Guardar como Abrir Lnea

httpd.conf httpd_noseguro.conf httpd.conf


Cambios Donde dice:

La copia de seguridad nos permitir recuperar la configuracin actual si es necesario.

Modificaciones en el fichero inicial Justificacin Con esta modificacin estamos indicando a Apache que escuche las peticiones recibidas tanto a travs del puerto 80 (modo no seguro) como a travs del puerto 443 (utilizado habitualmente para las peticiones en modo seguro). Indicamos a Apache que debe cargar el mdulo SSL que es el que permite tramitar las peticiones de comunicacin en modo seguro.

46

Listen 80 #
cambiar por:

Listen 80 Listen 443


Donde dice:

120

#LoadModule ssl_module modules/mod_ssl.so


cambiar por:

LoadModule ssl_module modules/mod_ssl.so


Agregar:

<Directory "C:/ServidoresLocales/Apache/htdocs/zona_segura"> SSLRequireSSL </Directory>

SSLRequireSSL establece el modo seguro como nico modo de acceso al directorio zona_segura. Cualquier peticin no realizada mediante el protocolo https ser rechazada. NameVirtualHost es una directiva de Apache que permite especificar la IP a travs de la que un host virtual puede recibir las peticiones. Al indicar *:443 estamos sealando como vlida cualquier IP siempre que utilice el puerto 443 que es el reservado para conexiones seguras.

NameVirtualHost *:443

Final del documento

<VirtualHost *:443> SSLEngine On SSLOptions +StdEnvVars +ExportCertData SSLCertificateFile "C:/ServidoresLocales/Apache/certificados/Servidor_certificado.crt" SSLCertificateKeyFile "C:/ServidoresLocales/Apache/certificados/Servidor_privada.key" DocumentRoot "C:/ServidoresLocales/Apache/htdocs/zona_segura" ErrorLog C:/ServidoresLocales/Apache/logs/error.log LogLevel warn </VirtualHost>

Comentamos en la parte inferior de esta tabla los contenidos de estas lneas

Lo contenido entre <VirtualHost> y </VirtualHost> son las directivas que se aplicarn solo al host virtual al que acabamos de aludir. Hemos incluido las siguientes: SSLEngine On que es la directiva que habilita el uso del motor SSL del servidor. SSLOptions es una directiva a travs de la que pueden establecerse condiciones especficas en los directorios a los que precede. Esas condiciones pueden ir

precedidas de un signo + o de un signo -. En el primer caso se entiende que la nueva condicin se agrega a las preexistentes. En el segundo caso, signo menos-, estaramos indicando que se desactive esa condicin manteniendo activas las dems. Activaremos dos de ellas: +StdEnvVars y +ExportCertData. De esta forma podremos leer y utilizar desde PHP la informacin contenida en las variables de entorno del servidor y en los certificados del cliente y del servidor. SSLCertificateFile es una directiva imprescindible para poder indicar la ruta absoluta hasta el certificado del servidor. SSLCertificateKeyFile igual que el anterior, indicando esta la ruta absoluta hasta la clave privada de cifrado del servidor. DocumentRoot especifica la ruta absoluta hasta el directorio que ser considerado como DocumenRoot de este servidor virtual que trabajar en modo seguro. ErrLog especifica la ruta absoluta hasta el fichero que ha de recoger el informes sobre errores producidos durante el funcionamiento del servidor. LogLevel establece los tipos de eventos que van a registrarse como errores. En este caso se registrarn desde advertencias (warn) y/o los errores de mayor gravedad que estas

Una pgina de prueba


Antes de reiniciar el servidor con la nueva configuracin crearemos una pgina de prueba que puede tener unas caractersticas similares a esta.

<?php print "Ests en la zona segura del servidor"; ?>


La guardaremos con nombre index.php en el directorio zona_segura del servidor Apache. Comprobaremos los resultados de intentar acceder a estas direcciones: https://localhost, http://localhost y http://localhost/zona_segura/ En le primer caso (https) estaremos accediendo en modo seguro y por lo tanto seremos dirigidos a la pgina index.php que hemos incluido en el directorio zona_segura que es el DocumentRoot del servidor cuando trabaja en ese modo. En el segundo caso (http) estaremos accediendo en modo no seguro y visualizaremos la pgina index alojada en htdocs (directorio raz del servidor). El tercer supuesto, intento de acceder en modo no seguro (http) a un directorio seguro (zona_segura) nos dar un mensaje de error y nos ser impedido el acceso.

Mensajes de advertencia en los navegadores


Hechas las modificaciones en la configuracin y reiniciado el servidor los intentos de acceso en modo seguro (requiere escribirhttps:// en vez del clsico http:// que los navegadores aaden por defecto) van a aparecernos algunos mensajes de advertencia tales como los que puedes ver en los diferentes apartados de este grfico.
Pulsando sobre la flechas de la imagen podrs visualizar los diferentes pasos del proceso

Formatos de los certificados


Los certificados digitales pueden tener diferentes formatos. Los ms comunes son el formato DER (un formato binario utilizado bsicamente por Java y por Macintosh) y el formato PEM (una representacin de los certificados DER en base64, con marcas de inicio y final). El primero es el formato en el que el Cuerpo Nacional de Polica nos facilita los certificados raz del DNIe cuyos ficheros disponibles puedesver en este enlace de dnde podremos descargar el fichero ACRAIZ-SHA1.zip que vamos a utilizar para la configuracin de nuestro servidor. La FNMT nos permite descargar su certificado raz FNMTClase2CA.cer en ese mismo formato DER. El servidor Apache requiere que los certificados tengan formato PEM (que coincide coun el certificados autofirmados que hemos creado en pginas anteriores. Por tanto nuestros certificados van a poder ser utilizados sin ninguna modificacin por el servidor Apache.

Los certificados emitidos por la Direccin General de la Polica y por la FNMT tienen formato DER y por tanto es preciso hacer un cambio de formato (de DER a PEM) para poder utilizarlos en Apache. La transformacin puede hacerse mediante OpenSSL ejecutando el siguiente comando: openssl x509 -in nombre_del fichero_der -inform DER -out nombre_del_fichero_pem -outform PEM Para facilitarte la tarea hemos incluido en el fichero certificados.zip los certificados raz del DNIe y de la FNMT transformados a formatoPEM por medio de los siguientes comandos: openssl x509 -in ACRAIZ-SHA1.crt -inform DER -out RaizDNIe.crt -outform PEM openssl x509 -in FNMTClase2CA.cer -inform DER -out RaizFNMT.crt -outform PEM Tenemos por tanto los certificados raz de tres entidades certificadoras: nuestra propia CA (CA_certificado.crt, en formato PEM), elDNIe (ACRAIZ-SHA1.crt, en formato DER, y su equivalente en formato PEM, RaizDNIe.crt) y la FNMT (FNMTClase2CA.cer en formato DER y su equivalente en formato PEM, RaizFNMT.crt)

Accesos restringidos
Podemos establecer conexiones en modo seguro con un servidor si que se nos exija cumplir ningn requisito. El concepto seguro significara que el servidor posee un certificado digital y que la informacin circula encriptada mediante una clave simtrica pero desconociendo la identidad del cliente. Son habituales las webs que requieren un registro previo del usuario en el que se le facilita un nombre de usuario y contrasea que le sern requeridas siempre que intente acceder a un rea restringida del servidor. Disponiendo de un servidor seguro es posible exigir al cliente que disponga de un certificado digital (certificado de cliente) para acceder al rea segura del servidor o algunos de sus directorios. Veamos como hacerlo. Empezaremos creando un subdirectorio de zona_segura al que pondremos el nombre de restringido e incluiremos en l una pgina, a la que llamaremos index.php, que nos permita hacer la comprobacin de funcionamiento y que puede contener algo como esto:

<?php print "Aqu solo acceden los usuarios autorizados"; ?>


Nuestro propsito es que slo puedan acceder acceder al directorio restringido los cliente que dispongan de: nuestro certificado autofirmado de pruebas, de un DNIe o de un certificado de la FNMT. Establecer esa exigencia nos obliga a configurar Apache de forma que sepa qu ha de requerir un certificado de cliente y, adems,qu tipo o tipos de certificados debe considerar vlidos. Esto se logra a travs de la directiva SSLCACertificateFile que debe ir seguida de la ruta absoluta hasta un nico fichero que ha de contener el certificado o certificados raz de las entidades certificadoras a cuyos usuarios se va a permitir el acceso. En el epgrafe anterior hemos visto como obtener, en formato PEM, los tres certificados (CA_certificado.crt, RaizDNIe.crt yRaizFNMT.crt). Hemos de juntarlos en un nico fichero. Para ello podemos crear un fichero nuevo en blanco (con Notepad++, el bloc de notas o cualquier otro editor de tu eleccin) e ir incluyendo en l, uno tras de otro, los contenidos de los tres ficheros anteriores. Una vez guardemos el fichero resultante podemos ponerle como nombre todos.crt en el almacn de certificados del servidor (C:/ServidoresLocales/Apache/certificados) ya solo nos faltara modificar el fichero de configuracin de Apache para que contemple la nueva situacin. La modificaciones a realizar son las que puedes ver en esta tabla

Fichero inicial Guardar como Abrir

httpd.conf http_seguroparcial.conf
Nos permitir recuperar la configuracin actual si es necesario

httpd.conf
Trabajaremos sobre la configuracin previa una vez asegurada una copia de ella Donde dice:

Modificaciones en el fichero inicial

SSLCertificateKeyFile "C:/ServidoresLocales/Apache/certificados/Servidor_privada.key""
insertar inmediatamente despus

SSLCACertificateFile "C:/ServidoresLocales/Apache/certificados/todos.crt"

Agregar inmediatamente antes de la etiqueta de cierre </VirtualHost> que hay al final del fichero :

Final del documento

<Directory "C:/ServidoresLocales/Apache/htdocs/zona_segura/restringido"> SSLVerifyClient require SSLVerifyDepth 2 SSLRequire (%{SSL_CLIENT_V_REMAIN} >= "0") </Directory>

Se trata de sealar la existencia un fichero con los certificados raz de las entidades certificadoras autorizadas mediante la directivaSSLCACertificateFile seguida de la ruta absoluta hasta el fichero que contiene tales certificados y de indicar qu directorio debe restringirse y cuales son las condiciones de acceso. Esto se indica en el contexto de las etiquetas <Directory > y </Directory >. Dentro de la etiqueta de apertura indicamos la ruta absoluta del directorio objeto de la restriccin (en este caso ser restringido) y entre la etiqueta de apertura y cierre incluimos las restantes directivas. Mediante el valor require de la directiva SSLVerifyClient Apache interpretar que debe exigir uno de los certificados de usuario permitidos para acceder al directorio en el que se incluye tal directiva. Si esta directiva no se incluyera entre las etiquetas <Directory></Directory> se entendera que la directiva habra de afectar a todo el espacio del servidor seguro. Con las modificaciones anteriores el servidor ya debera funcionar de acuerdo con nuestros propsitos. Sin embargo, si observas con detenimiento las propuestas de modificaciones, vers que hemos incluido la directiva SSLVerifyDepth 2. Esto es consecuencia de la inclusin de la opcin DNIe. La Autoridad de Certificacin de Primer Nivel de la Direccin General de la Polica slo emite certificados para s misma y para sus tres autoridades certificadoras subordinadas. Por tanto, ninguno de los certificados incluidos en los DNie es emitido por la Autoridad Certificadora de primer nivel. Quien certifica nuestro DNIe es una de las tres entidades subordinadas (segundo nivel) que dependen de aquella. Por medio de la directiva SSLVerifyDepth 2 lo que hacemos es indicarle a Apache que, si es necesario, profundice hasta ese segundo nivel para comprobar la validez del certificado del cliente. Aunque es un aspecto que ser comentado con un poco ms de profundidad en prrafos suguientes, la lnea dnde dice SSLRequire (%{SSL_CLIENT_V_REMAIN} >= "0") tiene como finalidad que Apache impida el acceso a usuarios cuyos certificados del cliente han superado su perodo de validez (qu han caducado). Hechas estas modificaciones y reiniciado Apache podremos comprobar que para acceder a la direccin https://localhost" no es preciso disponer de ningn certificado. Por el contrario, si pretendemos acceder a https://localhost/restringido/ nos ser requerido uno cualquiera de estos tres certificados: nuestro certificado autofirmado, un certificado de la FNMT el DNIe.

Condicionando las restricciones


En la configuracin anterior establecimos como nica condicin para el acceso al directorio restringido disponer de uno de los certificados permitidos y que este no hubiera expirado (un poco ms abajo comentamos la directiva SSLRequire que es la que hace esta comprobacin). Vamos a crear ahora dos nuevos subdirectorios en la zona_segura. A uno le llamaremos dnie y al otro certificado. Incluiremos en cada uno de ellos, una pgina con nombre index.php para hacer las pruebas de funcionamiento. El acceso al primero dnie lo limitaremos a los usuarios que dispongan de un DNIe o un certificado de la FNMT e impediremos que pueda hacerlo quien slo disponga del certificado autofirmado creado para nuestros ejemplos. Para el acceso al directorio certificado invertiremos las condiciones. Slo estar permitido el acceso autentificndose mediante el certificado autofirmado. Dado que en el fichero todos.crt estn incluidos los certificados raz de las tres entidades certificadoras permitidas, las nuevas limitaciones requieren hacer uso de la directiva SSLRequire. Veamos que ocurre con ella. Cuando hacemos una peticin en modo seguro y la directiva SSLOptions est configurada +StdEnvVars se transfieren al servidor una serie de variables de entorno cuyos nombres y valores para cada uno de los tres tipos de certificado (lgicamente con datos ficticios) puedes ver en este enlace:
Variables de entorno

Los valores que se visualizan en este ejemplo son el resumen de la comprobacin de los tres tipos de certificados digitales y han sido obtenidos desde PHP mediante funciones similares a esta: <?php print getenv('SSL_CLIENT_S_DN');?> dnde a la funcin getenv se el incluye como parmetro el nombre de una variable de entorno. Aqu tienes el cdigo fuente del script que hemos utilizado para leer todas esas variables (https) y la lista de sus nombres.

Si observamos con un poco de detenimiento la tabla del enlace anterior podremos ver que hay una variable de entorno llamadaSSL_CLIENT_V_REMAIN que recoge los das que faltan hasta la fecha de caducidad de cada uno de los certificados. Tambin podemos ver como SSL_CLIENT_I_DN_OU recoge los valores: certNORA, FNMT Clase 2 CA y DNIE y que en SSL_CLIENT_I_DN_Ose incluyen: ACREDITACIONES DEL NORA, S.L.U., FNMT y DIRECCION GENERAL DE LA POLICIA. Mediante la directiva SSLRequire y manejando esas variables, a las que se alude mediante la sintaxis %{nombre de la variable} , los operadores lgicos and y/o or (en minsculas porque SSLRequire es sensible a maysculas/minsculas) y los operadores de comparacin== (o su equivalente eq), <, > podemos establecer las condiciones requeridas para el acceso a un directorio determinado. Analicemos este ejemplo. SSLRequire (%{SSL_CLIENT_V_REMAIN} >= "0" \ and (%{SSL_CLIENT_I_DN_O} eq "FNMT" or %{SSL_CLIENT_I_DN_OU} == "DNIE")) SSLRequire() incluye, dentro del parntesis, las condiciones restriccitivas que son las siguientes: %{SSL_CLIENT_V_REMAIN} >= "0"que exige que el certificado no haya expirado con anterioridad a la fecha (le quede un nmero de das de vigencia mayor o igual que cero). Aunque se trate de un valor nmerico el cero lo pondremos entre comillas. La barra invertida (\) es un carcter imprescindible para indicar que el condicionado contina en la lnea siguiente y el operador andagrega como nueva condicin que %{SSL_CLIENT_I_DN_O} eq "FNMT" or %{SSL_CLIENT_I_DN_OU}=="DNIE" lo cual significa la exigencia de que solo sern admisibles certificados en los que SSL_CLIENT_I_DN_O="FNMT" o aquellos en los que SSL_CLIENT_I_DN_OU="DNIE". De esta forma, las ltimas modificaciones de la configuracin de Apache, seran las siguientes:

Fichero inicial Guardar como Abrir

httpd.conf httpd_seguro_parcial_1.conf
Nos permitir recuperar la configuracin actual si es necesario

httpd.conf
Trabajaremos sobre la configuracin previa una vez asegurada una copia de ella Agregar inmediatamente antes de la etiqueta de cierre </VirtualHost> que hay al final del fichero :

Modificaciones en el fichero inicial

Final del documento

<Directory "C:/ServidoresLocales/Apache/htdocs/zona_segura/dnie"> SSLVerifyClient require SSLVerifyDepth 2 SSLRequire (%{SSL_CLIENT_V_REMAIN} >= "0" \ and (%{SSL_CLIENT_I_DN_O} eq "FNMT" \ or %{SSL_CLIENT_I_DN_OU} == "DNIE")) ErrorDocument 403 https://localhost/error_dnie.html </Directory> <Directory "C:/ServidoresLocales/Apache/htdocs/zona_segura/certificado"> SSLVerifyClient require SSLVerifyDepth 2 SSLRequire (%{SSL_CLIENT_V_REMAIN} >= "0" \ and %{SSL_CLIENT_I_DN_OU} =="certNORA") ErrorDocument 403 https://localhost/error_certificado.html </Directory>

Las lneas ErrorDocument tienen por finalidad redirigir el navegador hacia una pgina de error cuando intentemos acceder a un directorio restringido sin cumplir los requisitos exigidos para ello. Una vez hayas reiniciado el servidor despus de finalizar la configuracin podrs comprobar el funcionamiento accediendo a las direcciones: https://localhost, http://localhost y http://localhost/zona_segura/ Para acceder la primera de ellas necesitars uno de los tres certificados. El segundo requiere disponer de DNIe o un certificado de la FNMT y al tercero podrs acceder si tienes instalado en tu navegador el certificado auto firmado de cliente.

Extraer informacin de certificados Validez de los certificados


Las comprobaciones que se realizan sobre los certificados de usuarios presentan una laguna importante. La validez nos indica que un certificado de DNIe no ha sido manipulado y que ha sido emitido por la polica pero no podemos saber si est siendo usado de modo indebido por el titular o por una tercera persona. Supongamos que perdemos nuestro DNIe, o que simulamos su extravo. En el momento de formular la denuncia, la autoridad gubernativa procede a revocar nuestro certificado digital incorporndolo a la base de datos pblica de documentos revocados. Podramos entender que a partir de ese momento no somos responsables del uso que pueda hacerse del mismo. Para consultar esa base de datos existe un protocolo conocido como OCSP (Online Certificate Status Protocol) mediante el cual podemos conocer la validez actual de un certificado. Estos servicios de validacin del DNIe, segn informan en su web, son prestados de forma ininterrumpida todos los das del ao por la Fbrica Nacional de Moneda y Timbre Real Casa de la Moneda, que prestar sus servicios de validacin con carcter universal: ciudadanos, empresas ... No ocurre lo mismo con los certificados FNMT ya que en ese caso el acceso al OCSP responder no tiene carcter gratuito. Ms abajo tienes un ejemplo de la forma de efectuar la comprobacin de la validez del DNIe y, adems, podrs ver la forma en la que pueden extraerse los datos personales: nombre, apellidos, n, periodo de validez e incluso la fecha de nacimiento del titular. Da la impresin de que en un futuro no muy lejano la autentificacin, e incluso la restriccin de accesos a menores, acabar hacindose mediante este documento.

Lectura de certificados de cliente


PHP dispone de la funcin openssl_x509_parse(certificado, booleano) que permite leer los contenidos de un certificado en formatoPEM y recoger los resultados en un array. Cuando el parmetro booleano es TRUE -valor por defecto- utilizar nombres cortos para los ndices de los arrays. Si a ese parmetro le asignamos el valor FALSE (0) usara nombres largos. La diferencia puedes verla en estos ejemplos. Estos primeros utilizan la opcin FALSE
lee certNORA leee FNMT lee DNIe

mientras que estos otros utilizan la opcin TRUE. En ambos caso estamos visualizando copias de los tres tipos de certificados: nuestros certificados de prueba, un certificado de la FNMT y otro de DNIe.
lee certNORA leee FNMT lee DNIe

Para que puedas visualizar estos certificados ejemplo tienen carcter pblico y no pueden ser utilizados sin su clave privada hemos guardado aqu una copia de ellos. Cuando intentamos acceder, mediante el protocolo HTTPS a un directorio configurado como SSLVerifyClient require y, adems se incluye la opcin SSLOptions +ExportCertData los datos de los certificados de servidor y cliente son recogidos en dos variables superglobales. La variable $_SERVER['SSL_SERVER_CERT'] contendr una cadena con el certificado del servidor en formato PEM mientras que$_SERVER['SSL_CLIENT_CERT'] tendr idntica informacin pero referente al certificado del cliente. Este es el cdigo fuente del script utilizado en los ejemplos anteriores.
ver cdigo fuente

Verificacin de la validez de un DNIe


OpenSSL dispone de una utilidad que permite verificar la validez de un DNIe. Se tratara de ejecutar desde la lnea de comando lo siguiente: openssl ocsp -CAfile cert_raiz_dnie -issuer emisor -cert cliente -url direccion cuyos parmetros son los siguientes:

cert_raiz_dnie es la ruta completa y el nombre del fichero (en formato PEM) que contiene el certificado raz del DNIe. emisor es la ruta completa y el nombre de un fichero que contiene los datos del emisor del certificado de DNIe. Se extrae de este documento. cliente es la ruta completa y el nombre de un fichero que contiene los datos del cliente extraidos del DNIe (se extrae de este documento. direccion es la direccin que permite hacer la comprobacin. En el caso del DNIe sera http://ocsp.dnie.es Este comando puede ser ejecutado desde PHP incluyndolo en una llamada a la funcion shell_exec() que es el procedimiento que seguimos en el ejemplo que tienes a continuacin. Al ver el cdigo fuente podrs observar que al script le hemos incluido una opcin para simular la lectura de un DNIe sin necesidad de que configures tu servidor en modo seguro y, a la vez, para intentar ilustrar las posibilidades del DNIe y el certificado de la FNMT en el caso en que no dispongas de ellos o no te apetezca configurar tu servidor para trabajar en modo seguro. Para utilizar este script con tu propio DNIe bastar con que lo copies al directorio restringido de la configuracin que hemos propuesto para el servidor seguro (obviamente es imprescindible esa configuracin) y que accedas a l a travs de la direccin:https://localhost/dnie/test_dnie.php.
Verificar DNIe Ver cdigo fuente

Cuidado! Si has hecho la verificacin del DNIe del ejemplo anterior habrs podido ver que el certificado est revocado. Eso es cierto. El certificado que hemos utilizado corresponde a un DNIe que ya fu renovado y como consecuencia de esa renovacin ha sido emitido un nuevo certificado con la consiguiente revocacin del anterior.

Cmo utilizar el DNIe?


La utilizacin del DNIe electrnico requiere, tal como se explica en su pgina oficial, disponer de un lector de tarjetas inteligentes que cumpla el estndar ISO-7816. Existen distintas implementaciones, bien integrados en el teclado, bien externos (conectados va USB) o bien a travs de una interfaz PCMCIA el uso de un lector. Adems del dispositivo de hardware es necesario realizar algunas instalaciones de certificados y modificar algunas configuraciones de los navegadores. Este proceso puede hacerse basndose en la informacin de la web oficial del DNIe o recurriendo a algunas herramientas que permiten efectuar esa instalacin y configuracin de forma automtica. Una de ellas, https://zonatic.usatudni.es nos permite descargar paquetes autoinstaladores tanto para las diferentes versiones de Windows como para Ubuntu. Para este ltimo caso, en enlace anterior an no dispone en esta fecha (03.04.2012) de una versin que permita realizar la instalacin sobre Ubuntu 12.04. Para quien necesite utilizar esta versin del sistema operativo hay una excelente pgina http://bitplanet.es/manuales/3-linux/ dnde se describe de forma minuciosa todo el proceso de instalacin y configuracin en este supuesto.

Pginas WEB dinmicas


Servidores y clientes
Es frecuente observar, en la calle, que son muchas las personas que cuando se refieren a los servidores lo hacen como s se tratara de mquinas complejsimas, misteriosas, lejanas y enormes que, bajo esa aureola de cripticismo, parecen totalmente distintas al ordenador que usamos habitualmente. Nada ms lejos de la realidad! Vamos a intentar aclarar algunos conceptos con ejemplos cotidianos. Pensemos en esos ordenadores remotos (tambin llamados host) como si se tratara de uno esos sitios desde los que se sirven comidas a domicilio.

Quiz lo primero en lo que se te ocurra pensar sea en una pizza, no porque desconozcas que tambin es posible comprar otras cosas sino por la popularidad de ese tipo de servicio. Algo similar ocurre con los host. La frecuencia con la que accedemos a ellos en demanda de pginas web hace que tendamos a identificarlos con ellas, pero tambin los host ofrecen o pueden ofrecer ms servicios. Sigamos con las comidas a domicilio. Cada una de esas empresas puede atender peticiones de uno solo o de varios servicios distintos (pizzas, helados, o platos regionales, por citar algunos ejemplos), pero la oferta de cada uno de esos servicios requiere una infraestructura adecuada a cada caso. La oferta de pizzas exigir disponer de un horno, y la de helados necesitar de una instalacin frigorfica. Pues bien, algo muy similar ocurre con los host. Tambin stos pueden ofrecer uno o varios servicios (pginas web, correo electrnico, transferencias FTP, noticias, etctera) y tambin es necesario que cada servicio disponga de su propia infraestructura, que en este caso sera un programa distinto (software de servidor) para cada uno de ellos. Como puedes ver, no basta con hablar de servidores. Es necesario especificar tambin qu es lo que sirven.Habra que decir: servidor de pginas web, servidor de correo, etctera y tener presente que aunque convivan en la misma mquina cada uno de ellos requiere su propio software y su propia configuracin. Resumiendo, cuando en lenguaje coloquial hablamos de un servidor estamos aludiendo un host (ordenador remoto) el tamao y la lejana carecen de importancia provisto de programas (software de servidor) que, cuando est accesible (conectado a Internet) y con el software activo (servidor en funcionamiento) es capaz de atender peticiones y devolver a los clientes los documentos solicitados, o un mensaje de error, en el caso de que no estuvieran disponibles. Veamos un ejemplo de cmo se desarrolla ese proceso de peticinrespuesta. Para leer el correo electrnico necesitas disponer de un programa supongamos que es Outlook Express instalado en tu ordenador y hacer, a travs de l, una peticin a un ordenador remoto (host). Si quisieras visualizar pginas web tendras que utilizar un programa distinto Firefox o Internet Explorer, por ejemplo capaz de realizar esta otra tarea. Al programa que utilizamos para realizar cada peticin le llamaremos cliente.

Qu es una peticin?
Una peticin es un conjunto de datos que un cliente (recuerda que el cliente siempre es uno de los programas instalados en tu ordenador) enva a travs de Internet solicitando una respuesta determinada por parte de un servidor (ordenador remoto).

Qu contendra esa peticin?


Cada tipo de peticin tendr contenidos distintos. Por ejemplo, cuando se trata de leer mensajes de correo, la peticin realizada por el cliente (Outlook Express) contendra, entre otros, muchos de los datos de la configuracin de la cuenta, tales como: el protocolo (forma de comunicacin) en el caso del correo lo habitual sera el protocolo POP (Post Office Protocol), el nombre de host donde est alojado el buzn (servidor POP servidor de correo entrante), el nombre de la cuenta, la contrasea de acceso, y algunas otras informaciones relativas a la gestin de esa cuenta tales como si deben conservarse o no los mensajes en el servidor, etctera.

Qu ocurre con esa peticin?


Cualquier peticin pasa en primera instancia por un servidor de nombres de dominio (Domain Name Server) DNS, una especie de gua telefnica que contiene los nombres de los servidores y las direcciones IP a travs de las cuales estn conectados a Internet. Podra decirnos los datos son ficticios que olmo.cnice.mecd.es es el nombre de un host que est conectado a Internet a travs de la direccin IP 111.112.113.114 Una vez resuelta esa peticin por el servidor DNS (direccionamiento de la peticin a la IP correspondiente) se comprobar si esa IP est activa (si efectivamente hay un ordenador conectado a travs de ella) y, en caso de estarlo, se determinar si ese ordenador al que estamos accediendo es capaz de atender la peticin.

Qu tiene que ocurrir para que pueda atenderse una peticin?


Es necesario que el ordenador remoto tenga instalado y funcionando el software de servidor adecuado al protocolo de nuestra peticin. Ello quiere decir siguiendo con el ejemplo que el ordenador remoto debe tener instalado y funcionando un software especfico de servidor de correo capaz de interpretar el protocolo POP3 especificado en la peticin.

Cuidado!

El ordenador remoto debe tener instalado y funcionando el software adecuado a cada tipo de peticin (servicio) que deba atender. No basta con decir servidor, es preciso conocer los servicios que presta y es factible que un mismo ordenador preste simultneamente varios servicios, siempre que tenga instalado y activo el software especfico para cada uno de esos servicios.

Cuando el ordenador remoto acepta la peticin el software de servidor y/o las aplicaciones del lado del servidor (software instalado en el ordenador remoto y vinculado con el software de servidor) resuelven la peticin (comprobar que el nombre de la cuenta y la contrasea son correctas, comprobar si existen mensajes, borrarlos del buzn si as lo especifica la peticin, etc.) y devuelven al cliente (recuerda que el cliente era nuestro Outlook Express) la informacin requerida. Solo falta que una vez recibida la respuesta Outlook Express (cliente) interprete la informacin recibida y nos permita visualizar o imprimir el contenido de los mensajes descargados del servidor.

Servidor y cliente en una misma mquina


Hasta ahora al referirnos a servidores y clientes hemos hecho alusin a dos mquinas: nuestro propio ordenador (ordenador local) en el que estaran instaladas las aplicaciones cliente y un ordenador remoto en el que se alojaran las aplicaciones de servidor. Eso es lo ms habitual, pero no es la nica posibilidad. Dado que servidor y cliente son nicamente aplicaciones, es perfectamente posible que ambas convivan dentro de la misma mquina. La diferencia sustancial sera que ahora no es necesario el servidor de DNS para buscar la direccin IP. Utilizaramos una IP (habitualmente la 127.0.0.1) reservada para estos casos preestablecida en la configuracin del servidor y a travs de ella se canalizaran las peticiones a nuestro propio servidor. Ya hablaremos ms adelante de esta IP.

Tipos de pginas web


Una de las clasificaciones ms simples de las pginas web permitira agruparlas en dos tipos: estticas y dinmicas.

Pginas web estticas


Diremos que una pgina web es esttica cuando sus contenidos no son susceptibles de ser modificados ni por intervencin del usuario ni por una accin automtica del servidor (ordenador remoto) ni del cliente (navegador).

Un ejemplo de pgina esttica


Cualquier usuario que acceda a esta pgina que incluimos como ejemplo ya sea en modo local, o a travs de un servidor remoto visualizar siempre la misma fecha: 22 de setiembre de 2011.

<html> <head> </head> <body> Hoy es 22-09-2011 y son las 11:23:37 horas </body> </html>
ejemplo1.html

Las peticiones de pginas estticas se realizan de la forma que puedes ver en este esquema.

Si observas con detenimiento el esquema de la parte superior es posible que encuentres algo que no te cuadre... porque en el esquema hay un servidor que parece imprescindible para atender las peticiones y sin embargo t sin tener instalado ningn servidor eres capaz de visualizar tus propias pginas web sin ms hacer un doble clic sobre su icono. Eso es cierto, pero fjate en las dos direcciones que aparecen en esta otra imagen.

La de la izquierda consecuencia de haber hecho doble clic sobre el icono del documento contiene como direccin una ruta (el path que conduce hasta el documento) mientras que en la de la derecha aparece el sintagma http al principio de la direccin. En el primer caso no hemos hecho ninguna peticin de pgina web sino que hemos abierto un documento cuya extensin (html) est asociada en nuestra configuracin de Windows con Firefox, Internet Explorer, Opera o cualquier otro navegador que

tengamos instalado en nuestro equipo. El proceso ha sido exactamente el mismo que si hubiramos hecho doble clic sobre el icono de un documento con extensintxt, con la nica salvedad de que en este ltimo caso se habra abierto el bloc de notas (por la asociacin de extensiones y aplicaciones en la configuracin de Windows). En el segundo caso las cosas son distintas. Se incluye el sintagma http acrnimo de HiperText Transfer Protocol para indicar que ese es el protocolo que debe ser utilizado y que ser preciso que el servidor que reciba la peticin sea capaz de interpretarlo. Por eso a los servidores que alojan pginas web se les suele llamar servidores web o servidores HTTP dado que se les requiere que soporten este protocolo.

Pginas dinmicas
Llamaremos dinmicas a las pginas cuyos contenidos s pueden ser modificados de forma automtica o mediante la intervencin de un usuario bien sea desde el cliente y/o desde el servidor. Para que una modificacin de este tipo pueda producirse es necesario que algo o alguien especifique: qu, cmo, cundo, dnde y de qu forma debe hacerse el cambio, y que exista otro algo o alguien capaz de: acceder, interpretar y realizar, en el momento preciso, las instrucciones de modificacin. Igual que ocurre en el contexto de la vida cotidiana, las especificaciones y las instrucciones precisan de un lenguaje para poder definirlas, un soporte para almacenarlas, y un intrprete capaz de ejecutarlas. Somos capaces de entender unas instrucciones escritas en castellano pero si estuvieran escritas en blgaro las cosas seguramente seran bastante distintas, y, por supuesto, a un blgar@ le pasara justamente lo contrario. Igual ocurre con los programas intrpretes de los lenguajes de script. Ellos tambin requieren rdenes escritas en su propio idioma.

Scripts
Se llama script a un conjunto de instrucciones, escritas en un lenguaje determinado, que van incrustadas dentro de una pgina WEB de modo que su intrprete pueda acceder a ellas en el momento en el que se requiera su ejecucin. Cuando se incrustan scripts en una pgina WEB empiezan a convivir dentro de un mismo documento informaciones destinadas a distintos intrpretes. Por una parte, el cdigo HTML que ha de ser interpretado por el navegador, y por la otra, los scripts que han de ser ejecutados por el intrprete propio del lenguaje en el que hayan sido escritos. La manera de diferenciar los contenidos es delimitar los scripts marcando su comienzo con una etiqueta de apertura <script> y sealando el final con una etiqueta de cierre </script>. Lo que no est contenido entre esas etiquetas ser considerado cdigo HTML. La posibilidad de insertar en un mismo documento scripts escritos en distintos lenguajes obliga a especificar cul se ha utilizado en cada caso, para que en el momento en el que vayan a ser ejecutados se invoque el intrprete adecuado. Para ello, dentro de la propia etiqueta de apertura (<script>) se inserta una referencia al tipo de lenguaje con esta sintaxis:language="nombre" Por ejemplo: <script language="PHP"> ...... ...... instrucciones .. ...... </script> indicara que las instrucciones estn escritas con la sintaxis de PHP. Por el contrario, al escribir: <script language="JavaScript"> ...... ...... instrucciones .. ...... </script> estaramos sealando que en las instrucciones contenidas en el script utilizan sintaxis de JavaScript. La alternativa ms reciente (la anterior est obsoleta) sera:<script type="text/javascript">

Para el caso concreto de PHP, existe una sintaxis alternativa, mucho ms cmoda y habitual. Es la siguiente: <?php ...... ......instrucciones.. ...... ?> Aqu <?php har la misma funcin que <script language="PHP"> y ?> ser equivalente a </script>. Con la configuracin adecuada tambin podramos usar <? en vez de <?php como marca inicial.

Lenguajes de script
Hay mltiples posibilidades en cuanto a lenguajes de script. Pero antes de hacer mencin a algunos de ellos es conveniente hacer una clasificacin previa. Hablaremos de dos tipos:lenguajes del lado del cliente y lenguajes del lado del servidor.

Lenguajes del lado del cliente


Diremos que un lenguaje es del lado del cliente cuando el intrprete que ha de ejecutar sus scripts es accesible desde ste el cliente sin que sea necesaria ninguna intervencin en este sentido por parte servidor. Seguramente te ha ocurrido alguna vez que al intentar acceder a una pgina web ha aparecido un mensaje advirtiendo que para la correcta visualizacin de la pgina se requiere un plug-in determinado, y que, a la vez, se te haya ofrecido la posibilidad de descargarlo en ese momento. Eso ocurre porque cuando el navegador que en el caso de las pginas web es el cliente trata de interpretar la pgina, encuentra incrustado en ella algo (un fichero de sonido, una animacin Flash, etctera) que de forma muy similar a lo que ocurre con los scripts requiere un intrprete adecuado del que no dispone en ese momento. Cuando los scripts contenidos en un documento son de este tipo, el servidor lo entrega al cliente si efectuar ningn tipo de modificacin. Sin pretender hacer una enumeracin exhaustiva, entre los lenguajes de script del lado del cliente los ms populares son: DHTML,JavaScript y VBScript. DHTML no es exactamente un lenguaje de programacin. Se trata ms bien de una serie de capacidades que se han ido aadiendo a los navegadores modernos mediante las cuales las pginas pueden contener hojas de estilo y/o organizarse en capas susceptibles de ser modificadas, redimensionadas, desplazadas y/o ocultadas. JavaScript es uno de los lenguajes ms populares. Cada navegador incluye su propio intrprete y es frecuente que los resultados de visualizacin sean algo distintos segn el navegador y la versin que se utilice. Parece ser que las versiones ms recientes de los distintos navegadores se aproximan a un estndar ECMA Script-262 que ha sido desarrollado por la ECMA (Asociacin Europea de Normalizacin de Sistemas de Informacin y Comunicacin), lo que hace suponer que en un futuro muy prximo todos los navegadores se ajustarn a esa especificacin y que, con ello, las pginas web ya se visualizarn de forma idntica en todos ellos. VBScript es un lenguaje de script derivado de VisualBasic y diseado por Microsoft para Internet Explorer y los navegadores derivados o vinculados a este. Una peticin de pgina en la que hay incrustados scripts escritos en lenguaje del lado del cliente se realizara de una forma similar a esta:

Como puedes observar no requiere nada distinto a lo del supuesto anterior. La diferencia sera que en este caso se haran llamadas al intrprete de JavaScript incluido en los navegadores, tal como comentamos al margen y/o a eventuales plugins necesarios para interpretar otros tipos de script. Aqu tienes dos ejemplos de pginas web dinmicas. Ambas utilizan los JavaScript que puedes ver en rojo en su cdigo fuente. Si pulsas en el enlace del primero de estos dos ejemplos vers que la fecha que aparece en la pgina es la fecha actual de tu sistema, y adems, cada vez que pulses el botn Actualizar de tu navegador comprobars que esa intervencin del usuario modifica los contenidos actualizando la hora que aparece en el documento.

<html> <head> <script type="text/javaScript"> var son= new Date(); var fecha=son.getDate()+" - "+(son.getMonth()+1)+" - "+son.getFullYear(); var hora=son.getHours()+":"+son.getMinutes()+":"+son.getSeconds(); document.write('Hoy es '+fecha+' y son las '+hora+' horas'); </script> </head> <body> </body> </html>
ejemplo2.html

En este otro ejemplo la modificacin de los contenidos no requiere intervencin alguna por parte del usuario. Cada 5 segundos (fjate donde dice var frecuencia=5000). Cinco mil es el perodo de actualizacin, expresado en milisegundos) se rescribirn de forma automtica la fecha y la hora. Tenemos por tanto una especie de cronmetro automtico.

<html> <head> <script type="text/javaScript"> var reloj=0; var frecuencia=5000; function actualiza(){

var son= new Date(); var fecha=son.getDate()+" - "+(son.getMonth()+1)+" - "+son.getFullYear(); var hora=son.getHours()+":"+son.getMinutes()+":"+son.getSeconds(); var escribe='Hoy es '+fecha+' y son las '+hora+' horas'; var situa=document.getElementById('capa0'); situa.innerHTML=escribe; reloj=setTimeout("actualiza()",frecuencia); } </script> </head> <body onLoad="actualiza()";> <div id="capa0"> </div> </body> </html>
ejemplo3.html

Lenguajes del lado del servidor


Un lenguaje es del lado del servidor cuando la ejecucin de sus scripts se efecta, por instancia de este el servidor, antes de dar respuesta a la peticin, de manera que el cliente no recibe el documento original sino el resultante de esa interpretacin previa. Cuando se usan estos tipos de lenguaje el cliente recibe un documento en el que cada script contenido en el original habr sido sustituido por los resultados de su ejecucin. Esto es algo a tener muy en cuenta, porque, en este caso, los usuarios no tendrn la posibilidad de visualizar el cdigo fuente, mientras que cuando se trata de lenguajes del lado del cliente siempre es posible visualizar los scripts, bien sea de forma directa mirando el cdigo fuente de la pgina recibida o leyendo el contenido de ficheros externos vinculados a ella que son bastante fciles de encontrar en la cach del navegador. La utilizacin de este tipo de scripts requiere que el intrprete del lenguaje sea accesible est del lado desde el propio servidor. Entre los lenguajes del lado del servidor los ms populares son: PHP, ASP, PERL y JSP. Cada uno de ellos tiene sus propias peculiaridades. No abundaremos en ellas. Nosotros trataremos aqu sobre PHP.

Las posibles dudas del servidor


Dado que en unos casos el servidor debe entregar el documento original pginas estticas o pginas dinmicas en las que se usan lenguajes del lado del cliente mientras que en otros casos pginas dinmicas usando lenguajes del lado del servidor tiene que devolver el resultado de la ejecucin de los scripts, es razonable que te preguntes: cmo sabe el servidor lo que debe hacer en cada caso? La respuesta es simple. Eso hay que decrselo. Y se le dice de una forma bastante simple. Se indica al poner la extensin al documento. Si en la peticin se alude a un documento con extensin .htm o .html el servidor entender que esa pgina no requiere la intervencin previa de ningn intrprete de su lado y entregar la pgina tal cual. Si en esa peticin se aludiera a una extensin distinta .php, por ejemplo el servidor entendera que antes de servir la pgina debe leerla y requerir al intrprete de PHP que ejecute los scripts desarrollados en ese lenguaje (en caso de que los contuviera) y devolvera al cliente el documento que resultara de las eventuales ejecuciones de tales scripts. Aqu tienes el esquema de un ejemplo de convivencia en un mismo documento de varios scripts y varios tipos de lenguaje.

Aqu ya es preciso que, adems de un servidor capaz de soportar el protocolo HTTP, est instalado del lado del servidor un intrprete PHP, un servidor de bases de datos MySQL y que, adems, estn configurados de modo que puedan interactuar entre ellos. El lenguaje PHP dispone de funciones que le permiten acceder a muy diversos tipos de servidores de bases de datos pudiendo: crear, consultar, borrar y modificar tanto bases de datos como tablas y registros de las mismas. Nosotros vamos a utilizar MySQL, unos de los gestores ms potentes y populares que existen en este momento.

Requisitos para el uso del Lenguaje PHP


De acuerdo a lo comentado en los prrafos anteriores el uso del lenguaje PHP requiere tener instalado y configurado: Un software de servidor web configurado para interactuar con el intrprete de PHP que soporte el protocolo HTTP y que en nuestro caso ser el denominado servidor Apache. El intrprete de PHP. Un software de servidor de bases de datos capaz de ser gestionado mediante funciones propias de PHP. Podemos utilizar el servidor de bases de datos MySQL o su fork MariaDB (me gust eso del fork!) y tambin podrs encontrar referencias al uso deSQLite que en muchos casos puede resultar una alternativa ms ligera y accesible.

PHP y HTML Pginas PHP


Las pginas PHP pueden ser pginas web normales a las que nicamente se les cambia la extensin tradicional (.htm .html) , por la extensin .php. Observemos este cdigo fuente. Como vers, se trata de una pgina web muy simple que no contiene ningn script PHP.

<html>

<head> <title>Aprendiendo PHP</title></head> <body> Esta es una pgina supersimple </body> </html>
Hemos guardado esa pgina con el nombre ejemplo6.html y luego la hemos vuelto a guardar sin modificar nada en sus contenidos como ejemplo6.php. Observa que al visualizarlas no hay diferencia alguna entre ellas.
Ver ejemplo6.html Ver ejemplo6.php

Un poco de sintaxis
En una pgina cuyo nombre tenga por extensin .php se pueden insertar instrucciones escritas en lenguaje PHP anteponiendo <?php a la primera instruccin y escribiendo ?> despus de la ltima. A cada uno de estos bloques de instrucciones le llamaremos un script. No existe lmite en cuanto al nmero de scripts distintos que pueden insertarse dentro de una pgina. La primera instruccin PHP que conoceremos ser esta: echo "un texto...";. La instruccin echo seguida de un texto entrecomillado har que el PHP escriba en la pgina web resultante lo contenido en esa cadena de texto. Al final de cada instruccin debemos insertar siempre un punto y coma (;). Este signo (;) indicar a PHP que lo que viene a continuacin es una nueva instruccin. Para facilitar la depuracin de los scripts no suelen escribirse dos instrucciones en una misma lnea. print "un texto ...";

La instruccin print tiene una funcin similar no es exactamente la misma a la descrita para echo. Ms adelante veremos algunas de sus diferencias. print ("un texto...");

Esta es otra manera la ms habitual de utilizar print. Ahora encerramos entre parntesis la cadena que pretendemos que aparezca impresa en la pgina web. El hecho de que utilicemos parntesis no evita la obligacin de encerrar entre comillas el texto (texto) que deseamos imprimir . Comillas dentro de comillas

Existen dos tipos de comillas: dobles " (SHIFT+2) y sencillas ' (tecla ? en minsculas). Cuando es preciso anidar comillasdeben utilizarse tipos distintos para las exteriores y para las interiores. Para que una instruccin echo o print interprete unas comillas como texto y no como un delimitador de la cadena es necesarioanteponerles un signo de barra invertida(\). En argot suele decirse escaparlas. En ningn caso ni con echo ni con print est permitido sustituir las comillas exteriores (las que encierran la cadena) por \". Esta sintaxis solo es vlida para indicar a PHP que debe interpretar las comillas como un carcter ms. En la pgina siguiente veremos las diferentes opciones de las lneas de comentarios. Al realizar el ejercicio que te proponemos no es necesario que pongas los comentarios del ejemplo.

Los primeros script PHP


Editemos la pgina anterior (ejemplo6.php) y aadmosle nuestra primera etiqueta PHP guardndola como ejemplo7.php. Este sera el cdigo fuente:

<html> <head> <title>Aprendiendo PHP</title></head> <body> Esta es una pgina supersimple <?php echo "Aparecer esta linea?"; ?> </body> </html>
ejemplo7.php

Veamos ahora un ejemplo con las diferentes opciones de uso de las comillas

<html> <head> <title>Aprendiendo PHP</title></head> <body> <?php /* Las instrucciones PHP son las que aparecen en rojo. Las etiquetas en azul intenso son el cdigo HTML. Todo lo que aparece en este color son lneas de comentario de las que hablaremos ms adelante Cuando rescribas estos primeros scripts bastar que incluyas las instrucciones escritas en rojo */ /* ponemos <br> al final del texto para que cuando se ejecute cada una de las instrucciones echo se escriba -adems del texto- un salto de linea HTML. De este modo, el resultado de cada ECHO aparecer en una lnea diferente */ # aqu utilizamos solo unas comillas echo "Este texto solo lleva las comillas de la instruccin<br>"; # aqu anidaremos comillas de distinto tipo echo "La palabra 'comillas' aparecer entrecomillada<br>"; # esta es otra posibilidad invirtiendo el orden de las comillas echo 'La palabra "comillas" aparecer entrecomillada<br>'; # una tercera posibilidad en la que utilizamos un mismo # tipo de comillas. Para diferenciar unas de otras anteponemos # la barra invertida, pero esta opcin no podramos utilizarla # al revs. # No podramos poner \" en las comillas exteriores. echo "La palabra \"comillas\" usando la barra invertida<br>"; ?> </body> </html>
Ver ejemplo8.php

Lneas de comentario Por qu usar lneas de comentario?


A primera vista pueden parecer intiles. Para qu recargar las pginas con contenidos que no se van a ver ni ejecutar?. Las lneas de comentario sirven para poder recordar en un futuro qu es lo que hemos hecho al escribir un script y por qu razn lo hemos hecho as.

A medida que vayamos avanzando vers que en muchos casos tendremos que aplicar estrategias individuales para resolver cada problema concreto. Cuando necesites hacer una correccin o una modificacin al cabo de un tiempo vers que confiar en la memoria no es una buena opcin. Es mucho mejor utilizar una lnea de comentario que confiar en la memoria. Palabra!

Comentarios
Para insertar comentarios en los scripts de PHP podemos optar entre varios mtodos y varias posibilidades: Una sola linea

Basta colocar los smbolos // al comienzo de la lnea o detrs del punto y coma que seala el final de una instruccin. Tambin se puede usar el smbolo # en cualquiera de las dos posiciones. Varias lneas

Si un comentario va a ocupar ms de una lnea podremos escribir /* al comienzo de la primera de ellas y */ al final de la ltima. Las lneas intermedias no requieren de ningn tipo de marca. Los comentarios para los que usemos la forma /* ... */ no pueden anidarse. Si, por error, lo hiciramos PHP nos dar un mensaje de error.

Ensayando lneas de comentario


En este ejemplo hemos incluido marcados en rojo algunos ejemplos de insercin de lneas de comentario.

<html> <head> <title>Ejemplo 9</title></head> <body> <?php // Este comentario no se ver en la pgina echo "Esto se leer <BR> "; // Esto no se leer /* Este es un comentario de mltiples lneas y no se acabar hasta que no cerremos as.... */ echo "Este es el segundo comentario que se leer<BR>"; # Este es un comentario tipo shell que tampoco se leer # Este, tampoco echo ("Aqu el tercer texto visible"); #comentario invisible /* Cuidado con anidar /* comentarios multilinea con estos*/ al PHP no le gustan */ ?> </body> </html>
Ver ejemplo9.php Ver ejemplo10.php

Ejecutemos los dos ejemplos. En el caso del ejemplo9 hemos mantenido el cdigo exactamente como se muestra aqu arriba. Como consecuencia de haber anidado comentarios nos dar un error al ejecutarlo. Esto es una muestra de la importancia que tiene cuidar estrictamente ese aspecto.

En el ejemplo10 hemos quitado el /* que va delante de comentarios y el */ que va despus de multilnea con estos (marcado en magenta en el cdigo fuente). Ya no hay comentarios anidados y ya funciona correctamente.

Cuidado! Si tu sistema operativo es Ubuntu es muy probable que en vez de los mensajes de error comentados en los ejemplos anteriores solo visualices una pgina en blanco. Ello es debido a la configuracin por defecto de la directiva display_errors de php.ini. En este enlace (http://www.rinconastur.com/php/errores.php) tienes informacin relativa a la configuracin de las directivas de error.

Constantes Definir constantes


Una constante es un valor un nmero o una cadena que no va a ser modificado a lo largo del proceso de ejecucin de los scriptsque contiene un documento. Para mayor comodidad, a cada uno de esos valores se le asigna un nombre, de modo que cuando vaya a ser utilizado baste con invocar ese nombre. Cuando ponemos nombre a una constante se dice que definimos esa constante. En PHP las constantes se definen mediante la siguiente instruccin: define("nombre","valor");

dnde nombre es una cadena que contiene la palabra que pretendemos asignar como tal nombre y valor el contenido que pretendemos asignar a esa constante. El valor debe escribirse entre comillas, salvo que se trate de una constantes numrica que no las requiere. Los valores asignados a las constantes se mantienen en todo el documento, incluso cuando son invocadas desde una funcin. Si se realizan operaciones aritmticas con constantes tipo cadena, y su valor comienza por una letra, PHP les asigna valor cero. Si una cadena empieza por uno o varios caracteres numricos, al tratar de operarla aritmticamente PHP considerar nicamente el valor de los dgitos anteriores a la primera letra o carcter no numrico. El punto entre caracteres numricos es considerado como separador de parte decimal. Tal como puedes ver en el cdigo fuente del ejemplo, es posible definir constantes a las que se asigne como valor el resultado de una operacin aritmtica.

Ampliando echo y print


Mediante una sola instruccin echo pueden presentarse de forma simultnea (en la ventana del navegador del cliente) varias cadenas de caracteres y/o constantes y variables. Basta con ponerlas una a continuacin de otra utilizando una coma como separador. La forma anterior no es la nica ni la ms habitual de enlazar elementos mediante la instruccin echo. Si en vez de utilizar la una coma usramos un un punto (el concatenador de cadenas) conseguiramos el mismo resultado. Cuando enlacemos elementos distintos cadenas, constantes y/o nmeros hemos de tener muy en cuenta lo siguiente: Cada una de las sucesivas cadenas debe ir encerrada entre sus propias comillas. Los nombres de constantes nunca van entre comillas.

Las instrucciones print tambin permiten concatenar cadenas en una misma instruccin. En este caso solo es posible usar un puntocomo elemento de unin. Si pusiramos comas como podemos hacer con echo PHP nos dara un error.

Un ejemplo con constantes


<html><head><title>Constantes</title></head> <body> <?php /* Definiremos la constante EurPta y le asignaremos el valor 166.386 */ define("EurPta",166.386); /* Definiremos la constante PtaEur asignndole el valor 1/166.386 En este caso el valor de la constante es el resultado de la operacin aritmtica dividir 1 entre 166.386*/ define("PtaEur",1/166.386); /* Definimos la constante Cadenas y le asignamos el valor: 12Esta constante es una cadena*/ define("Cadena","12Esta constante es una cadena"); /* Definimos la constante Cadena2 y le asignamos el valor: 12.54Constante con punto decimal*/ define("Cadena2","12.54Constante con punto decimal"); /* Comprobemos los valores. Observa la nueva forma en la que utilizamos echo Lo hacemos enlazando varias cadenas separadas con punto y/o coma, segn se trate de echo o de print */ echo "Valor de la constante EurPta: ", EurPta, "<BR>"; echo "Valor de la constante PtaEur: ". PtaEur . "<BR>"; print "Valor de la constante Cadena: " . Cadena . "<BR>"; print "Valor de la constante Cadena x EurPta: " . Cadena*EurPta ."<br>"; print "Valor de la constante Cadena2 x EurPta: " . Cadena2*EurPta ."<br>"; echo "Con echo los nmeros no necesitan ir entre comillas: " ,3,"<br>"; print "En el caso de print si son necesarias: " . "7" . "<br>"; print ("incluso entre parntesis necesitan las comillas: "."45"."<br>"); print "Solo hay una excepcin en el caso de print. "; print "Si los nmeros van en un print independiente no necesitan comillas "; print 23; # Pondremos la etiqueta de cierre del script y escribiremos # una lnea de cdigo HTML ?> <br>Ahora veremos los mismos resultados usando la function prueba<br><br> <?php # Estamos dentro de un nuevo script abierto por el <? anterior

/* Aunque an no la hemos estudiado, escribiremos una funcin a la que (tenemos que ponerle siempre un nombre) vamos a llamar prueba() Lo sealado en rojo es la forma de indicar el comienzo y el final de la funcion Lo marcado en azul son las instrucciones que deben ejecutarse cuando la funcin prueba() sea invocada */ function prueba(){ echo "Valor de la constante EurPta: ". EurPta . "<BR>";

print "Valor de la constante PtaEur: ". PtaEur. "<BR>"; echo "Valor de la constante Cadena: ", Cadena , "<BR>"; print ("Valor de la constante Cadena x EurPta: " . Cadena*EurPta . "<br>"); print ("Valor de la constante Cadena2 x EurPta: " . Cadena2*EurPta . "<br>"); } # Las funciones solo se ejecutan cuando son invocadas /* La funcin anterior no se ejecutar hasta que escribamos una lnea como esta de abajo en la que ponemos nicamente el nombre de la funcin: prueba() */ ?> <?php prueba(); ?> </body> </html>
Ver ejemplo11.php

Cuidado! Presta mucha atencin a la sintaxis. Olvidar los ; o no poner unas comillas suelen ser la causa de muchos mensajes de error.

Variables Qu es una variable?


Podramos decir que una variable es el espacio de la memoria RAM del ordenador que se reserva a lo largo del tiempo de ejecucin de un script para almacenar un determinado tipo de datos cuyos valores son susceptibles de ser modificados por medio de las instrucciones contenidas en el propio programa. En PHP todos los nombres de variable tienen que empezar por el smbolo $.y han de llevar una letra inmediatamente despus del smbolo $ ($pepe1 es un nombre vlido, pero $1pepe no lo es). Para PHP las letras maysculas y las minsculas son distintas. La variable $pepe es distinta de $Pepe.

Definicin y tipos de variables


A diferencia de otros lenguajes de programacin, PHP no requiere una definicin previa de las variables. Se pueden definen en el momento en que son necesarias y para ello basta que se les asigne un valor por medio de una expresin como esta: $variable=valor;

donde valor puede ser una cadena (texto, texto y nmeros, o nmeros que no requieren ser operados matemticamente) o slo unnmero. En el primero de los casos habra que escribirlo entre comillas. En PHP tampoco es necesario definir el tipo de variable, por lo tanto, una misma variable puede contener una cadena de caracteresen un momento del proceso y, posteriormente, un valor numrico susceptible de ser operado matemticamente.

Cuidado! En algunas configuraciones de PHP el uso de variables no definidas previamente puede dar lugar a mensajes de error como el que puedes observar si ejecutas el ejemplo12.php desde PHP 5.3.6 utilizando la configuracin explicada en

pginas anteriores. El mensaje se debe a la forma en la que est configuradas la directiva relativa a los mensajes de error cuya explicacin puedes ver en este enlace. Ese mensaje de error puede evitarse de la forma que hemos hecho en el ejemplo14.php o modificando la directiva error_reporting o display_errors tal como se comenta aqu

mbito de las variables


Los valores de una variable definida en cualquier parte de un script siempre que no sea dentro de una funcin pueden ser utilizados desde cualquier otra parte de ese script, excepto desde dentro de las funciones que contuviera el propio script o desde las que pudieran estar contenidas en un fichero externo. Si una variable es definida dentro de una funcin slo podr ser utilizada dentro esa funcin. Si en una funcin aludimos a una variable externa a ella, PHP considerar esa llamada como si la variable tuviera valor cero (en caso de ser tratada como nmero) o una cadena vaca ("" es una cadena vaca). Igual ocurrira si desde fuera de una funcin hiciramos alusin a una variable definida en ella. Si definimos dos variables con el mismo nombre, una dentro de una funcin y otra fuera, PHP las considerar distintas. La funcin utilizar cuando sea ejecutada sus propios valores sin que sus resultados modifiquen la variable externa.

Variables globales
Lo comentado anteriormente, admite algunas excepciones. Las funciones pueden utilizar valores de variables externas a ellas pero ello requiere incluir dentro de la propia funcin la siguiente instruccin: global nombre de la variable;

Por ejemplo: global $a1; permitira utilizar el valor preexistente de esa variable dentro de una funcin. Las eventuales modificaciones que pudiera producirle la funcin mantendran su nuevo valor despus de finalizar la ejecucin de la funcin. En una instruccin global pueden definirse como tales, de forma simultnea, varias variables. Basta con escribir los nombres de cada una de ellas separados por comas. Por ejemplo: global $a1, $a2, $a3;

Variables superglobales
A partir de la versin 4.1.0 de PHP se ha creado un nuevo tipo de variables capaces de comportarse como globales sin necesidad de que se definan como tales. Estas variables que no pueden ser creadas por usuario, recogen de forma automtica informacin muy especficay tienen nombres preasignados que no pueden modificarse. Las estudiaremos un poco ms adelante. Por ahora, slo citar los nombres de algunas de ellas: $_SERVER, $_POST, $_GET, $_ENVo $_SESSION son los de algunas de las ms importantes.

Practicando con variables y sus mbitos


El cdigo fuente que ves aqu debajo corresponde al ejemplo12.php. Si pulsas en el enlace que hay debajo y ejecutas el script vers que aparece un mensaje de error que dice: Notice: Undefined variable: pepe ... que parece contradictorio con lo afirmado ms arriba respecto a que PHP no requiere una definicin previa de variables. Esa afirmacin es cierta. Lo que ocurre es que PHP no est dando un mensaje de error propiamente dicho (NOTICE es una simple advertencia con un significado distinto a ERROR ) sino que advierte de que no se ha hecho algo habitual en una gran cantidad de lenguajes. Hay dos formas de evitar ese mensaje. La primera de ellas la comentamos en el propio cdigo fuente sera definir las variables antes de usarlas (siguiendo la metodologa ms generalizada de programacin). La segunda de las opciones sera modificar el fichero php.ini cambiando el valor actual: error_reporting = E_ALL | E_STRICT por error_reporting = E_ALL &

~E_NOTICE. De esta forma, (al anteponer ~aE_NOTICE) estaremos indicando a PHP , tal como explicamos aqu, que desactive este tipo de mensajes de advertencia.

<html> <head> </head> <body> <?php /* En ejemplo12.php la linea siguiente a este comentario($pepe="" ) estar marcada con lneas de comentario mientras que en ejemplo13.php y ejemplo14.php aparecer tal como la ves aqu */ $pepe=""; # Definimos las variables $Pepe y $Pepa (ojo con maysculas y minsculas) $Pepe="Me llamo Pepe y soy serio y formal"; $Pepa="Me llamo Pepa y tambin soy seria y formal"; ?> <!-- esto es HTML, hemos cerrado el script --> <center><b>Vamos a ver el contenido de las variables</b></center> <!-un nuevo script PHP -->

<?php echo "<br> El valor de la variable $pepe es: ",$pepe; echo "<br> No ha puesto nada porque $pepe esta vaca"; echo "<br> El valor de la variable Pepe es: ",$Pepe; ?> <center><b><br>Invocando la variable desde una funcin</b></center> <?php /* Escribiremos una function llamada vervariable Observa la sintaxis. La palabra function delante y el () al final seguidos de la llave. Hasta que no cerremos la llave todas las lneas sern consideradas parte de la funcin */ function vervariable(){ // $Pepe=""; /* si no inicializamos la variable $Pepe nos puede aparecer el mensaje de error que comentamos al margen y que veremos al ejecutar este script tanto desde el enlace ejemplo12.php como desde el ejemplo13.php En el caso del ejemplo14.php, donde ya no aparece el error lo nico que hemos hecho ha sido precisamente inicializar la variable $Pepe asignndole un valor nulo tal como puedes ver en la lnea anterior (marcado en rojo) y comentada con // En el ejemplo14.php hemos descomentar esta lnea */ echo "<br> Si invoco la variable Pepe desde una funcin"; echo "<br>me aparecer en blanco"; echo "<br>El valor de la variable Pepe es: ",$Pepe; } /* esta llave de arriba seala el final de la funcin. Los contenidos que hay en adelante ya no pertenecen a ella */ /* Haremos una llamada a la funcion vervariable. Las funciones no se ejecutan hasta que no se les ordena y se hace de esta forma que ves aqu debajo: nombre de la funcion seguido de los famosos parntesis */

vervariable(); ?> <!-- mas HTML puro --> <center><b><br>Ver la variable desde la funcin poniendo <i>global</i></b></center> <?php # una nueva funcion function ahorasi(){ # aqui definiremos a $Pepe como global # la funcin leer su valor externo global $Pepe; echo "<br><br> Hemos asignado mbito global a la variable"; echo "<br>ahora Pepe aparecer"; echo "<br>El valor de la variable Pepe es: ", $Pepe; } # hemos cerrado ya la funcion con la llave. # Tendremos que invocarla para que se ejecute ahora ahorasi(); ?> <center><b><br>Un solo nombre y dos <i>variables distintas</i></b><br> Dentro de la funcin el valor de la variable es <br></center> <?php function cambiaPepa(){ $Pepa="Ahora voy a llamarme Luisa por un ratito"; echo "<br>",$Pepa; } cambiaPepa(); ?> <center>... pero despus de salir de la funcin vuelvo al valor original...</center> <?php echo "<br>",$Pepa; ?> </body> </html>
Ver ejemplo12.php Ver ejemplo13.php Ver ejemplo14.php

Constantes predefinidas Constantes predefinidas


PHP dispone de algunas constantes predefinidas que no requieren la instruccin: define("Nombre","Valor") ya que utilizan palabras reservadas y se asignan valor de forma automtica. Algunas de ellas son estas: __FILE__

Recoge el nombre del fichero que se est ejecutando y la ruta completa de su ubicacin en el servidor. Su nombre lleva dos guiones bajos ( __ ) delante de FILE y otros dos detrs. __LINE__

Recoge el nmero de la lnea actual (incluidas las lneas en blanco) del fichero PHP cuyos scripts est interpretando. Puede resultar muy til para depurar programas. PHP_OS

Recoge informacin sobre el sistema operativo que utiliza el servidor en el que se est interpretando el fichero. PHP_VERSION

Recoge la versin de PHP que est siendo utilizada por el servidor.

Cuidado! Por si existieran dudas por problemas de visualizacin tanto FILE como LINE tienen que llevar dos guiones bajosdelante y otras dos detrs.

Un ejemplo con constantes predefinidas


<html> <head> </head> <body> <?php # La constante del sistema __FILE__ nos devolver echo "La ruta completa de este fichero es: "; echo __FILE__; # # # # La constante del sistema __LINE__ nos devolver el nmero de lnea que se est interpretando tambin cuenta las lneas en blanco cuenta las lneas y vers que devuelve ... 16

echo "<br>Esta es la lnea: ",__LINE__, " del fichero"; echo "<br>Estamos utilizando la versin: ",PHP_VERSION, " de PHP"; echo "<br>El PHP se est ejecutando desde el sistema operativo: ",PHP_OS; ?> </body> </html>
Ver ejemplo15.php

Variables predefinidas
Las tablas de valores
En las tablas que hay al final de esta pgina podrs ver los valores actuales clasificados por tipos de algunas de las variables predefinidas de PHP. Esta informacin (variables y valores) est siendo extraida de la configuracin de tu servidor y de este documento y se trata de variables de tipo superglobal tal como lo definamos en esta pgina. Probablemente te extraar justificadamente la longitud y la estructura un tanto rara de estos nombres de variables. Cuando tratemos el tema de los arrays asociativos veremos que esa es la sintaxis habitual de ese tipo de variables. Las nombres de las variables de cada uno de los tipos, slo se diferencian en lo contenido entre los corchetes porque se trata dedistintos elementos del mismo array asociativo y tal como veremos esa es la sintaxis tpica de los array. No vamos a agobiarte con una enumeracin de variables y contenidos, pero a poco que observes las tablas de valores te dars cuenta de que es muy abundante y muy importante la informacin que recogen. Si analizas las variables de servidor te dars cuenta de que aparece un montn de informacin relativa a su configuracin: nombre, rutas, nombres de pginas, IP del servidor, etctera. Con los dems tipos ocurre algo similar.

Los distintos tipos


Veamos los diferentes tipos de variables predefinidas que existen en PHP. Por ahora, no te preocupes demasiado sobre la forma de utilizarlas. Las incluimos aqu como una simple enumeracin y con una breve descripcin de su utilidad. En temas posteriores haremos referencia a ellas. Por el momento nos bastar con conocer su existencia. Estamos viendo los valores de las variables de de entorno (ENV) y las de servidor (SERVER), pero, adems de ellas, existen algunas otras cuyos nombres y utilidades vamos a comentarte.

Variables de sesin
Las identificaremos por el nombre $_SESSION. Este tipo de variables las utilizaremos cuando hagamos mencin al uso de sesiones. La utilizacin de sesiones ya abundaremos en ello es una forma de recoger, de forma temporal en un documento del mismo carcter, informacin especfica generada a travs de los accesos de cada uno de los usuarios. Por ejemplo, cuando accedes a una cuenta de correo web y escribes tu clave y contrasea se crea un documento temporal en el servidor de correo con un nmero nico y exclusivo para ese acceso identificador de sesin que te permite acceder a diferentes apartados sin necesidad de que reescribas, en cada una de las pginas, esos mismos valores. Habrs comprobado tambin, ms de una vez, su carcter efmero cuando al actualizar una pgina te ha aparecido ese mensaje tpico que dice la sesion ha caducado.

Variables de los mtodos GET y POST


Las identificaremos por los nombres $_GET y $_POST Este tipo de variables que utilizaremos con frecuencia recogen la informacin que se enva desde el cliente para ser utilizada por el servidor. Recuerda el carcter dinmico de PHP y que ese dinamismo (interaccin cliente servidor) requiere que el servidor guarde y/o interprete los datos remitidos por el cliente. La existencia de los dos tipos se justifica porque tambin existen dos tipos de mtodos(maneras) de enviar datos desde el cliente hasta el servidor. Cuando el mtodo de envo es el llamado GET los datos se recogen en variables de este tipo, y, por el contrario, si ese mtodo envo fuera POST se recogeran en aquellas.

Variables de transferencia de ficheros


Las identificaremos por el nombre $_FILES. Cuando se trata de la transferencia de un fichero desde el cliente hasta el servidor subir un fichero es necesario utilizar un procedimiento de envo distinto de los comentados en el prrafo anterior. Ser en este caso cuando se utilicen variables de este tipo.

El tipo GLOBALS

A diferencia de las anteriores, las variables de este tipo, $GLOBALS,utilizan una sintaxis algo distinta ya no llevan el guin bajo detrs de $. Su finalidad es recoger en una tabla los nombres de todas la variables establecidas como globales en cada momento as como sus valores. Si observas la tabla que tienes al final de esta pgina quiz te sorprenda leer nombre o pgina. De donde han salido esos valores?. Bueno... en esta pgina utilizamos scripts PHP y esos son los nombres de unas variables que hemos incluido en ellos. Conocida la existencia de los diferentes tipos de variables predefinidas y vista esta tabla a modo de ejemplo de su utilidad no ser preciso que profundicemos ms en el asunto. Lo trataremos en el momento en el que tengamos que hacer uso de cada una de ellas.

Variables de servidor
$_SERVER['UNIQUE_ID']

il4An0g0jIEAAHqC@fQAAAAO
$_SERVER['HTTP_HOST']

www.rinconastur.com
$_SERVER['HTTP_CONNECTION']

keep-alive
$_SERVER['HTTP_USER_AGENT']

Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.52 Safari/536.5


$_SERVER['HTTP_ACCEPT']

text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q= 0.8
$_SERVER['HTTP_REFERER']

http://www.rinconastur.com/php/php29.php
$_SERVER['HTTP_ACCEPT_ENCODING']

gzip,deflate,sdch
$_SERVER['HTTP_ACCEPT_LANGUAGE']

es-ES,es;q=0.8
$_SERVER['HTTP_ACCEPT_CHARSET']

ISO-8859-1,utf-8;q=0.7,*;q=0.3
$_SERVER['HTTP_COOKIE']

PHPSESSID=ed3f35bf913ecbae9d18c30daff4f6e8
$_SERVER['PATH']

/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin
$_SERVER['SERVER_SIGNATURE']

$_SERVER['SERVER_SOFTWARE']

Apache/2.0.63 (Unix) mod_ssl/2.0.63 OpenSSL/0.9.8e-fips-rhel 5 mod_bwlimited/1.4 PHP/5.2.11


$_SERVER['SERVER_NAME']

www.rinconastur.com
$_SERVER['SERVER_ADDR']

72.52.140.129
$_SERVER['SERVER_PORT']

80
$_SERVER['REMOTE_ADDR']

190.82.98.194
$_SERVER['DOCUMENT_ROOT']

/home/rinconas/public_html
$_SERVER['SERVER_ADMIN']

webmaster@rinconastur.net

$_SERVER['SCRIPT_FILENAME']

/home/rinconas/public_html/php/php30.php
$_SERVER['REMOTE_PORT']

33367
$_SERVER['GATEWAY_INTERFACE']

CGI/1.1
$_SERVER['SERVER_PROTOCOL']

HTTP/1.1
$_SERVER['REQUEST_METHOD']

GET
$_SERVER['QUERY_STRING']

$_SERVER['REQUEST_URI']

/php/php30.php
$_SERVER['SCRIPT_NAME']

/php/php30.php
$_SERVER['PHP_SELF']

/php/php30.php
$_SERVER['REQUEST_TIME']

1338997030
$_SERVER['argv']

$_SERVER['argc']

Variables GLOBALES
$GLOBALS['GLOBALS']['GLOBALS']

Array
$GLOBALS['GLOBALS']['_ENV']

Array
$GLOBALS['GLOBALS']['HTTP_ENV_VARS']

Array
$GLOBALS['GLOBALS']['_POST']

Array
$GLOBALS['GLOBALS']['HTTP_POST_VARS']

Array
$GLOBALS['GLOBALS']['_GET']

Array
$GLOBALS['GLOBALS']['HTTP_GET_VARS']

Array
$GLOBALS['GLOBALS']['_COOKIE']

Array
$GLOBALS['GLOBALS']['HTTP_COOKIE_VARS']

Array
$GLOBALS['GLOBALS']['_SERVER']

Array
$GLOBALS['GLOBALS']['HTTP_SERVER_VARS']

Array

$GLOBALS['GLOBALS']['_FILES']

Array
$GLOBALS['GLOBALS']['HTTP_POST_FILES']

Array
$GLOBALS['GLOBALS']['_REQUEST']

Array
$GLOBALS['GLOBALS']['xyz_DOCUMENT_ROOT']

C:/ServidoresLocales/Apache/htdocs
$GLOBALS['GLOBALS']['mi_xyz']

$GLOBALS['GLOBALS']['xyz_SERVER_ROOT']

C:/ServidoresLocales/Apache/
$GLOBALS['GLOBALS']['xyz_INSTALL']

C:/ServidoresLocales/
$GLOBALS['GLOBALS']['xyz_DIR_INSTALL']

ServidoresLocales
$GLOBALS['GLOBALS']['ver']

ver.php?URL=
$GLOBALS['GLOBALS']['ver_extension']

.php
$GLOBALS['GLOBALS']['extension']

.php
$GLOBALS['GLOBALS']['prefijo']

$GLOBALS['GLOBALS']['incluye']

general.inc.php
$GLOBALS['GLOBALS']['prefx']

$GLOBALS['GLOBALS']['prefx1']

$GLOBALS['GLOBALS']['prefx0']

$GLOBALS['GLOBALS']['opcion']

I
$GLOBALS['GLOBALS']['anterior']

php29.php
$GLOBALS['GLOBALS']['siguiente']

php31.php
$GLOBALS['GLOBALS']['clave']

Array
$GLOBALS['GLOBALS']['nombre']

argc
$GLOBALS['GLOBALS']['nombre1']

GLOBALS
$GLOBALS['GLOBALS']['valor']

GLOBALS
$GLOBALS['GLOBALS']['nombre2']

valor
$GLOBALS['_ENV']['TERM']

vt100

$GLOBALS['_ENV']['SSH_CLIENT']

80.35.161.51 52129 22
$GLOBALS['_ENV']['CPANEL_IS_CRON']

0
$GLOBALS['_ENV']['LD_LIBRARY_PATH']

/usr/local/apache/lib:
$GLOBALS['_ENV']['PATH']

/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin
$GLOBALS['_ENV']['PWD']

/usr/local/cpanel/whostmgr/docroot
$GLOBALS['_ENV']['SHLVL']

1
$GLOBALS['_ENV']['RESTARTSRV']

1
$GLOBALS['_ENV']['_']

/usr/local/apache/bin/httpd
$GLOBALS['HTTP_ENV_VARS']['TERM']

vt100
$GLOBALS['HTTP_ENV_VARS']['SSH_CLIENT']

80.35.161.51 52129 22
$GLOBALS['HTTP_ENV_VARS']['CPANEL_IS_CRON']

0
$GLOBALS['HTTP_ENV_VARS']['LD_LIBRARY_PATH']

/usr/local/apache/lib:
$GLOBALS['HTTP_ENV_VARS']['PATH']

/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin
$GLOBALS['HTTP_ENV_VARS']['PWD']

/usr/local/cpanel/whostmgr/docroot
$GLOBALS['HTTP_ENV_VARS']['SHLVL']

1
$GLOBALS['HTTP_ENV_VARS']['RESTARTSRV']

1
$GLOBALS['HTTP_ENV_VARS']['_']

/usr/local/apache/bin/httpd
$GLOBALS['_COOKIE']['PHPSESSID']

ed3f35bf913ecbae9d18c30daff4f6e8
$GLOBALS['HTTP_COOKIE_VARS']['PHPSESSID']

ed3f35bf913ecbae9d18c30daff4f6e8
$GLOBALS['_SERVER']['UNIQUE_ID']

il4An0g0jIEAAHqC@fQAAAAO
$GLOBALS['_SERVER']['HTTP_HOST']

www.rinconastur.com
$GLOBALS['_SERVER']['HTTP_CONNECTION']

keep-alive
$GLOBALS['_SERVER']['HTTP_USER_AGENT']

Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.52 Safari/536.5


$GLOBALS['_SERVER']['HTTP_ACCEPT']

text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
$GLOBALS['_SERVER']['HTTP_REFERER']

http://www.rinconastur.com/php/php29.php

$GLOBALS['_SERVER']['HTTP_ACCEPT_ENCODING']

gzip,deflate,sdch
$GLOBALS['_SERVER']['HTTP_ACCEPT_LANGUAGE']

es-ES,es;q=0.8
$GLOBALS['_SERVER']['HTTP_ACCEPT_CHARSET']

ISO-8859-1,utf-8;q=0.7,*;q=0.3
$GLOBALS['_SERVER']['HTTP_COOKIE']

PHPSESSID=ed3f35bf913ecbae9d18c30daff4f6e8
$GLOBALS['_SERVER']['PATH']

/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin
$GLOBALS['_SERVER']['SERVER_SIGNATURE']

$GLOBALS['_SERVER']['SERVER_SOFTWARE']

Apache/2.0.63 (Unix) mod_ssl/2.0.63 OpenSSL/0.9.8e-fips-rhel5 mod_bwlimited/1.4 PHP/5.2.11


$GLOBALS['_SERVER']['SERVER_NAME']

www.rinconastur.com
$GLOBALS['_SERVER']['SERVER_ADDR']

72.52.140.129
$GLOBALS['_SERVER']['SERVER_PORT']

80
$GLOBALS['_SERVER']['REMOTE_ADDR']

190.82.98.194
$GLOBALS['_SERVER']['DOCUMENT_ROOT']

/home/rinconas/public_html
$GLOBALS['_SERVER']['SERVER_ADMIN']

webmaster@rinconastur.net
$GLOBALS['_SERVER']['SCRIPT_FILENAME']

/home/rinconas/public_html/php/php30.php
$GLOBALS['_SERVER']['REMOTE_PORT']

33367
$GLOBALS['_SERVER']['GATEWAY_INTERFACE']

CGI/1.1
$GLOBALS['_SERVER']['SERVER_PROTOCOL']

HTTP/1.1
$GLOBALS['_SERVER']['REQUEST_METHOD']

GET
$GLOBALS['_SERVER']['QUERY_STRING']

$GLOBALS['_SERVER']['REQUEST_URI']

/php/php30.php
$GLOBALS['_SERVER']['SCRIPT_NAME']

/php/php30.php
$GLOBALS['_SERVER']['PHP_SELF']

/php/php30.php
$GLOBALS['_SERVER']['REQUEST_TIME']

1338997030
$GLOBALS['_SERVER']['argv']

Array
$GLOBALS['_SERVER']['argc']

$GLOBALS['HTTP_SERVER_VARS']['UNIQUE_ID']

il4An0g0jIEAAHqC@fQAAAAO
$GLOBALS['HTTP_SERVER_VARS']['HTTP_HOST']

www.rinconastur.com
$GLOBALS['HTTP_SERVER_VARS']['HTTP_CONNECTION']

keep-alive
$GLOBALS['HTTP_SERVER_VARS']['HTTP_USER_AGENT']

Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.52 Safari/536.5


$GLOBALS['HTTP_SERVER_VARS']['HTTP_ACCEPT']

text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
$GLOBALS['HTTP_SERVER_VARS']['HTTP_REFERER']

http://www.rinconastur.com/php/php29.php
$GLOBALS['HTTP_SERVER_VARS']['HTTP_ACCEPT_ENCODING']

gzip,deflate,sdch
$GLOBALS['HTTP_SERVER_VARS']['HTTP_ACCEPT_LANGUAGE']

es-ES,es;q=0.8
$GLOBALS['HTTP_SERVER_VARS']['HTTP_ACCEPT_CHARSET']

ISO-8859-1,utf-8;q=0.7,*;q=0.3
$GLOBALS['HTTP_SERVER_VARS']['HTTP_COOKIE']

PHPSESSID=ed3f35bf913ecbae9d18c30daff4f6e8
$GLOBALS['HTTP_SERVER_VARS']['PATH']

/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin
$GLOBALS['HTTP_SERVER_VARS']['SERVER_SIGNATURE']

$GLOBALS['HTTP_SERVER_VARS']['SERVER_SOFTWARE']

Apache/2.0.63 (Unix) mod_ssl/2.0.63 OpenSSL/0.9.8e-fips-rhel5 mod_bwlimited/1.4 PHP/5.2.11


$GLOBALS['HTTP_SERVER_VARS']['SERVER_NAME']

www.rinconastur.com
$GLOBALS['HTTP_SERVER_VARS']['SERVER_ADDR']

72.52.140.129
$GLOBALS['HTTP_SERVER_VARS']['SERVER_PORT']

80
$GLOBALS['HTTP_SERVER_VARS']['REMOTE_ADDR']

190.82.98.194
$GLOBALS['HTTP_SERVER_VARS']['DOCUMENT_ROOT']

/home/rinconas/public_html
$GLOBALS['HTTP_SERVER_VARS']['SERVER_ADMIN']

webmaster@rinconastur.net
$GLOBALS['HTTP_SERVER_VARS']['SCRIPT_FILENAME']

/home/rinconas/public_html/php/php30.php
$GLOBALS['HTTP_SERVER_VARS']['REMOTE_PORT']

33367
$GLOBALS['HTTP_SERVER_VARS']['GATEWAY_INTERFACE']

CGI/1.1
$GLOBALS['HTTP_SERVER_VARS']['SERVER_PROTOCOL']

HTTP/1.1
$GLOBALS['HTTP_SERVER_VARS']['REQUEST_METHOD']

GET
$GLOBALS['HTTP_SERVER_VARS']['QUERY_STRING']

$GLOBALS['HTTP_SERVER_VARS']['REQUEST_URI']

/php/php30.php
$GLOBALS['HTTP_SERVER_VARS']['SCRIPT_NAME']

/php/php30.php
$GLOBALS['HTTP_SERVER_VARS']['PHP_SELF']

/php/php30.php
$GLOBALS['HTTP_SERVER_VARS']['REQUEST_TIME']

1338997030
$GLOBALS['HTTP_SERVER_VARS']['argv']

Array
$GLOBALS['HTTP_SERVER_VARS']['argc']

0
$GLOBALS['_REQUEST']['PHPSESSID']

ed3f35bf913ecbae9d18c30daff4f6e8
$GLOBALS['xyz_DOCUMENT_ROOT']

C:/ServidoresLocales/Apache/htdocs
$GLOBALS['mi_xyz']

$GLOBALS['xyz_SERVER_ROOT']

C:/ServidoresLocales/Apache/
$GLOBALS['xyz_INSTALL']

C:/ServidoresLocales/
$GLOBALS['xyz_DIR_INSTALL']

ServidoresLocales
$GLOBALS['ver']

ver.php?URL=
$GLOBALS['ver_extension']

.php
$GLOBALS['extension']

.php
$GLOBALS['prefijo']

$GLOBALS['incluye']

general.inc.php
$GLOBALS['prefx']

$GLOBALS['prefx1']

$GLOBALS['prefx0']

$GLOBALS['opcion']

I
$GLOBALS['anterior']

php29.php
$GLOBALS['siguiente']

php31.php
$GLOBALS['clave']

php31.php
$GLOBALS['nombre']

argc

$GLOBALS['nombre1']

nombre
$GLOBALS['valor']

ed3f35bf913ecbae9d18c30daff4f6e8
$GLOBALS['nombre2']

PHPSESSID

Otras variables Valores de las variables


Cuando hablbamos de las variables y nos referamos a su mbito decamos que las variables definidas dentro de una funcin pierden sus valores en el momento en el que abandonemos el mbito de esa funcin, es decir, cuando finaliza su ejecucin. Decamos tambin que si el mbito en el que hubiera sido definida fuera externo a una funcin los valores slo se perderantemporalmente mientras durara la eventual ejecucin de las instrucciones de aquella y que, una vez acabado ese proceso, volvan a recuperar sus valores. Bajo estas condiciones, si invocramos repetidamente la misma funcin obtendramos cada vez el mismo resultado porque las posibles modificaciones que pudieran haberse producido (a travs de las instrucciones contenidas en la funcin) en sus valores se perderan cada vez que abandonramos la funcin con lo cual, cada una de las llamadas sucesivas restablecera el valor inicial.

Variables estticas
Para poder conservar el ltimo valor de una variable definida dentro de una funcin basta con definirla como esttica. La instruccin que permite establecer una variable como esttica es la siguiente: static nombre = valor;

Por ejemplo: si la variable fuera $a y el valor inicial asignado fuera 3 escribiramos: static $a=3; La variable conservar el ltimo de los valores que pudo habrsele asignado durante la ejecucin de la funcin que la contiene. No retomar el valor inicial hasta que se actualice la pgina.

Ejemplo de variables estticas


<?php # Observa que hemos prescindido de los encabezados HTML. # No son imprescindibles para la ejecucin de los scripts /* Escribamos una funcin y llammosla sinEstaticas Definamos en ella dos variables sin ninguna otra especificacin e insertemos las instrucciones para que al ejecutarse se escriban los valores de esas variables */ function sinEstaticas(){ # Pongamos aqu sus valores iniciales $a=0; $b=0; # Imprimamos estos valores iniciales echo "Valor inicial de $a: ",$a,"<br>"; echo "Valor inicial de $b: ",$b,"<br>";

/* Modifiquemos esos valores sumando 5 al valor de $a y restando 7 al valor de $b. $a +=5 y $b -=7 sern quienes haga esas nuevas asignaciones de valor ya lo iremos viendo, no te preocupes */ $a +=5; $b -=7; # Visualicemos los nuevos valores de las variables echo "Nuevo valor de $a: ",$a,"<br>"; echo "Nuevo valor de $b: ",$b,"<br>"; } # Escribamos ahora la misma funcin con una modificacin que ser # asignar la condicin de esttica a la variable $b # Llamemos a esa funcin: conEstaticas function conEstaticas(){ # Definimos $b como esttica $a=0; static $b=0; echo "Valor inicial de $a: ",$a,"<br>"; echo "Valor inicial de $b: ",$b,"<br>"; $a +=5; $b -=7; echo "Nuevo valor de $a: ",$a,"<br>"; echo "Nuevo valor de $b: ",$b,"<br>"; } # Insertemos un texto que nos ayude en el momento de la ejecucin print ("Esta es la primera llamada a sinEstaticas()<br>");

# Invoquemos la funcin sinEstaticas; sinEstaticas(); # Aadamos un nuevo comentario a la salida print ("Esta es la segunda llamada sinEstaticas()<br>"); print ("Debe dar el mismo resultado que la llamada anterior<br>"); # Invoquemos por segunda vez sinEstaticas; sinEstaticas(); # Hagamos ahora lo mismo con la funcin conEstaticas print ("Esta es la primera llamada a conEstaticas()<br>"); conEstaticas(); print ("Esta es la segunda llamada a conEstaticas()<br>"); print ("El resultado es distinto a la llamada anterior<br>"); conEstaticas(); ?>

ejemplo16.php

Variables de variables
Adems del mtodo habitual de asignacin de nombres a las variables -poner el signo $ delante de una palabra-, existe la posibilidad de que tomen como nombre el valor de otra variable previamente definida. La forma de hacerlo sera esta: $$nombre_variable_previa;

Veamos un ejemplo. Supongamos que tenemos una variable como esta: $color="verde";. Si ahora queremos definir una nueva variable que utilice como nombre el valor (verde) que est contenido en la variable previa ($color), habramos de poner algo como esto: $$color="es horrible";

Si se tratara de visualizar el valor de esta nueva variable podramos hacerlo de una de estas tres maneras: print $$color; o print ${$color}; o tambin print $verde;

Cualquiera de las instrucciones anteriores nos producira la misma salida: es horrible. Podemos preguntarnos cmo se justifica que existan dos sintaxis tan similares como $$color y ${$color}? Qu pintan las llaves?. La utilizacin de las llaves es una forma de evitar situaciones de interpretacin confusa. Supongamos que las variables tienen un nombre un poco ms raro. Por ejemplo que $color no se llama as sino $color[3] (podra ser que $color fuera un array una lista de colores y que esta variable contuviera el tercero de ellos). En este supuesto, al escribir: print $$color[3] cabra la duda de si el nmero 3 pertenece (es un ndice) a la variable $color o si ese nmero corresponde a $$color. Con print ${$color[3]} no habra lugar para esas dudas. Estaramos aludiendo de forma inequvoca a 3 como ndice de la variable $color.

Qu ocurre cuando la variable previa cambia de valor?


Cuando la variable utilizada para definir una variable de variable cambia de valor no se modifica ni el nombre de esta ltima ni tampoco su valor. Puedes ver este concepto, con un poco ms de detalle, en el cdigo fuente del ejemplo.

<?php # Definamos una variable y asignmosle un valor $color="rojo"; # Definamos ahora una nueva variable de nombre variable # usando para ello la variable anterior $$color=" es mi color preferido"; # Veamos impresos print ( "El color #o tambin print ( "El color # o tambin print ( "El color los contenidos de esas variables ".$color. $$color ."<br>"); ".$color. ${$color}."<br>"); ".$color. $rojo."<br>");

# advirtamos lo que va a ocurrir al visualizar la pgina print ("Las tres lneas anteriores deben decir lo mismo<br>"); print ("Hemos invocado la misma variable de tres formas diferentes<BR>");

# cambiemos ahora el nombre del color $color="magenta"; /* La variable $rojo seguir existiendo. El hecho de cambiar el valor a $color no significa que vayan a modificarse las variables creadas con su color anterior ni que se creen automticamente variables que tengan por nombre el nuevo valor de $color

*/

# Pongamos un mensaje de advertencia para que sea visualizado en la salida print ("Ahora la variable $color ha cambiado a magenta<br>"); print ("pero como no hemos creado ninguna variable con ese color<br>"); print ("en las lineas siguientes no aparecer nada <br>"); print ("detrs de la palabra magenta <br>"); print ("solo un mensaje de error advirtiendo que la variable no existe<br>"); /* para evitar ese mensaje de error basta con anteponer el smbolo @ a las dos instrucciones print siguientes # Escribimos los print advertidos @print (" El color ".$color.$$color."<br>"); @print (" El color ".$color.${$color}."<br>"); # Comprobemos que la variable $rojo creada como variable de variable # cuando $color="rojo" an existe y mantiene aquel valor print ("Pese a que $color vale ahora ".$color."<br>"); print ("la vieja variable $rojo sigue existiendo <br>"); print ("y conserva su valor. Es este: ".$rojo); ?>
ejemplo17.php Con mensaje de error ejemplo18.php Sin mensajes de error

Insercin de smbolos como elementos de texto


Tanto PHP como los navegadores hacen interpretaciones como smbolos del lenguaje de algunos caracteres especiales tales como$, ", o <, que cuando se pretendieran incluir como elementos no se visualizaran en pantalla. Cuando pretendamos que aparezcan escritos tendremos que indicarlo de una forma especial. En este enlace podrs ver la forma de hacerlo.

Tipos de variables
Tipos de variables
Ya hemos comentado que en PHP no es necesaria una definicin previa del tipo de variables. Segn los valores que se les vayan asignando, las variables podrn cambiar de tipo de modo automtico y se irn adaptando a los valores que contengan en cada momento. Las variables en PHP pueden ser de tres tipos: Enteras (tipo Integer) De coma flotante (tipo Double) Cadenas (tipo String)

Cualquier nmero entero cuyo valor est comprendido entre 2

31

ser interpretado por PHP como de tipo Integer.

Si el valor de una variable es un nmero decimal o siendo entero desborda el intervalo anterior, bien por asignacin directa o como resultado de una operacin aritmtica, PHP la convierte a tipo Double. Cualquier variable a la que se le asigne como valor el contenido de una cadena de caracteres (letras y/o nmeros delimitados por comillas) es interpretada por PHP como tipo String. En el cuadro siguiente podemos ver los tres tipos de variables que utiliza PHP. Las variables en PHP
Tipo Ejemplo Valor mximo Valor mnimo Observaciones Cualquier valor numrico entero (dentro de este intervalo) que se asigne a una variable ser convertido a este tipo

Integer $a=1234 2147483647 -2147483647

Double $a=1.23 una variable la convertir a este tipo String $a="123" convertir a este tipo

Cualquier valor numrico decimal, o entero fuera del intervalo anterior, que se asigne a Cualquier valor entrecomillado (sean nmeros o letras) que se asigne a una variable la

Determinacin de tipos de variables


PHP dispone de la funcin: gettype(variable) dnde variable es el nombre de la variable, devuelve una cadena de caracteres indicando el tipo de la variable que contiene.La cadena devuelta por esta funcin puede ser: Integer, double o string. Dado que PHP gestiona las variables de forma automtica y modifica los tipos de acuerdo con los valores que va tomando durante la ejecucin del script, este valor puede ser distinto segn el punto del script dnde se ejecute la funcin. En esta tabla tienes algunos ejemplos de aplicacin de esa funcin. Puedes observar en la columna Sintaxis que para visualizar el resultado anteponemos echo a gettype. Es decir, le indicamos a PHP que muestre el resultado obtenido al determinar el tipo de variable. Ejemplos de determinacin del tipo de una variable
Variable Sintaxis echo gettype($a1) echo gettype($a2) echo gettype($a3) echo gettype($a4) echo gettype($a5) echo gettype($a6) echo gettype($a7) echo gettype($a8) echo gettype($a9) echo gettype($a10) Devuelve

$a1=347 $a2=2147483647 $a3=-2147483647 $a4=23.7678 $a5=3.1416 $a6="347" $a7="3.1416" $a8="Solo literal" $a9="12.3 Literal con nmero" $a10=""

integer integer integer double double string string string string string

Forzado de tipos de variable


PHP permite forzar los tipos de las variables. Eso quiere decir que se puede obligar a PHP a asignar un tipo determinado a una variable determinada, siempre que los valores que contenga estn dentro del rango del nuevo tipo de variable. Los tipos se pueden forzar tanto en el momento de definir la variable como en un momento posterior.

Forzado y asignacin simultnea de valores


Al asignar un valor a una variable, se puede forzar su tipo de la siguiente forma. Si deseamos que la variable pase a ser tipo de doublebasta con anteponer a su valor entre parntesis tal como se indica una de las expresiones siguientes: (double), (real) o (float). Por ejemplo, tanto con $a=((double)45); como con $a=((float)45); o con $a=((real)45); se producira el mismo resultado: convertir la variable $a a tipo Double. Para forzar una variable a tipo Integer podemos anteponer a su valor una de estas expresiones: (integer), o (int). Por ejemplo: $b=((integer)4.5); o $b=((int)45); produciran el mismo efecto: convertir la variable $b a tipo Integer. Para forzar una variable a tipo String basta con anteponer a su valor (entre parntesis): (string). Por ejemplo: $c=((string)4.5); convertira la variable $c a tipo String. Forzado de tipo de variable
Variable Sintaxis echo gettype((real)$a1) echo gettype((double)$a2) echo gettype((float)$a3) echo gettype((int)$a4) echo gettype((integer)$a5) echo gettype((double)$a6) echo gettype((int)$a7) echo gettype((string)$a7) echo gettype((double)$a8) echo gettype((int)$a9) Devuelve

$a1=347 $a2=2147483647 $a3=-2147483647 $a4=23.7678 $a5=3.1416 $a6="347" $a7="3.1416" $a7="3.1416" $a8="Solo literal" $a9="12.3 Literal con nmero"

double double double integer integer double integer string double integer

Cuidado! Al modificar los tipos de variables pueden modificarse sus valores. Si forzamos a entera una variable que contenga un nmero decimal se perdera la parte decimal y la variable modificada solo contendra el valor de la parte entera. Si tratamos de convertir a numrica una variable alfanumrica el nuevo valor sera cero.
Nuevos valores de la variable
Valor inicial Sintaxis echo ((real)$a1) echo ((double)$a2) echo ((float)$a3) echo ((integer)$a5) echo ((double)$a6) echo ((int)$a7) echo ((string)$a7) echo ((int)$a8) echo ((double)$a9) Nuevo valor

$a1=347 $a2=2147483647 $a3=-2147483647 $a4=23.7678 $a5="3.1416" $a6="347" $a7="3.1416" $a8="Solo literal" $a9="12.3 Literal con nmero"

347 2147483647 -2147483647 23 3.1416 347 3.1416 0 12.3

$a9="12.3 Literal con nmero" $a10=""

echo ((int)$a9) echo ((int)$a10)

12 0

Forzado de tipos en variables ya definidas


La forma ms aconsejable de forzado de tipos en variables que ya estuvieran definidas previamente, es el uso de la siguiente instruccin: settype( var, tipo) donde var es el nombre de la variable cuyo tipo pretendemos modificar y tipo una expresin que puede contener (entre comillas) uno de estos valores: 'double', 'integer', o 'string' segn se trate de forzar a: coma flotante, entero, o cadena. Un ejemplo podra ser este: settype($a,'integer') que convertira a tipo entero la variable $a. La ejecucin de la instruccin settype devuelve (da como resultado) un valor que puede ser: true o false (1 0) segn la conversinse haya realizado con xito o no haya podido realizarse. Aqu tienes algunos ejemplos del uso de esa funcin. La tabla est organizada en bloques de tres filas que corresponden a la ejecucin de tres instrucciones y a la visualizacin del resultado de cada una de ellas. El resultado de settype primera fila solo podr ser 1 0 segn la instruccin se haya ejecutado con xito o no haya podido realizarse. En la segunda fila comprobamos el nuevo tipo de variable obtenida mediante la ejecucin de la instruccin anterior y en la terceravisualizamos los nuevos valores de la variable, que pueden haber cambiado como consecuencia del cambio de tipo. Forzado de tipos con settype()
Variable Sintaxis echo (settype($a1,'double') Devuelve

1 double 347 1 double 2147483647 1 double -2147483647 1 integer 23 1 integer 3 1 double 347 1 integer 3 1 double

$a1=347

echo gettype($a1) echo $a1 echo (settype($a2,'double')

$a2=2147483647

echo gettype($a2) echo $a2 echo settype($a3,'double')

$a3=-2147483647

echo gettype($a3) echo $a3 echo settype($a4,'integer')

$a4=23.7678

echo gettype($a4) echo $a4 echo settype($a5,'integer')

$a5=3.1416

echo gettype($a5) echo $a5 echo settype($a6,'double')

$a6="347"

echo gettype($a6) echo $a6 echo settype($a7,'integer')

$a7="3.1416"

echo gettype($a7) echo $a1

$a8="Solo literal"

echo settype($a8,'double') echo gettype($a8)

echo $a8 echo settype($a9,'integer')

0 1 integer 12

$a9="12.3 Literal con nmero"

echo gettype($a9) echo $a9

Operaciones con distintos tipos de variables


PHP permite la realizacin de operaciones aritmticas con cualquiera de los tres tipos de variables y adeca el resultado al tipo ms apropiado. En la tabla puedes ver algunos ejemplos, pero, en resumen, ocurre lo siguiente: Al operar con dos enteros, si el resultado est dentro del rango de los enteros, devuelve un entero. Si al operar con dos enteros el resultado desborda el rango entero, convierte su valor, de forma automtica, al tipo coma flotante Al operar un entero con una variable tipo coma flotante el resultado es de coma flotante. Al operar con una cadena lo hace como si se tratara de un entero. Si hay caracteres numricos al comienzo, los extrae (hasta que aparezca un punto o un carcter no numrico) y los opera como un nmero entero. Si una cadena no comienza por un carcter numrico PHP la operar tomando su valor numrico como CERO. La tabla siguiente contiene en cada fila los valores asignados a dos variables (A y B) y el resultado de la suma de ambas. A continuacin se recogen los tipos de variable de cada una de ellas y el del resultado. El tipo de este ltimo generado por PHP estar condicionado por el valor del resultado de cada una de las operaciones. Resultados de operaciones y tipos de variables resultantes
Valores A B A+B Tipos de variables A B A+B

12 12 -12 12 1.2456 1.2456 12 1.2456 12 12 1.2456 1.2456 abc abc 12abc

16 2147483647 -2147483640 1.2456 12 123.4567 abc abc 12abc 12.34567abc 12.34567abc 12.3e2abc 12abc 12.34567abc 12.34567abc

28 2147483659 -2147483652 13.2456 13.2456 124.7023 12 1.2456 24 24.34567 13.59127 1231.2456 12 12.34567 24.34567

integer integer integer integer double double integer double integer integer double double string string string

integer integer integer double integer double string string string string string string string string string

integer integer integer double double double integer double integer double double double integer double double

Utilizando formularios PHP dinmico


Hasta el momento, PHP slo nos ha servido para escribir una serie de scripts y ver los resultados de su ejecucin pero an no hemos hecho mencin alguna a la manera en la que puede establecerse un dilogo (interaccin) entre cliente y el servidor que, en definitiva, es la razn de ser de las pginas dinmicas.

Cuando se trata de pginas estticas la comunicacin est muy restringida. El cliente hace una peticin (escribe el nombre de una pgina en la barra de direcciones del navegador) y el servidor se limita a devolver los contenidos de esa pgina. Un primer paso para mejorar es esa comunicacin ser que el cliente especifique algo ms en su peticin y que el servidor interprete esa informacin complementaria. Ese algo ms puede incluirse en la barra de direcciones con la siguiente sintaxis: pagina.php?nombre1=valor1&nombre2=valor2, ...

dnde pagina.php es la direccin de una pgina que contiene scripts PHP y dnde ? es un carcter obligatorio que indica que detrs de l se incluye ms informacin. Esa informacin estar formada por parejas nombre - valor enlazadas por un signo = y separadas entre s por el smbolo &. De esa forma el servidor entendera la peticin de la siguiente forma: Vete a la pgina pagina.php, mira los scripts PHP, asigna a las variables nombre1, nombre2 etctera los valores valor1, valor2,... ejecuta los scripts con esos valores y devulveme los resultados. Observars que los nombres de las variables nunca llevan el signo $ y que los valores de las variables sean nmeros o cadenastampoco se escriben nunca entre comillas. Algunos caracteres especiales (& por ejemplo) no pueden escribirse directamente dado que se prestan a confusin dando lugar a la duda de si habran de intepretarse como un valor como el smbolo de unin. En esos casos es necesario sustituir el carcter por su codificacin URL que representa cada carcter anteponiendo el signo % al valor de su cdigo ASCII expresando en formato hexadecimal. Eneste enlace tienes una tabla de conversin. Se pueden incluir tantos nombre = valor como se desee. La nica restriccin es la longitud mxima permitida por el mtodo GET (el utilizado en este caso) que se sita en torno a los 2.000 caracteres.

Recepcin de datos
Cuando es recibida por el servidor la peticin de un documento con extensin .php en la que tras el signo ? se incluyen una o varias parejas nombre = valor, los nombres de las variables y sus valores respectivos se incluyen siempre, de forma automtica, en variables predefinidas de dos tipos: $_GET['nombre1']=valor1, $_GET['nombre2']=valor1, etctera, en las que nombre1, nombre2, ... coinciden exactamente con nombres especificados en las peticin y los valores asignados a estas variables tambin coinciden con los recibidos, junto con cada nombre, a travs de la peticin. $_REQUEST['nombre1']=valor1, $_REQUEST['nombre2']=valor1 recoge los mismos valores que la anterior $_GET. Esta aparente duplicidad de informacin tiene una funcionalidad aadida que veremos un poco ms adelante La variables anteriores tienen una sintaxis un poco engorrosa. Por eso, las versiones ms recientes de PHP incluyen una nueva funcin que puede agregar algo de funcionalidad. Es la siguiente: extract(array asociativo)

que crea de forma automtica variables con los nombres de todos los indices del array les asigna el valor de ese elemento del array. Es decir, si hemos recibido valores como $_GET['nombre1']=7 y $_GET['nombre2']='pepe' e incluimos en el script la funcin extract($_GET)PHP crear de forma automtica las variables $nombre1=7 y $nombre2='pepe'. Mediante extract($_REQUEST) obtendran los mismos resultados. En definitiva, la funcin extract() no hace otra cosa que crear variables PHP con idntico nombre al indicado en la peticin. Hay configuraciones de PHP en las que no es necesario utilizar la funcin extract(). Cuando el fichero php.ini tiene configurada la directiva register_globals=ON las variables del tipo: $nombre1=valor1, $nombre2=valor2, etctera se crearan de forma automtica al ser recibida la peticin del cliente.

Cuidado! La directiva register_globals ha evolucionado mucho a travs de las distintas versiones de PHP. En las versiones ms antiguas vena configurada, por defecto, con el valor ON. Actualmente viene configurada, tambin por defecto

comoOFF y se comenta que en futuras versiones de PHP su valor seguir siendo OFF pero ya no ser posible modificarla. Por ello, quiz lo ms prudente escribir nuestro cdigo pensando siempre que su configuracin es OFF y adems es inmodificable.

Veamos algunos ejemplos.

<?php /* Empezaremos utilizando $_GET['a'], $_GET['b' */ # Pongamos un comentario de advertencia. Recuerda que <br> # sirve para insertar un salto de lnea en la salida print ("Este resultado es el que utiliza \$_GET<br>"); print ($_GET['a']." x ".$_GET['b']." = ".$_GET['a']*$_GET['b']); /* Ahora trataremos de comprobar que tambin podemos utilizar la superglobal $_REQUEST como $_REQUEST['a'] y $_REQUEST['b'] con iguales resultados que las anteriores */ # Un comentario para identificar el origen del resultado print("<br>El resultado siguiente ha sido generado usando \$_REQUEST <br>"); print $_REQUEST['a']." x ".$_REQUEST['b']." = "; print $_REQUEST['a']*$_REQUEST['b']; ?>
ejemplo19.php ejemplo20.php

Si pulsas el enlace del ejemplo19 vers que te aparece una retahila de mensajes de advertencia. Es lgico que as sea. El script necesita los valores de las variables $a y $b. Como no recibe nada los ha de considerar con valor cero y, a la vez, dado que PHP tiene configurada la gestin de errores de forma muy estricta nos advierte que esas variables no han sido inicializadas. Si escribieras ejemplo19.php?a=21&b=456 todo funcionara correctamente. No habra lugar al mensaje de advertencia porque las variables ya tienen contenido. Para evitar la visualizacin de los mensajes de advertencia existen diferentes posibilidades. Adems de las mencionadades cuando estudibamos las variables las tienes comentadas en este enlace tenemos la opcin de modificar el script anteponiendo a las instrucciones print (las que pueden dar el mensaje de error cuando se ejecuten sin asignar valores a las variables) el smbolo @. Mediante ese smbolo (@) inhibimos la aparicin del mensaje de error al ejecutarse la instruccin a la que precede. Eso es lo que hemos hecho en elejemplo20. Vers que al ejecutarlo (aqu est su cdigo fuente) ya no aparece el mensaje de error. Como es lgico, al asignar valores a las variables escribiendo en la barra de direcciones del navegador la siguiente direccin:ejemplo20.php?a=21&b=456, (o pulsemos directamente en este enlace) el resultado no diferira en nada del obtenido con el ejemplo19.

Cuidado! Aqu, ms que nunca, conviene reiterar, una vez ms, los errores de sintaxis ms frecuentes: Los nombres de variables son distintos si se cambian maysculas y minsculas. Pon mucho cuidado en escribirlos correctamente. Los nombres de las variables predefinidas, tales como $_GET, etctera van en maysculas. No olvides poner punto y coma al final de cada lnea de instrucciones. Presta atencin a la apertura/cierre de comillas y mucha ms atencin an si se trata de comillas anidadas. En este caso procura usar (") para las exteriores y (') para las interiores.

Probemos otras de las opciones. Utilicemos la funcin extract para leer los datos recibidos.

<?php /* al incluir extract se crearn variables automticas con los nombres incluidos a travs de la barra de direcciones

del navegador */ extract($_GET); /* Escribamos una instruccin, que imprima en pantalla el valor de una de las variables extraidas ($a), una "x" que har funciones de aspa en la presentacin, otra variable ($b), el signo igual y $a*$b que es el producto de ambas variables El simbolo de multiplicar es (*) anteponemos al print el simbolo @ para evitar que aparezca mensaje de error por variable no definida @print ($a." x ".$b." = ".$a*$b); # Aadamos una bobadilla, para animar... ;-) print ("<br> Acabamos de usar la funcin extract!!"); ?>
ejemplo21.php ejemplo22.php

*/

Ejecuta este ejemplo (no aparecern mensajes de advertencia porque hemos incluido los @ que los inhiben) y observa lo que aparece. Slo x =0? y la otra lnea? El resultado es lgico. No hemos asignado valores a las variables $a y $b y por eso no escribi su valor. Sin embargo, a la hora de multiplicar -recuerda que una variable vaca es interpretada como cero a la hora de hacer operaciones la interpret como cero y con muy buen criterio nos respondi que cero por cero es cero. Escribamos ahora la direccin: ejemplo21.php?a=13&b=7, (tambin puedes pulsar en este enlace) y podremos comprobar que 13 x 7 = 91 . Observa tambin que ahora no aparece ningn mensaje de error porque hemos antepuesto @ a la instruccin print. Hagamos un nuevo experimento. Probemos ejemplo22.php?a=13&b=7 y veamos que el resultado no es el esperado. El ejemplo22 es muy similar al ejemplo21 (puedes ver aqu su cdigo fuente) pero tiene una diferencia importante. Hemos comentado la lnea que contiene la funcin extract. Por tanto esta ya no se ejecuta. Lo que realmente ocurre es que no lee los valores de las variables $a y $b porque para poder leerlas directamente se requera que la directiva register_globals de php.ini estuviera ON y, por defecto, esta directiva viene configurada como register_globals=Off. Si pruebas a cambiar esa configuracin, reinicias el servidor y pulsas de nuevo en el enlace, vers que esta vez si ha recibido los valores de a y b y nos ha dado el resultado de la operacin.

Cuidado! En modo local puedes establecer las configuraciones de php.ini a tu antojo que te permite utilizar cualquiera de las opciones de transferencia de variables. Pero, si pretendes publicar tus pginas utilizando un hosting ajeno debes usar la opcin de mayor compatibilidad se son, sin duda alguna, $_GET, $_REQUEST complementadas, si lo estimas ms cmodo con la funcin extract. Ten en cuenta que all no vas a poder modificar las configuraciones y de no tener en cuenta estos aspectos, puedes verte obligad@ a modificar tu cdigo fuente para adecuarlo a la configuracin de tu hosting.

Envo a travs de formularios


La interaccin clienteservidor que acabamos de ver resulta incmoda en su uso y no demasiado esttica. Hay una segunda opcin la de uso ms frecuente que es la utilizacin de formularios que no son elementos propios de PHP actan del lado del cliente siendo su estudio es ms propio del mbito de HTML que de PHP. No obstante por si te fuera necesario aqu tienes un formulario, en el que se comenta la sintaxis de sus elementos ms comunes.

Un ejemplo formulario

<html> <head>

</head> <body> <!-- Un formulario debe empezar siempre con una etiqueta de este tipo <form ...> dentro de la cual obligatorio indicar con esta sintaxis action='nombre.extension' el nombre de la pgina destinataria de la informacin que se incluya en el formulario. nombre.extension debe contener el nombre (o la ruta completa en el caso de que estuviera en un directorio o hosting distinto del que alberga el documento que contiene el formulario desde el que se realiza la peticin) Es opcional incluir (tambin dentro de la etiqueta <form ...>) method que puede tener dos valores method='GET' method='POST' Por defecto (cuando no se indica) se interpretar que method='GET' Tambin es opcional -a los efectos de PHP- incluir name. Ese valor es til cuando se incluyen scripts del lado del cliente del tipo JavaScript //--> <form name='mi_formulario' action='ejemplo26.php' method='post'> <!-- Pueden incluirse textos dentro del formulario --> Escribe tu nombre: <!-- Uno de los tipos de campos posibles es el tipo texto. Su sintaxis (hablamos de HTML) requiere la etiqueta <input type='text'> que indica que el contenido ser texto. Esta etiqueta debe incluir obligatoriamente un name='nombre' en el que pueden usarse caracteres alfabticos, sin tildes ni ees y sin espacios. Salvo excepciones que veremos ms adelante el nombre ha de ser nico y distinto para cada elemento del formulario. Tambin dentro de la etiqueta <input type='text'> puede incluirse value='' que puede no contener nada tal como ocurre aqu o contener el texto que, por defecto, queremos que aparezca en ese campo al cargar el formulario. Tambin puede conteenr (es opcional) size=xx. Su utilidad es la de ajustar el tamao de la ventana al nmero de caracteres que se indiquen mediante xx //-> <input type='text' name='nombre' value='' size=15><br> Escribe tu clave: <!-- <input type='password'> solo se diferencia del anterior en que en el momento de rellenarlo se sustituyen los carecteres visualizados (no el contenido) por asteriscos //--> <input type='password' name='clave' value=''><br> Elige tu color de coche favorito:<br> Los <input type='radio'> permite optar entre varios valores posibles. Habr que repetirlos tantas veces como opciones queramos habilitar. Todos los input correspondientes a la misma opcin deben tener el mismo nombre (name) value='xxxxx' deber tener un valor distinto en cada uno de ellos. El valor (loquesea) de la opcin marcada es que ser transferido a travs del formulario Si queremos que una opcin aparezca marcada (por defecto)al cargar el formulario, deberemos incluir en su etiqueta la palabra checked <!--

Los contenidos de value no se visualizan en el navegador por lo que conviene incluir una descripcin de los valores despus de cerrar la etiqueta de cada uno de esos input. Al enviar el formulario solo se transmite el value de la opcin seleccionada //--> <input type='radio' name='color' value='Rojo'>Rojo</br> <input type='radio' checked name='color' value='Verde'>Verde</br> <input type='radio' name='color' value='Azul'>Azul</br> Elige los extras:<br> <!-- Cada uno de los <input type='checkbox'> requiere un nombre distinto (name) y un valor (value) Pueden marcarse uno, varios, todos o ninguno. Si queremos que una casilla aparezca marcada (por defecto) al cargar el formulario, deberemos incluir en su etiqueta la palabra checked Solo sern transferidos a travs del formulario los nombres y valores de aquellos cuya casilla est marcada. Los contenidos de value no se visualizan en el navegador por lo que conviene incluir una descripcin de los valores despus de cerrar la etiqueta de cada input //--> <input type='checkbox' name="acondicionado" value="Aire">Aire acondicionado<br> <input type='checkbox' checked name="tapiceria" value="Tapicieria">Tapiceria en piel<br> <input type='checkbox' name="llantas" value="aluminio">Llantas de aluminio<br> <br>Cual es el precio mximo que estaras dispuesto a pagar? <!-- La etiqueta <input type='select'> requiere un nombre y una etiqueta de cierre </select> Entre ambas -apertura y cierre- deben incluirse las diferentes opciones entre las etiquetas <option>valor<option> Al enviar el formulario se transmite lo contenido despus de opcin en la seleccionada salvo que dentro de la propia etiqueta opcin se incluya un value. Si dentro de una etiqueta option escribimos selected ser esa la que aparezca seleccionada ,por defecto, al cargarse el formulario//--> <select name="precio"> <Option>Menos de 6.000 euros</option> <Option>6.001 - 8.000 euros</option> <Option selected >8.001 - 10.000 euros</option> <Option value=11634.52>10.001 - 12.000 euros</option> <Option>12.001 - 14.000 euros</option> <Option>Ms de 14.000 euros</option> </select> <!-- Las reas de texto deben tener una etiqueta de apertura <textarea name='checkbox'> seguida de una etiqueta de cierre </textarea> Dentro de la etiqueta de apertura puede incluirse rows=xx (indicar el nmero de filas) cols=yy (indicar el ancho expresado en nmero de caracteres) y opcionalmente un value='lo que sea...' que puede contener el texto que -por defecto- pretendemos que aparezca en ese espacio al cargar el formulario //--> <br> Escribe aqu cualquier otro comentario:<br> <textarea rows=5 cols=50 name='texto'></textarea><br>

<!-- El <input type='hidden'> permite insertar en un formulario una valor oculto que no requiere ser cumplimentado por el usuario y que no aparece visible en el documento. Requiere un name y un value //--> <input type="hidden" name='oculto' value='Esto ira oculto'><br> <!-- El <input type='submit'> es el encargado de ejecutar la action incluida en la etiqueta de apertura del formulario. Sera la llamada a la pgina que se indica en la action El texto que se incluya en su value ser el que se visualice en el propio botn de envio //--> <input type="submit" value="enviar"> <!-- El <input type='reset'> permite borrar todos los contenidos del formulario y reestablecer los valores por defecto de cada campo //--> <input type="reset" value="borrar"> <!-- La etiqueta </form> es la etiqueta (obligatoria) de fin del formulario </form> </body> </html> //-->

Interpretacin de los datos recibidos a travs de formularios


Igual que ocurra en el caso anterior, los datos enviados a travs de un formulario son recogidos en diferentes tipos de variables predefinidas. Ahora se aade una nueva particularidad. Existe la posibilidad de dos mtodos (method) de envo: GET o POST. En el caso anterior decamos que se utilizaba el mtodo GET, pero en el caso de los formularios son posibles ambos mtodos. Conviene tenerlo en cuenta.

Mtodo GET
No se diferencia en nada de lo descrito para el supuesto anterior. Utiliza las mismas variables predefinidas ($_GET y $_REQUEST), las utiliza con idntica sintaxis y se comporta de igual forma en lo relativo a las opciones de register_globals. Los nombres de las variables son en este caso, los incluidos como name en cada una de las etiquetas del formulario. Respecto a los valores recogidos del formulario seran los siguientes. En los casos de campos tipo: text, password y textarea seran los valores introducidos por el usuario en cada uno de ellos. En el caso de los campos tipo radio en el que varias opciones pueden tener el mismo nombre recogera el valor indicado en la casilla marcada; mientras que si se trata de campos tipo checkbox se transferiran nicamente las variables y los valores que corresponden a las casillas marcadas. Si se tratara de un campo oculto tipo hidden se transferira el valor contenido en su etiqueta y, por ltimo, en el caso del select sera transferido como valor de la variable la parte del formulario contenida entre las etiquetas <option></option> de la opcin seleccionada salvo que, dentro de la propia etiqueta option se incluya un valor mediante value=xxxxx.

Mtodo POST
En el caso de que el mtodo de envo sea POST hay una diferencia a tener en cuenta en cuanto a las variables que recogen la informacin. Ahora ser la variable superglobal $_POST['nombre'] la que reemplace a $_GET['nombre'] usado en el caso del mtodo GET. Si register_globals est en On el comportamiento de las variables directas es idntico al comentado para el caso de GET.

La opcin REQUEST
La variable superglobal $_REQUEST['nombre'] ana las funcionalidades de $_GET y $_POST y que recoge tanto los valores transferidos mediante el mtodo GET como mediante POST.

Identificacin del mtodo de envo


PHP recoge en una variable el mtodo utilizado para enviar los datos desde un formulario. Se trata de la variable: $_SERVER['REQUEST_METHOD']

que devuelve una cadena (GET POST) que especifica el mtodo de envo utilizado.

Diferencias ente los mtodos GET y POST


Las diferencias entre uno y otro mtodo son las siguientes: Mtodo GET Al ser enviado el formulario se carga en el navegador la direccin especificada como action, se le aade un ? y a continuacin se incluyen los datos del formulario. Todos los datos de la peticin van a ser visibles en la barra de direcciones del navegador. nicamente son aceptados los caracteres ASCII. Tiene una limitacin en el tamao mximo de la cadena que contiene los datos a transferir. En IE esa limitacin es de 2.083 caracteres. Suele ser utilizado cuando los datos no producen modificaciones en el servidor tal como ocurre en consultas en bases de datos, bsquedas y similares. Mtodo POST No tiene las limitaciones indicadas para el caso de GET en lo relativo a la aceptacin de caracteres no ASCII. Los datos del formulario no se visualizan en la barra de direcciones del navegador. Este mtodo de transferencia de datos es el ms habitual cuando se utilizan formularios. Suele ser utilizado cuando los datos transferidos producen algn tipo de modificacin en los dos datos almacenados en el servidor tales como: altas en bases de datos, modificaciones, etctera.

Tipos de contenidos de los formularios


Vamos a contemplar un ltimo aspecto relativo a los formularios. Se trata de la forma de codificar los datos para su transmisin (ENCTYPE). Puede especificarse dentro de la etiqueta<form> utilizando la sintaxis: enctype='valor'. En el caso de que no se especifique, tomar el valor application / x-www-form-urlencoded, sea GET o POST el mtodo que se utilice. ENCTYPE admite tambin el valor multipart/form-data como una opcin alternativa a la anterior. Las diferencias bsicas entre ambos modos de codificacin son las siguientes: En el tipo application/x-www-form-urlencoded los nombres de control y los valores se transforman en secuencias de escape, es decir, convirtiendo cada byte en una cadena %HH, donde HH es la notacin hexadecimal del valor del byte. Adems, los espacios son convertidos en signos +, los saltos de lnea se representan como %0D%0A, el nombre y el valor se separan con el signo = y los diferentes bloques nombre/valor, se separan con el carcter &. El tipo de contenido application / x-www-form-urlencoded es utilizable cuando el volumen de datos es reducido y todos los caracteres remitidos son ASCII. En cuanto a la encriptacin tipo multipart/form-data, sigue las reglas de las transferencias MIME, que comentaremos ms adelante cuando tratemos el tema del correo electrnico.

El tipo de contenido multipart / form-data debe utilizarse en formularios que contienen archivos adjuntos, caracteres no-ASCII, y datos binarios.

Cuidado! Cuando se incluye una cadena vaca ("") como valor de action en un formulario se recargar el mismo documento como respuesta al envo del formulario.

Ejemplos de las diferentes opciones de formularios


Intentaremos ver ejemplos de las diferentes opciones. Utilizaremos un formulario idntico al descrito anteriormente dnde incluiremos como action una llamada al script ejemplo26.php (su cdigo fuente es el que puedes ver aqu debajo) y donde dnde no especificaremos ningn valor para ENCTYPE con lo cual asumir su valor por defecto, application / x-www-form-urlencoded En el cdigo fuente que ves aqu debajo intentamos leer los contenidos transferidos utilizando las diferentes posibilidades que nos ofrece PHP. Incluimos dos ejemplos cuya una nica diferencia el mtodo utilizando en el formulario. En el primero de ellos se utiliza el mtodo GET y en el segundo POST.

<?php print "Empezaremos comprobando el mtodo de envo"; print " El method que ha usado fu: ".$_SERVER['REQUEST_METHOD']."<br>"; print "Leeremos los contenidos de la superglobal \$_REQUEST"; print " Funcionar tanto con el mtodo GET como con POST"."<br>"; @print $_REQUEST['nombre']."<br>"; @print $_REQUEST['clave']."<br>"; @print $_REQUEST['color']."<br>"; @print $_REQUEST['acondicionado']."<br>"; @print $_REQUEST['tapiceria']."<br>"; @print $_REQUEST['llantas']."<br>"; @print $_REQUEST['precio']."<br>"; @print $_REQUEST['texto']."<br>"; @print $_REQUEST['oculto']."<br>"; print "Ahora leeremos los contenidos de la superglobal \$_POST"; print " Slo dar resultados cuando el mtodo sea POST"."<br>"; @print $_POST['nombre']."<br>"; @print $_POST['clave']."<br>"; @print $_POST['color']."<br>"; @print $_POST['acondicionado']."<br>"; @print $_POST['tapiceria']."<br>"; @print $_POST['llantas']."<br>"; @print $_POST['precio']."<br>"; @print $_POST['texto']."<br>"; @print $_POST['oculto']."<br>"; print "Ahora leeremos los contenidos de la superglobal \$_GET"; print " Slo dar resultados cuando el mtodo sea GET"."<br>"; @print $_GET['nombre']."<br>"; @print $_GET['clave']."<br>"; @print $_GET['color']."<br>"; @print $_GET['acondicionado']."<br>"; @print $_GET['tapiceria']."<br>"; @print $_GET['llantas']."<br>"; @print $_GET['precio']."<br>"; @print $_GET['texto']."<br>"; @print $_GET['oculto']."<br>"; print "Ahora intentaremos leer variables directas" ; print " Slo dar resultados cuando REGISTER_GLOBALS=On"."<br>"; @print $nombre."<br>"; @print $clave."<br>"; @print $color."<br>"; @print $acondicionado."<br>";

@print $tapiceria."<br>"; @print $llantas."<br>"; @print $precio."<br>"; @print $texto."<br>"; @print $oculto."<br>"; print "Incluyamos la funcin extract aplicada a \$_REQUEST"; print " de esa forma dar resultados tanto cuando el mtodo sea GET como cuando sea POST. "; print " Si la hubiramos aplicado \$_POST solo funcionara con ese mtodo."; print " Si lo hubiramos hecho \$_GET solo atendera ese mtodo"."<br>"; extract($_REQUEST); @print $nombre."<br>"; @print $clave."<br>"; @print $color."<br>"; @print $acondicionado."<br>"; @print $tapiceria."<br>"; @print $llantas."<br>"; @print $precio."<br>"; @print $texto."<br>"; @print $oculto."<br>"; ?>
Con method = POST Con method = GET

Estos dos nuevos ejemplos son modificaciones de los anteriores. Ahora hemos incluido dentro de la etiqueta <form> la opcinENCTYPE="multipart/form-data" manteniendo el resto del formulario sin ninguna modificacin.
Con method = POST Con method = GET

La seguridad en los envos de datos


El tema de la seguridad es una preocupacin constante entre los usuarios de Internet. Cuando utilizamos las tcnicas que venimos comentando en esta pgina nos referimos siempre al caso de servidores remotos corremos dos tipos de riesgo de seguridad que no estara de ms tener en cuenta. El riesgo de que la informacin sea interceptada durante el proceso de transmisin desde el cliente hasta el servidor lo compartimos con todos los dems usuarios de la Red, pero hay otro el riesgo de daos en los contenidos de nuestro espacio de servidor que esexclusivamente nuestro. La transparencia del mtodo GET es tal, que incluso muestra en el momento del envio todos los datos en la barra de direcciones del navegador. Eso permite que cualquier usuario pueda conocer a simple vista la ruta completa hasta el script, as como los nombres y valores de las variables. Cuando se usa el mtodo POST los formularios son un poco ms discretos, pero igual de transparentes. El cdigo de cualquier formulario estar accesible slo con ir a la opcin Ver cdigo fuente y all estarn de nuevo todos los datos: nombre del script, nombres de las variables, etctera, con lo que, cualquier usuario y desde cualquier sitio, puede acceder a ese script. No hara falta ni usar nuestro formulario. Bastara guardar una copia del mismo en el ordenador del visitante y despus haciendo ligersimos retoques se podra acceder a nuestro script sin necesidad de utilizar el formulario alojado en nuestro servidor. Si pensamos que uno de nuestros scripts puede estar diseado con el fin de modificar algunos de los contenidos de nuestro espacio borrar datos, por ejemplo seguramente sera cuestin de empezar a preocuparnos, y mucho ms si en nuestro servidor tenemos datosimportantes. Existen formas de evitar, o al menos reducir, este tipo de riesgos. Restringir a usuarios autorizados el uso de algunos subdirectorios es una de ellas, almacenar datos importantes fuera del directorio root del servidor es otra y el uso de algunas de las variables predefinidas como elementos de proteccin puede ser una tercera. Hacemos este comentario a ttulo meramente informativo. Por el momento nos basta con manejar los formularios, pero queremos que tengas presente la existencia de ese tipo de riesgos. Ms adelante, ve- remos la manera de tratar de evitarlos. En los

contenidos opcionales de estos materiales hemos incluido informacin relativa a la configuracin y uso de servidores seguros que pueden paliar en gran medida algunos de estos riesgos de seguridad.

Operaciones aritmticas Operaciones aritmticas


En pginas anteriores hemos podido ver que PHP permite utilizar un tipo de variables las numricas cuyos valores puedan seroperados de la misma forma que se hace con los nmeros en la vida cotidiana. Los resultados de las operaciones pueden utilizarse de forma directa o ser recogidos en una nueva variable. Si asignamos a una nueva variable el resultado de una operacin el valor contenido en ella no se modifica si cambian posteriormente los de las variables que intervinieron su creacin.

Sintaxis de print y echo


Si queremos encadenar en una sola instruccin echo print el resultado de una operacin junto con otras variables (o cadenas) esimprescindible poner entre parntesis las instrucciones de la operacin. Esta norma solo tiene dos excepciones: en caso de que el print solo contenga la propia operacin o cuando utilicemos echo y el separador sea una coma.

Operadores aritmticos
Las diferentes operaciones aritmticas se realizan en PHP utilizando la siguiente sintaxis: $a + $b

Devuelve la suma de los valores nmericos contenidos en las variables $a y $b. $a $b

Devuelve la diferencia de los valores nmericos contenidos en las variables $a y $b. $a * $b

Devuelve el producto de los valores nmericos contenidos en las variables $a y $b. $a / $b

Devuelve el cociente de los valores nmericos contenidos en las variables $a y $b. (int)($a / $b)

Devuelve el cociente entero de los valores nmericos contenidos en las variables $a y $b. $a % $b

Devuelve el resto de la divisin entera de los valores nmericos contenidos en las variables $a y $b. Sqrt($a)

Devuelve la raz cuadrada del valor nmerico contenido en la variables $a. pow($a,$b)

Devuelve el resultado de elevar el valor nmericos contenido en la variable $a a la potencia indicada en la variable $b (a ) pow($a,1/$b)

Devuelve el resultado de elevar el valor nmericos contenido en la variable $a a la potencia indicada en la variable 1/$b lo cual no es otra cosa que la raz de ndice $b de $a. Abs($a);

Devuelve el valor absoluto del valor nmerico contenido en la variable $a.

<?php # definamos dos variables numricas asignandoles valores $a=23; $b=34; /* hagamos una suma y escribamos directamente los resultados utilizando las instrucciones print y echo con todas sus posibles opciones de sintaxis */ print("La suma de $a + $b es: " . $a . "+" . $b . "=" . ($a+$b)."<br>"); print "La suma de $a + $b es: " . $a . "+" . $b . "=" . ($a+$b) ."<BR>"; print ("La suma de $a + $b es: " . $a . "+" . $b . "=" . ($a+$b) ."<BR>"); echo "La suma de $a + $b es: " . $a . "+" . $b . "=" . ($a+$b) ."<BR>"; echo "La suma de $a + $b es: " , $a , "+" , $b . "=" , ($a+$b) ."<BR>"; echo "La suma de $a + $b es: " , $a , "+" , $b , "=" , $a+$b ,"<BR>"; # guardemos ahora el resultado de esa operacin en una nueva variable $c=$a+$b; /*ahora presentemos el resultado utilizando esa nueva variable adviertiendo el la salida */ print ("Resultados recogidos en una nueva variable<br>"); print "La suma de $a + $b es: " . $a . "+" . $b . "=" . $c ."<BR>"; print ("La suma de $a + $b es: " . $a . "+" . $b . "=" . $c ."<BR>"); echo "La suma de $a + $b es: " . $a . "+" . $b . "=" . $c ."<BR>"; echo "La suma de $a + $b es: " , $a , "+" , $b . "=" , $c ."<BR>"; echo "La suma de $a + $b es: " , $a , "+" , $b , "=" , $c ,"<BR>"; /* modifiquemos ahora los valores de $a y $b comprobando que el cambio no modifica lo contenido en la variable $c */ $a=513; $b=648; print ("<br> C sigue valiendo: " . $c ."<br>"); # experimentemos con los parntesis en un supuesto de operaciones combinada # tratemos de sumar la variable $a con la variable $b # y multiplicar el resultado por $c. # Si escribimos print($a+$b*$c) nos har la multiplicacin antes que la suma print "<br>No he puesto parntesis y el resultado es: ".($a+$b*$c); # Si escribimos print(($a+$b)*$c) nos har la suma y luego multiplicar print "<br>He puesto parntesis y el resultado es: ".(($a+$b)*$c); ?>
ejemplo33.php

Operaciones aritmticas
Operacin Sintaxis $a+$b $a-$b $a*$b A B Resultado

Suma Diferencia Producto

12 12 12

-7.3 -7.3 -7.3

4.7 19.3 -87.6

Cociente Cociente entero Resto de la divisin Potencias a Potencias a


b b

$a/$b (int)($a/$b) $a%$b pow($a,$b) pow($a,$b) Sqrt($a) Sqrt($a) pow($a,(1/$b) Abs($b)

12 12 12 12 -7.3 12 -7.3 12

-7.3 -7.3 5 5 -3

-1.64383561644 -1 2 248832 -0.00257058174836 3.46410161514 NAN

Raz cuadrada Raz cuadrada Raz ensima Valor absoluto

3 -7.3

2.28942848511 7.3

Al realizar una operacin cuyo resultado no es un nmero real PHP devuelve la cadena NaN tal como puedes ver en el ejemplo de laraz cuadrada de un nmero negativo.

Redondeo de resultados
PHP dispone de tres opciones de redondeo: floor($z)

Redondeo por defecto ceil($z)

Redondeo por exceso round($z)

Redondeo tradicional Redondeos


tipo Sintaxis (int)$a (int)$a (int)$a (int)$a (int)$a (int)$a floor($a) floor($a) floor($a) floor($a) floor($a) floor($a) ceil($a) ceil($a) ceil($a) ceil($a) ceil($a) A Resultado

Parte entera Parte entera Parte entera Parte entera Parte entera Parte entera Redondeo por defecto Redondeo por defecto Redondeo por defecto Redondeo por defecto Redondeo por defecto Redondeo por defecto Redondeo por exceso Redondeo por exceso Redondeo por exceso Redondeo por exceso Redondeo por exceso

12 -7.3 -13.8546 -24.5 13.8546 24.5 12 -7.3 -13.8546 -24.5 13.8546 24.5 12 -7.3 -13.8546 -24.5 13.8546

12 -7 -13 -24 13 24 12 -8 -14 -25 13 24 12 -7 -13 -24 14

Redondeo por exceso Redondeo Redondeo Redondeo Redondeo Redondeo Redondeo

ceil($a) round($a) round($a) round($a) round($a) round($a) round($a)

24.5 12 -7.3 -13.8546 -24.5 13.8546 24.5

25 12 -7 -14 -25 14 25

Orden de operacin
Cuando una misma instruccin contiene una secuencia con varias operaciones el orden de ejecucin de las mismas sigue los mismos criterios que las matemticas. No se realiza una ejecucin secuencial sino que se respeta el orden de prioridad matemtico. Es decir, las potencias y races tienen prioridad frente a los productos y los cocientes, y estos, son prioritarios respecto a la suma y las diferencias. Igual que en matemticas se pueden utilizar los parntesis para modificar el orden de ejecucin de las operaciones, e igual que allPHP tambin permite encerrar parntesis dentro de parntesis.

Cuidado! Cuando realices operaciones combinadas, no olvides establecer mediante parntesis las prioridades que sean necesarias. No temas abusar de ellos! Te evitarn muchos problemas.

Punto flotante y precisin arbitraria


Las funciones aritmticas que estamos estudiando utilizan la sintaxis de punto flotante cuya precisin es limitada y, aunque depende del sistema, PHP tpicamente utiliza el formato de doble precisin IEEE 754, el cual puede dar un error relativo 16 mximo por aproximacin del orden de 1.11*10 . Las operaciones aritmticas ms elementales nunca van a dar grandes errores aunque la dimensin de estos podr irse incrementando a medida que se concatenar varios de esos errores simples en operaciones compuestas. Hay que tener en cuenta la existencia de fracciones que se pueden representar de forma exacta como nmeros de punto flotante en base 10 (por ejemplo 1/10 7/10) pero que carecen de esa exactitud al ser expresados en base 2 que es la usada internamente por PHP. As pues, hemos de tener cuidado al considerar nmeros de coma flotante hasta su ltimo dgito por los imprevisibles efectos sobretodo a la hora de la comparacin de esos errores en el resultado. Para operaciones matemticas que necesiten una mejor precisin PHP (innecesaria en el mbito cotidiano y limitada a casos muy puntuales del mbito cientfico) ofrece la calculadora binaria que soporta nmeros de cualquier tamao y precisin representados como cadenas. Las funciones que utilizan esa forma de clculo son las siguientes: bcadd($a,$b,c)

Devuelve la suma de los valores numricos contenidos en las cadenas $a y $b con una precisin (nmero de cifras decimales) especificada por el nmero entero especificado en el parmetro c. bcsub($a,$b,c)

Devuelve la diferencia entre los valores numricos contenidos en las cadenas $a y $b con una precisin (nmero de cifras decimales) especificada por el nmero entero especificado en el parmetro c.

bcmul($a,$b,c)

Devuelve el producto de los valores numricos contenidos en las cadenas $a y $b con una precisin (nmero de cifras decimales) especificada por el nmero entero especificado en el parmetro c. bcdiv($a,$b,c)

Devuelve el resultado de dividir los valores numricos contenidos en las cadenas $a y $b con la precisin especificada por el nmero entero contenido en el parmetro c. bcmod($a,$b)

devuelve el resto de la divisin entera de los valores contenidos en las cadenas $a y $b. bcpow($a,$b,c)

Devuelve el resultado de elevar el valor numrico contenido en la cadena $a a la potencia expresada por la cadena $b dando el resultado con la cantidad de decimales sealada por el parmetro c.

bcsqrt($a,c)

Devuelve la raz cuadrada del valor numrico contenido en la cadena $a con la cantidad de decimales sealada por el parmetro c. bccomp($a,$b,c)

Compara los valores contenidos en las cadenas $a y $b teniendo en cuenta nicamente el nmero de decimales especificados en c. Si $a>$b devuelve 1. Si las magnitudes comparadas son iguales devuelve 0 y si son distintas devuelve 1. Si comparamos $a='3.456' (es necesario indicar siempre los valores como cadenas) con $b='3.45' obtendremos como resultado: bccomp($a,$b,0)=0 bccomp($a,$b,1)=0 bccomp($a,$b,2)=0 bccomp($a,$b,3)=1 Compara 3 con 3 que obviamente son iguales Compara 34 con 34. Son iguales y por tanto devuelve cero Compara 345 con 345. Son iguales y por tanto devuelve cero Compara 3456 con 3450. No son iguales y por tanto devuelve uno

En el cuadro puedes ver, sealados en rojo, los resultados de efectuar la misma operacin utilizando el operador de coma flotante y estas funciones de precisin arbitraria. Si comparas las diferencias en los resultados obtenidos con cada una de ellas podrs darte idea del error provocado por los inevitables redondeos de la operacin con coma flotante.

Comparacin de punto flotante y precisin arbitraria


Comparacin de funciones matemticas
Operacin Variable Valor

$A S U M A $B bcadd($A,$B,0) $a=(double)$A $b=(double)$B

"12345678910123456789012345678901234567890" "45678910123456789012345678901234567890123" 58024589033580245801358024580135802458013 1.23456789101E+40 4.56789101235E+40

$a+$b $C $D bcadd($C,$D,50) $c=(double)$C $d=(double)$D $c+$d $A $B bcsub($A,$B,0) $a=(double)$A $b=(double)$B R E S T A $a-$b $C $D bcsub($C,$D,50) $c=(double)$C $d=(double)$D $c-$d $A $B bcmul($A,$B,0) $a=(double)$A P R O D U C T O $b=(double)$B $a*$b $C $D bcmul($C,$D,62) $c=(double)$C $d=(double)$D $c*$d $A D I V I S I N $B bcdiv($A,$B,30) $a=(double)$A $b=(double)$B $a/$b $C $D

5.80245890336E+40 58024589033580236333428572634998418440192 "0.0002345678902" "0.00000000000000000000000000000000000000001523786" 0.00023456789020000000000000000000000000001523786000 0.0002345678902 1.523786E-41 0.0002345678902 0,00023456789020000001029161995624860992393223568797 "12345678910123456789012345678901234567890" "45678910123456789012345678901234567890123" -33333231213333332223333333222333333322233 1.23456789101E+40 4.56789101235E+40 -3.33332312133E+40 -33333231213333327795815413198205132734464 "0.0002345678902" "0.00000000000000000000000000000000000000001523786" 0.00023456789019999999999999999999999999998476214000 0.0002345678902 1.523786E-41 0.0002345678902 0,00023456789020000001029161995624860992393223568797 "12345678910123456789012345678901234567890" "45678910123456789012345678901234567890123" 56393715734858534797546128354926080723008626986848 1383972550423718379870903950470 1.23456789101E+40 4.56789101235E+40 5.63937157349E+80 56393715734858529559076134525051001632068799181691 5078270593363632973621514731520 "0.0002345678902" "0.00000000000000000000000000000000000000001523786" 0.000000000000000000000000000000000000000000003574 312671362972 0.0002345678902 1.523786E-41 3.57431267136E-45 0 0,000000000000000000000000000000000000000000003574 31267136297184 "12345678910123456789012345678901234567890" "45678910123456789012345678901234567890123" 0.270270872854818178953756836882 1.23456789101E+40 4.56789101235E+40 0.270270872855 0,270270872854818211550309570157 "0.0002345678902" "0.00000000000000000000000000000000000000001523786"

bcdiv($C,$D,30) $c=(double)$C $d=(double)$D $c/$d $A R E S T O S $B bcmod($A,$B) $a=(double)$A $b=(double)$B $a % $b $A $B

15393755435474535138136194977509965310.08947450626 2690430283517501801 0.0002345678902 1.523786E-41 1.53937554355E+37 15393755435474538599292516471769399296,00000000000 0000000000000000000 "12345678910123456789012345678901234567890" "57" 19 1.23456789101E+40 57 0 "12345678910123456789012345678901234567890" "13" 15477282435120092620517640487873307882539433894477 02478876805675247359287360605519476488004915460644 30130253272627846453956411651820029120439549209342 64779279536097719586538292066102759581864670705845 47341619065960659102701030110334399943453939049941 81961179086427277645221130645386339095405377300948 55610257804029129290263282188925049521874093123594 94558994966581650612470024575134583192369561297975 69626211024080786875604177270092747586939296603680 65512433192215011092075340601280601173670507434702 7729224690000000000000 1.23456789101E+40 13 INF inf "12345678910123456789012345678901234567890" "13" 111111110651111110153.9111071478030905799220364 1.23456789101E+40 13 1.11111110651E+20 111111110651111112704,0000000000000000000000000

P O T E N C I A

bcpow($A,$B)

$a=(double)$A $b=(double)$B pow($a, $b) C U A D R A D A $A $B bcsqrt($A,15) $a=(double)$A $b=(double)$B Sqrt($a)

R A I Z

Aunque las diferencias de resultados puedan parecer muy grandes en valor absoluto (hemos exagerado premeditadamente los valores operados (tanto en valores grandes como en valores pequeos) los errores relativos son de escasa significacin. En la inmensa mayora de las situaciones (por no decir todas las cotidianas) resulta suficiente utilizar los operadores de coma flotante.

Logaritmos y trigonometra Logartmos y trigonometra


La sintaxis para el uso de las funciones logartmicas y trigonomtricas es esta: log($a)

Devuelve el valor del logaritmo neperiano de valor numrico contenido en la variable $a

Log10($a)

Devuelve el valor del logaritmo decimal de valor numrico contenido en la variable $a Exp($a)

Devuelve el valor del nmero e elevado a la variable $a (e ) Operaciones con logaritmos


Operacin Sintaxis log($a) log($a) Log10($a) Log10($a) Exp($a) Exp($a) Exp($a)
a a

$a

Resultado

Logaritmo neperiano Logaritmo neperiano Logaritmo decimal Logaritmo decimal exponencial e exponencial e exponencial e
a a a

12 -7.3 12 -7.3 12 1 -7.3 12 -7.3

2.48490664979 NAN 1.07918124605 NAN 162754.791419 2.71828182846 0.000675538775194 1000000000000 5.01187233627E-8

exponencial 10 exponencial 10

pow(10,$a) pow(10,$a)

Al realizar una operacin cuyo resultado no es un nmero real PHP devuelve la cadena NAN tal como puedes ver en los ejemplos delogaritmos de nmeros negativos. Las funciones trigonomtricas tanto las directas como las inversas consideran los valores de los angulos expresados en radianes. pi()

devuelve el valor del nmero irracional Sin($a)

devuelve el valor del seno del angulo $a expresado en radianes Cos($a)

devuelve el valor del coseno del angulo $a expresado en radianes Tan($a)

devuelve el valor de la tangente del angulo $a expresado en radianes deg2rad($a)

Transforma en radianes el del angulo $a expresado en grados sexagesimales Funciones trigonomtricas

Operacin

Sintaxis Pi() Sin($a) Sin(pi()) Cos($a) Cos(pi()) Tan($a) Tan(pi()) Tan(pi()) deg2rad($a) deg2rad($a)

Resultado

Valor de PI Seno de A (radianes) Seno de PI (radianes) Coseno de A (radianes) Coseno de PI (radianes) Tangente de A (radianes) Tangente de PI (radianes) Tangente de PI/2 (radianes) Pasa grados a radianes Pasa grados a radianes Asin($a)

3.14159265359 12 pi() 12 pi() 12 pi() pi()/2 45 30.8 -0.536572918 1.22464679915E-16 0.843853958732 -1 0.843853958732 -1.22464679915E-16 1.63312393532E+16 0.785398163397 0.537561409614

devuelve, expresado en radianes, la medida del angulo cuyo seno es $a Acos($a)

devuelve, expresado en radianes, la medida del angulo cuyo coseno es $a Atan($a)

devuelve, expresado en radianes, la medida del angulo cuya tangente es $a rad2deg($a)

convierte en grados sexagesimales la medida del angulo $a expresado en radianes Funciones trigonomtricas inversas
Operacin Sintaxis Asin($a) Asin($a) Acos($a) Acos($a) Atan($a) Atan($a) rad2deg($a) A Resultado

Arco seno de A (en radianes) Arco seno de A (en radianes) Arco coseno de A (en radianes) Arco coseno de A (en radianes) Arco tangente de A (en radianes) Arco tangente de A (en radianes) Pasa radianes a grados

0.8 12 0.8 12 0.8 12 pi()/4

0.927295218002 NAN 0.643501108793 NAN 0.674740942224 1.48765509491 45

Cambios de base y formatos Formatos de las variables numricas


En PHP, para asignar valores numricos a una variable pueden utilizarse uno de los siguientes sistemas de numeracin: Los nmeros enteros pueden escribirse en una cualquiera de estas bases: Base decimal $a=nmero

No se pueden insertar ceros a la izquierda cuando se escriben nmeros en base decimal. Base octal $a=0nmero octal Basta poner un CERO delante del nmero para que sea interpretado como escrito en base OCTAL. Obviamente, slo admite los dgitos de 0 a 7. Base hexadecimal $a=0xnmero hexadecimal Si se escribe CERO EQUIS (0x) delante del nmero, PHP lo interpretar como expresado en hexadecimal. En este caso, admitir como dgitos de 0 a 9 y de A a F. Un nmero de coma flotante puede escribirse de cualquiera de estas formas: Notacin decimal. $a=nmero Se puede utilizar un cero a la izquierda del punto decimal. Notacin cientfica $a=nmero e exponente Se puede utilizar un cero a la izquierda del punto decimal. Un ejemplo: $a=1.2e5 asigna a $a el valor: 1.2 x 10 . Cuando el -5 exponente es negativo $a=1.2e-5 asigna a $a el valor: 1.2 x 10 Asignacin de valores en distintas bases
Base Sintaxis $a=17 $a=017 $a=0x17 $a=0x1A3B $a=123000; $a=0.174 $a=1.23e5; $a=23.4e-2; Valor decimal Aplicable a
5

Base Decimal Base Octal Base Hexadecimal Base Hexadecimal Notacin decimal Base Decimal Notacin cientfica Notacin cientfica

17 15 23 6715 123000 0.174 123000 0.234

Nmeros enteros Nmeros enteros Nmeros enteros Nmeros enteros Coma flotante Coma flotante Coma flotante Coma flotante

Cambios de base
PHP permite hacer todo tipo de cambios de base. Para evitar ser reiterativos, observa los ejemplos. All tienes las diferentes funciones mediante las que se puede realizar ese proceso. Asignacin de valores en distintas bases
Valor de la variable Base Nueva base Sintaxis decoct($a) dechex($a) decbin($a) octdec($a) hexdec($a) Expresin

$a=1234 $a=1234 $a=1234 $a=1234 $a=1234

10 10 10 8 16

8 16 2 10 10

2322 4d2 10011010010 668 4660

$a=1010011 $a=1234 $a=1234 $a=1234

2 7 5 18

10 14 18 5

bindec($a) base_convert($a,7,14) base_convert($a,5,18) base_convert($a,18,5)

83 254 ae 202123

Presentaciones numricas
La presentacin de los valores numricos permite una gran variedad de formatos. El nmero de cifras decimales, los separadores de decimales y los separadores de mil pueden configurarse a voluntad utilizando alguna de estas funciones. number_format (nmero) Presenta la parte entera del nmero (sin decimales) y utiliza como separador de miles una coma (,). number_format (nmero , nmero de cifras decimales) Presenta el nmero de cifras decimales que se indiquen y utiliza como separador decimal un punto (.) y el separador de miles es una coma (,). number_format (nmero , nm decimales , "sep. decimal" , "sep. miles") Permite establecer el nmero de cifras decimales de la presentacin as como el carcter que se establezca como separador de decimales y como separadores de miles. Cuidado!. No te olvides de escribir los caracteres de separacin entre comillas. Formatos de presentacin de nmero
Valor inicial N de decimales Sep. dec. Sep. miles Sintaxis number_format($a) number_format($a,2) number_format($a ,2 , "," ,".") number_format($a ,2 , " ' " ," ") Resultado

$a=1234567.234 $a=1234567.234 $a=1234567.234 $a=1234567.234

0 2 1 1 . , '

, , . esp

1,234,567 1,234,567.23 1.234.567,2 1 234 567'2

Nmeros aleatorios El valor Unix Epoch


El conocido como tiempo UNIX o tambin Unix Epoch es un sistema referencia de tiempo cuya unidad son los segundos y que tiene su valor cero a las 00:00:00 horas (GMT) del da uno de enero de 1970. time()

La funcin time() devuelve el nmero de segundos transcurridos desde el comienzo de la Unix Epoch hasta el momento actual. Que cuantos son? Pues mira, desde el comienzo del tiempo UNIX hasta este mismo instante han transcurrido 1 338 997 370 segundos microtime()

Usando la funcin microtime() se obtiene una cadena que, adems del nmero de segundos transcurridos desde el comienzo de laUnix Epoch, incluye al comienzo de ella y separada por un espacio la parte decimal de ese tiempo expresada en microsegundos. El valor de la cadena devuelta por microtime() en este instante es 0.32155100 1338997370 . Como vers, aparece la fraccin decimal del tiempo Unix Epoch delante de su valor entero. (double)microtime()

Dado que microtime() devuelve una cadena, es posible convertirla en nmero de coma flotante anteponiendo (double) que, como recordars, es la funcin que permite forzar una cadena a nmero coma flotante. Una vez cambiado el tipo de variable el valor devuelto pormicrotime se convierte en: 0.321555 que como puedes observar es un nmero con seis decimales (si las ltimas cifras son ceros no se visualizarn). Si se multiplica el valor anterior por 1.000.000 obtenemos un nmero entero de seis cifras que cambia de valor cada millonsima de segundo. Observa el resultado de esta operacin: 321563 Fjate que ha cambiado! La diferencia no es otra cosa que el tiempo transcurrido entre los instantes en que se ejecutaron ambas instrucciones.

Nmeros aleatorios
PHP dispone de dos funciones capaces de generar nmeros aleatorios. Se trata de la funcin rand() y de la funcin mejoradamt_rand(). Generacin de un nmero aleatorio
Generador rand() Sintaxis echo rand() N aleatorio Generador mt_rand() Sintaxis echo mt_rand() N aleatorio

1691253796

1938204944

El nmero aleatorio generado est comprendido entre CERO y un valor mximo que puede determinarse para cada una de las dos opciones mediante las funciones getrandmax() y mt_getrandmax() Estos son sus valores. Valores mximos de los generadores de nmeros aleatorios
Generador rand() Sintaxis echo getrandmax() Valor mximo Generador mt_rand() Sintaxis echo mt_getrandmax() Valor mximo

2147483647

2147483647

Segn las libreras que est usando PHP, puede ocurrir que los valores mximos con ambos generadores sean iguales.

Una semilla que mejora la aleatoriedad


Se pueden ejecutar las funciones srand() o mt_srand() incluyendo en ellas una expresin como la especificada en rojo srand((double)microtime()*1000000) mt_rand((double)microtime()*1000000)

antes de invocar a las funciones rand() o mt_rand(). De esta forma estaremos introduciendo una semilla cuyo valor, tal como comentamos en el epgrafe anterior, se modifica cada millonsima de segungo y que mejora sustancialmente la aleatoriedad de los nmeros obtenidos. Aqu tenemos un ejemplo: Generacin de un nmero aleatorio con semilla
Generador rand() Sintaxis N aleatorio

srand((double)microtime()*1000000); echo rand() Generador mt_rand() Sintaxis mt_srand((double)microtime()*1000000); echo mt_rand()

82654550

N aleatorio 909959302

Manteniendo la sintaxis anterior no te olvides de incluir las semillitas se pueden generar nmeros aleatorios comprendidos dentro del intervalo que preestablezcamos. Bastara con aadir los valores de los extremos de ese intervalo como parmetros de la funcin. La sintaxis sera esta: rand(extremo inferior , extremo superior) y para la funcin mejorada mt_rand(extremo inferior , extremo superior) Generacin de un nmero aleatorio delimitando intervalos
Generador rand() Sintaxis srand((double)microtime()*1000000); echo rand(1,300) Generador mt_rand() Sintaxis mt_srand((double)microtime()*1000000); echo mt_rand(1,300) N aleatorio 173 N aleatorio 126

Variables tipo cadena Las variables de cadena


A las variables tipo cadena se les puede asignar los valores escribiendo el contenido entre comillas $var="Texto del contenido"; o por medio de la conocida como sintaxis de documento incrustado que es la siguiente: $var= <<< EOD ... contenido de la cadena... ... puede ir .... .. en varias lneas... EOD; donde EOD es una palabra cualquiera que debe repetirse exactamente igual al final de la instruccin. La sintaxis de documento inscrutado requiere tener presentes algunas consideraciones: El nombre de la variable, el signo igual que la precede, los tres smbolos < y el EOD deben escribirse en la misma lnea, que esta vez no ir acabada en punto y coma (observa que no acaba all la instruccin). Puede incluirse el texto (valor de la variable) en tantas lneas como se desee, pero hay que tener en cuenta que a la hora de visualizar el documento no se mantiene esa estructura ya que HTML slo entiende la etiqueta <BR> como indicador de salto de lnea. El cierre de la instruccin debe hacerse siempre escribiendo el EOD al comienzo una nueva lnea independiente que ahora s tiene que llevar el punto y coma que indica a PHP el final de una instruccin. Aqu tienes un ejemplo en el que se utilizan las dos formas de asignacin de valores a una cadena.

<html> <head>

<title>Ejemplo 34 - PHP</title> </head> <body> <?php $cadena1="Esto es una cadena de texto"; $cadena2= <<<Pepe Esta es otra cadena escrita con la sintaxis de documento incrustado. Se escribe en varias lneas y tiene la sintaxis siguiente. Despus de escribir el nombre de la variable y el signo igual se ponen los tres <<< y un nombre cualquiera. En este caso, Pepe. Luego hay que saltar de lnea y escribir el texto con las lneas que se desee, pero cuidado... a la hora de visualizar la cadena con la instruccin echo todo este texto se ver seguido ya que para que se visualizaran saltos de lnea en una pgina web habra que poner las famosas etiquetas <BR>. Se indica el final de la cadena escribiendo de nuevo el nombre asignado en la primera lnea -Pepe- pero teniendo la precaucin de escribirlo en una linea nueva al final de todo el texto... As como lo ves en el cdigo fuente. Pepe; $cadena3= <<<Pepa Esta es otra cadena con el nombre Pepa puedo escribir Pepa cuantas veces quiera porque el PHP no interpretar el final de documento incrustado hasta que no la escriba en una sola linea y seguida del punto y coma Pepa; echo $cadena1,"<br>"; echo $cadena2,"<br>"; echo $cadena3,"<br>"; ?> </body> </html>
ejemplo34.php

Operaciones con cadenas


La concatenacin de cadenas
Para concatenar (unir en una sola cadena) varias porciones de texto hemos venido utilizando en las instrucciones print y echo un punto (.). Este punto (.) es un elemento muy importante que, adems de la forma que hemos visto en las pginas anteriores, tiene los siguientes usos: Unir dos cadenas y recogerlas en una variable $a="cad1" . "cad2"; o $a= $b . $c podemos obtener una nueva variable formada por la unin dos trozos. Pero seguramente te preguntars qu ocurre si juntamos una variable cadena y una numrica? o qu ocurre si juntamos dos variables numricas?

En cualquiera de los supuestos puedes verlo en el ejemplo las variables sern tratadas por PHP con independencia de lo que puedan contener como de tipo cadena y la variable que contiene el resultado es del tipo string. Aadir contenidos a una variable tipo string $a .="cad1" o $a .=$b Si utilizamos una sintaxis como esta (presta mucha atencin al punto que va delante del signo igual) se aadira al valor actual de la variable $a el contenido indicado despus del signo igual. Fjate en la importancia del punto. Si est presente se aaden nuevos contenidos a la variable. En el caso de que no estuviera se asignara a la variable nicamente lo incluido despus del signo igual. Aqu tienes un ejemplo de concatenacin de variables tipo string.

<?php #definamos y asignemos valores a variables tipo cadena $cadena1="Esto es una cadena de texto"; $cadena2="Esta es una segunda cadena de texto"; #hagamos lo mismo con variables numricas $cadena3=127; $cadena4=257.89; # unmoslas mezclando tipos $union1=$cadena1 . $cadena2; $union2=$cadena1 . $cadena3; $union3=$cadena3 . $cadena4; #veamos que ha ocurrido echo $union1,"<br>"; echo $union2,"<br>"; echo $union3,"<br>"; # modifiquemos ahora una cadena # aadiendole contenidos $cadena3 .=" Este es el texto que se aadir a la variable cadena3"; # imprimamos los resultados echo $cadena3,"<br>"; # aadamos ahora un nuevo trozo, esta vez # a partir de una cadena escrita con la # sintaxis de documento incrustado $cadena3 .= <<<Pepito Ahora le aado a la cadena este trocillo asignado con el "formato" de documento incrustado Pepito; # visualicemos el resultado echo $cadena3,"<br>"; ?>
ejemplo35.php

Cuidado! Observa en el ejemplo que, excepcionalmente, la sintaxis de documento incrustado permite introducir comillas (sin ningn mtodo especial), pero recuerda que en cualquier otro caso hay que recurrir al truco del que hablbamos en aqu.

Array escalar y asociativo Qu es un array?


Un array es algo tan simple una tabla de valores. Cada uno de los elementos de esa tabla se identifica por medio de un nombre(comn para todos) y un ndice (que sera el elemento diferenciador de cada uno de ellos). Mediante el uso de arrays podemos utilizar el mismo nombre para varias variables diferencindolas por medio de sus ndices. La sintaxis que permite definir elementos en un array es esta: $nombre[indice] dnde $nombre utiliza exactamente la misma sintaxis empleada para definir variables, con la nica particularidad de que ahora deben aadrsele los corchetes y los ndices. El ndice puede ser un nmero (habra que escribirlo dentro del corchete sin comillas), una cadena(que habra que poner en el corchete encerrada entre comillas sencillas '), o una variable que tampoco necesitara ir entre comillas. Cuando los ndices de un array son nmeros se dice que es escalar mientras que si fueran cadenas se le llamara array asociativo. Tablas unidimensionales
Array escalar Variable Indice Valor Array asociativo Variable Indice Valor

$a[0] $a[1] $a[2] $a[3] $a[4] $a[5] $a[6]

0 1 2 3 4 5 6

Domingo Lunes Martes Mircoles Jueves Viernes Sbado

$a['Primero'] $a['Segundo'] $a['Tercero'] $a['Cuarto'] $a['Quinto'] $a['Sexto'] $a['Septimo']

Primero Segundo Tercero Cuarto Quinto Sexto Septimo

Domingo Lunes Martes Mircoles Jueves Viernes Sbado

Arrays escalares
Los elementos de un array escalar puede escribirse con una de estas sintaxis: $a[]=valor $a[xx]=valor $a=array(valor0, valor1, valor2,...)

En el primero de los casos PHP asigna los ndices de forma automtica atribuyendo a cada elemento el valor entero siguiente al ltimo asignado. Si es el primero que se define le pondr ndice 0 (CERO). En el segundo de los casos, seremos nosotros quienes pongamos (xx) el nmero correspondiente al valor del ndice. Si ya existiera un elemento con ese ndice, se cambiara el valor de su contenido, en caso contrario crear un nuevo elemento del array y se le asignara como valor lo especificado detrs del signo igual que de la misma forma que ocurra con las variables debera ir entre comillas si fuera una cadena o sin ellas si se tratara de un nmero. En el tercero de los supuestos, la palabra array que precede al parntesis indica que cada uno de los valores numricos o cadenas separados por comas e incluidos dentro del parntesis son los valores correspondientes a los elementos de ndices 0, 1, 2... de un array escalar.

Arrays asociativos

Los elementos de un array asociativo (aquel cuyos ndices no son nmeros) pueden escribirse usando la siguiente sintaxis: $a['indice']=valor

En este caso estamos obligados a escribir el nombre del ndice que habr de ser una cadena escrita entre comillas o tambin una variable definida previamente y con ese tipo de contenido. Tanto en el caso de los array asociativos como en los escalares es posible y bastante frecuente utilizar como ndice el contenido de una variable. El modo de hacerlo sera este $a[$indice]=valor

En este caso, sea cual fuere el valor de la variable $indice, el nombre de la variable nunca se pone entre comillas.

Ejemplo de arrays unidimensionales


<?php # Crearemos un array escalar (basta con definir un elemento) $a[2]="Este elemento es el segundo del array"; # creemos un nuevo elemento de ese array # esta vez de forma automtica # si ponemos corchetes vacos va aadiendo ndices automaticamente $a[]="Ser este tercero?"; # comprobemos que le ha puesto ndice 3 echo "El elemento ".$a[3]." tiene indice 3 (siguiente a 2) <br>"; # ahora insertemos un nuevo elemento con indice 32 $a[32]="Mi indice es 32"; # insertemos otro elemento de forma automtica $a[]= "Ir a parar al indice 33 este elemento?"; # la insercin se har con indice 33, comprobmoslo print "Vemos que contiene el elemento de indice 33 ...".$a[33]."<br>"; # qu ocurrir si pido que imprima el elemento 21 que nadie ha definido # seguramente estar vacio, comprobmoslo!! # antepondremos el @ para evitar el mensaje de advertencia de PHP @print ("Aqui--> ". $a[21]. "<--- si es que hay algo<br>"); # ahora crearemos un nuevo array llamado $b # insertmosle de forma automatica su PRIMER elemento $b[]="Estoy empezando con el array b y mi indice ser cero"; # comprobemos que efectivamente ha empezado con indice CERO print ($b[0]."<br>"); # veamos ahora eso de los arrays asociativos # creemos uno llamado $c con varios elementos $c["objeto"]="coche"; $c["color"]="rojo"; $c["tamao"]="ideal"; $c["marca"]= "Ferrari"; $c["precio"]="prohibitivo para un humilde docente"; #encadenemos variables para hacer una salida # pondremos cadenas " " para que no aparezcan los textos # pegados unos a otros.. $salida="<H2> El ". $c["objeto"] ." ".$c["marca"]." ".$c["color"]; $salida .=" tiene el tamao ideal ".$c["tamao"]; $salida .=" y su precio es ".$c["precio"]; $salida .="</H2>"; print $salida; # sigamos experimentando ahora # qu ocurrira si nos olvidamos de poner nombre al indice # e insertamos un corchete vacio lo creara?que indice pondria? # probemos ....

$c[]="crear un array escalar nuevo y le pondr indice cero?"; # tratemos ahora de visualizar esa variable # probemos a escribir $c[0] porque PHP # habr entendido que queremos un array escalar # y como no existe ninguno con ese nombre empezar por cero # comprobmoslo echo $c[0]; ?>
ejemplo36.php

Arrays bidimensionales Arrays bidimensionales


Los arrays bidimensionales pueden entenderse como algo bastante similar a una tabla de doble entrada. Cada uno de los elementos se identifica sigue siendo vlido el nombre nico que se usaba en los unidimensionales por un nombre ($nombre) seguido de dos ([ ]) que contienen los ndices (en este caso son dos ndices) del array. Los ndices pueden ser de tipo escalar -equivalen al nmero de fila y columna que la celda ocupa en la tabla asociativos lo que equivaldra en alguna medida a usar como ndices los nombres de la fila y de la columna y tambin mixtos (uno de los ndices es escalar y el otro asociativo).

Cuidado!
No dejes de tener en cuenta lo que hemos advertido al hablar de arrays unidimensionales. En este supuesto, tambin, se empiezan a numerar los arrays escalares a partir de CERO.

Arrays bidimensionales escalares


Los elementos de un array bidimensional escalar pueden escribirse usando una de estas sintaxis: $a[ ][ ]=valor o $a[xx][ ]=valor o $a[ ][xx]=valor o tambin $a[xx][yy]=valor

En el primero de los casos PHP asigna automticamente como primer ndice el valor que sigue al ltimo de los asignado a ese mismo ndice y, si es el primero que se define, le pondr como ndice 0 (CERO). Sea cual fuere el valor de primer ndice al segundo se le asignar cero ya que es en este mismo momento cuando se habr creado el primero y, por tanto, an carecer de elementos. En el segundo de los casos, asignamos un valor al primer ndice (xx) y ser el segundo quien se incremente en una unidad respecto al de valor ms alto de todos aquellos cuyo primer ndice coincide con el especificado. La tercera opcin es bastante similar a la anterior. Ahora se modificara automticamente el primer ndice y se escribira el contenido (xx) como valor del segundo. En la cuarta de las opciones se asignan libremente cada uno de los ndices (xx e yy) ponindoles valores numricos. Este es un ejemplo de uso de array bidimensionales escalares.

<?php # rellenamos el array desde [0][0] hasta [0][4] # la insercion automatica haria que este primero fuera [0][0] $a[][]=" ";

# ahora pondremos cero como indice del primer array y dejemos que PHP # nos vaya insertando automaticamente el segundo $a[0][]="3-2";$a[0][]="5-3";$a[0][]="7-1";$a[0][]="0-2"; #ahora desde [1][0] hasta [1][4] #este primero lo dejamos como automtico en ambos indices # de esta forma el primero tomar valor uno (siguiente al anterior) # de forma automtica $a[][]="0-11"; # repetimos el proceso anterior $a[1][]=" ";$a[1][]="2-1";$a[1][]="1-0";$a[1][]="1-2"; # y repetimos de nuevo, ahora crearia 2 como primer indice $a[][]="0-0"; #insertariamos los restantes valores de indice 2 $a[2][]="1-3";$a[2][]=" ";$a[2][]="1-4";$a[2][]="2-0"; # nuevo incremento del primer indice $a[][]="1-0"; # rellenamos $a[3][]="6-3";$a[3][]="14-3 ";$a[3][]=" ";$a[3][]="1-0"; # nuevo y ultimo incremento de primer indice $a[][]="1-1"; # rellenamos de nuevo $a[4][]="2-3";$a[4][]="0-1 ";$a[4][]="1-1";$a[4][]=""; # como vers el proceso no tiene complicaciones, pero ... pesadillo si es # verdad que si tuviramos una base de datos sera ms fcil? # estamos en ello, todo se andar... # # # # # tendramos que ver esos valores pero.. escribir "a mano" una tabla puede ser una tortura, as que mejor introducimos una bucle, otro recurso que estudiaremos pronto para esa labor repetitiva de mostrar en una tabla todos los datos del array

# Sera algo como esto # creamos la etiqueta de apertura de una tabla print ("<TABLE BORDER=2>"); # ahora dos bucles anidados (rojo uno, magenta el otro) # para rellenar las celdas de cada fila (el magenta) # y para insertar las etiquetas <TR> utilizaremos el rojo # antepondremos el @ a print para evitar mensaje de error for ($i=0;$i<5;$i++){ print("<tr>"); for($j=0;$j<5;$j++) { @print("<td>".$a[$i][$j]."</td>"); } } #ponemos la etiqueta de cierre de la tabla print("</table>"); ?>
ejemplo37.php

Utilizando el script anterior, con ligeros retoques estticos, hemos construido esta tabla:

Todos los resultados de la liguilla


Indice 0

2 2-1

0 1 2 3 4 0-11 0-0 1-0 1-1

3-2 5-3 1-3 6-3 14-3 2-3 0-1

7-1 0-2 1-0 1-2 1-4 2-0 1-0 1-1

Arrays bidimensionales asociativos


Los elementos de un array asociativo bidimiensional se pueden escribir usando la siguiente sintaxis: $a["indice1"]["indice2"]=valor

En este caso, los ndices sern cadenas y se escribirn entre comillas. Como ejemplo de array bidimensional emplearemos una tabla de resultados de una liga de ftbol en la que intervienen cinco equiposque como en toda liga que se precie se juega a doble partido. Resultados de la liguilla
Indice

Juvencia Mosconia Canicas Condal Piloesa 3-2 0-0 1-0 1-3 6-3 2-3 14-3 0-1 1-1 5-3 2-1 7-1 1-0 1-4 0-2 1-2 2-0 1-0

Juvencia Mosconia 0-11 Canicas Condal

Piloesa 1-1

Arrays multidimensionales Arrays multidimensionales


PHP permite el uso de arrays con dimensin superior a dos. Para modificar la dimensin del array basta con ir aadiendo nuevos ndices. $a[x][y][z]=valor; asignara un valor al elemento de ndices x, y y z de un array tridimensional $a[x][y][z][w]=valor; hara lo mismo, ahora con un array de dimensin cuatro. Pueden tener cualquier tipo de ndices: escalares, asociativos y, tambin, mixtos.

La funcin array();
Para asignar valores a una matriz puede usarse la funcin array(), que tiene la siguiente sintaxis:

$a= array ( ndice 0 => valor, ..... , ndice n => valor, ); Por ejemplo: $z=array (0 =>2, 1=>"Pepe", 2=>34.7, 3=>"34Ambrosio") producir igual resultado que: $z[0]=2; $z[1]="Pepe"; $z[2]=34.7; $z[3]="34Ambrosio"

Anidando en array();
La funcin array() permite escribir arrays de cualquier dimensin utilizando la tcnica de anidado. Si pretendemos escribir los elementos de este array: $z[0][0]=34; $z[0][1]=35; $z[0][2]=36; $z[1][0]=134; $z[1][1]=135; $z[1][2]=136; podriamos hacerlo asi:

$z=array( 0 => array ( 0 => 34, 1 => 35, 2 => 36, ), 1 => array ( 0 => 134, 1 => 135, 2 => 136, ) );
Como puedes observar, se trata de sustituir los valores asignados a los elementos de una primera funcin array() por otra nueva funcin array que contiene los segundos ndices asi como los valores asignados a los mismos. El anidado sucesivo permitira generar arrays de cualquier dimensin. Aunque en el ejemplo anterior nos hemos referido a un array escalar, idntico procedimiento sera vlido para arrays asociativos con slo cambiar los nmeros por cadenas escritas entre comillas. Este podra ser un ejemplo de array asociativo: $z['a']['A']=34; $z['a']['B']=35; $z['a']['C']=36; $z['b']['A']=134; $z['b']['B']=135; $z['b']['C']=136; que podra definirse tambin de esta forma:

$z=array( "a" => array ( "A" => 34, "B" => 35, "C" => 36, ), "b" => array ( "A" => 134, "B" => 135, "C" => 136, ) );

A medida que la dimensin se hace mayor la sintaxis requiere muchsima ms atencin y los errores son poco menos que inevitables. Refresquemos un poco la memoria. No olvides los punto y coma del final de las instrucciones. Cuidado con las formas anidadas y tambin con los parntesis. Cierra cada uno de los parntesis que abras y no olvides que los parntesis se anidan, ya sabes... el primero que se abre siempre con el ltimo que se cierra, el segundo con el penltimo, etctera. No dejes de prestar atencin a las comillas. Recuerda que hay que cerrarlas siempre y que hay que diferenciarlas en los casos en que van comillas dentro de otras comillas. Esta es la forma en la que hemos definido el array tridimensional que utilizaremos en el ejemplo.

<?php $b = array( "Juvencia" => array( "Juvencia" => array ( "Resultado" => " ", "Amarillas" => " ", "Rojas" => " ", "Penalty" => " " ), "Mosconia" => array ( "Resultado" => "3-2", "Amarillas" => "1", "Rojas" => "0", "Penalty" => "1" ), "Canicas" => array ( "Resultado" => "5-3", "Amarillas" => "0", "Rojas" => "1", "Penalty" => "2" ), "Condal" => array ( "Resultado" => "7-1", "Amarillas" => "5", "Rojas" => "2", "Penalty" => "1" ), "Piloesa" => array ( "Resultado" => "0-2", "Amarillas" => "1", "Rojas" => "0", "Penalty" => "0" ), ), "Mosconia" => array( "Juvencia" => array ( "Resultado" => "0-11 ", "Amarillas" => "4", "Rojas" => "2", "Penalty" => "4" ), "Mosconia" => array ( "Resultado" => " ", "Amarillas" => " ", "Rojas" => " ", "Penalty" => " " ),

"Canicas" => array ( "Resultado" => "2-1", "Amarillas" => "0", "Rojas" => "0", "Penalty" => "2" ), "Condal" => array ( "Resultado" => "1-0", "Amarillas" => "1", "Rojas" => "0", "Penalty" => "0" ), "Piloesa" => array ( "Resultado" => "1-2", "Amarillas" => "1", "Rojas" => "0", "Penalty" => "0" ), "Canicas" ), => array( "Juvencia" => array ( "Resultado" => "0-0", "Amarillas" => "0", "Rojas" => "1", "Penalty" => "1" ), "Mosconia" => array ( "Resultado" => "1-3", "Amarillas" => "2", "Rojas" => "0", "Penalty" => "1" ), "Canicas" => array ( "Resultado" => " ", "Amarillas" => " ", "Rojas" => " ", "Penalty" => " " ), "Condal" => array ( "Resultado" => "1-4", "Amarillas" => "2", "Rojas" => "1", "Penalty" => "1" ), "Piloesa" => array ( "Resultado" => "2-0", "Amarillas" => "1", "Rojas" => "0", "Penalty" => "0" ), ), => array( "Juvencia" => array ( "Resultado" => "1-0 ", "Amarillas" => "4", "Rojas" => "1", "Penalty" => "2" ), "Mosconia" => array ( "Resultado" => "6-3", "Amarillas" => "1", "Rojas" => "2",

"Condal"

"Penalty" => "3" ), "Canicas" => array ( "Resultado" => "14-3", "Amarillas" => "1", "Rojas" => "0", "Penalty" => "0" ), "Condal" => array ( "Resultado" => " ", "Amarillas" => " ", "Rojas" => " ", "Penalty" => " " ), "Piloesa" => array ( "Resultado" => "1-0", "Amarillas" => "3", "Rojas" => "1", "Penalty" => "0" ), "Piloesa" ), => array( "Juvencia" => array ( "Resultado" => "1-1", "Amarillas" => "0", "Rojas" => "0", "Penalty" => "1" ), "Mosconia" => array ( "Resultado" => "2-3", "Amarillas" => "1", "Rojas" => "0", "Penalty" => "0" ), "Canicas" => array ( "Resultado" => "0-1", "Amarillas" => "0", "Rojas" => "0", "Penalty" => "0" ), "Condal" => array ( "Resultado" => "1-1", "Amarillas" => "1", "Rojas" => "2", "Penalty" => "0" ), "Piloesa" => array ( "Resultado" => " ", "Amarillas" => " ", "Rojas" => " ", "Penalty" => " " ), )

); ?>
ejemplo38.php

Presentacin de nmeros Funciones de salida


Ya conocemos algunas de las funciones que PHP utiliza para mostrar informacin salidas en la ventana del navegador del cliente. Recordmoslas: echo

La funcin echo, aunque admite tambin la forma echo(), no requiere de forma obligatoria el uso de los parntesis. Detrs de lainstruccin echo pueden insertarse: variables, cadenas (stas entre comillas) y nmeros (stos sin comillas) separadas por comas. Este es un ejemplo de cdigo: $a=24; $b="Pepe"; $c="<br>"; echo $a,$b,25, "Luis",$c; que producira esta salida: 24Pepe25Luis print()

La funcin print() slo puede contener dentro del parntesis una sola variable, o el conjunto de varias de ellas enlazadas por un punto. Aqu tienes algunos ejemplos: print(25.3) producira esta salida 25.3 print("Gonzalo") escribira Gonzalo $z=3.1416; print($z); escribira 3.1416 Recuerda tambin que es posible utilizar dentro del parntesis el concatenador de cadenas. $h=3; $f=" hermanos"; print("Heladeria ".$h.$f) que escribira Heladeria 3 hermanos

Salidas con formato


Ni la funcin echo, ni tampoco print permiten establecer una presentacin (formato) en sus salidas, excepto que alguna de las variables que se use contenga el resultado de una funcin number_format. La funcin printf() ofrece un gran nmero de posibilidades en este sentido. Tanto la sintaxis como los valores de los diferentes parmetros cuando se trate de presentar nmeros las tienes resumidas en la tabla. En la pgina siguiente veremos el uso de printf() para el tratamiento de variables tipo cadena. Sintaxis printf(cadena de formato,variable1,variable2,..) Cadena de formato "%[relleno][alineacin][ancho][precisin][tipo]"
Carcter Valor

0 * 1) espacio Relleno

0 '* ' '-

Sintaxis printf("%020d",32) printf("%'*20d",32) printf("%' 20d",32) printf("%'-20d",32)

Resultado 00000000000000000032 ******************32 32 ------------------32

Observaciones En este apartado prestaremos atencin nicamente a los caracteres marcados en rojo, que son los que corresponden a las diferentes formas de relleno. Los dems parmetros los iremos tratando uno en los apartados siguientes. Cuando se pretende rellenar con ceros a la izquierda basta escribir el 0 inmediatamente detrs del

signo % Si se trata de rellenar con un carcter distinto de cero debe escribirse inmediatamente despus de% una comilla simple ' seguida del carcter de relleno. Si se pretende rellenar con espacios forzados se puede escribir la comilla simple 'einmediatamente despus teclear la combinacin ALT+0160 (carcter ASCII 160) usando el teclado numrico. Aunque obviamente no se visualiza el espacio si se conserva tal como puede verse en el ejemplo 1) Obsrvese que como la tipografa es de ancho variable y que segn el carcter que se use como relleno se modifica el ancho de la presentacin. Quiz convenga recordar que 32 es en este caso la variable a la que pretendemos dar formato y que ese valor podra ser sustituido por el nombre de una variable que contenga valores numricos. Carcter Ninguno Valor Dcha Izda Dcha Izda Dcha Izda Dcha Izda Sintaxis printf("%020d",32) printf("%020d",32) printf("%'*20d",32) printf("%'*20d",32) printf("%020s",32) printf("%020s",32) printf("%'*20s",32) printf("%'*20s",32) Resultado 00000000000000000032 32 ******************32 32****************** 00000000000000000032 32000000000000000000 ******************32 32******************

Ninguno Ninguno

Ninguno Observaciones

Alineacin En los casos en que figura Ninguno en la columna Caracter tratamos de indicar que no es
necesario escribir nada en la cadena de formato. Cuando aparece un signo () estamos indicando que debe insertarse un signo menos. Fjate que en los cuatro primeros supuestos el identificador de tipo es d, lo cual hace que considere la variable como numrica, mientras que en los cuatro ltimos ese valor es s, con lo cual considera la variable como tipo cadena. Cuando tratamos de rellenar una variable numrica con ceros por la derecha PHP los omite para no alterar el valor numrico en la presentacin Con cualquier otro carcter de relleno (incluidos los caracteres numricos con ' delante) s efecta el relleno. Carcter Entero Entero Decimal Decimal Decimal Decimal Valor 14 17 14.5 17.8 14.5 11.8 Sintaxis printf("%'*14d",32) printf("%'*-17d",32) printf("%'*14.5d",32) printf("%'*-17.8d",32) printf("%'*14.5f",32) printf("%'*-11.8f",32) Resultado ************32 32*************** ************32 32*************** ******32.00000 32.00000000

Ancho

Observaciones El ancho (n de caracteres totales) puede especificarse mediante un nmero entero para todo tipo de variables Si se expresa mediante un nmero decimal y la variable es tipo coma flotante la parte decimal indica la precisin (n de cifras decimales) y la parte entera el ancho como nmero de caracteres de la parte entera o de la parte decimal, segn se rellene a la derecha o a la izquierda. Tipo Presentacin en forma binaria Caracter correspondiente al cdigo ASCII Nmero presentado como entero Nmero presentado con decimales Presentacin en forma octal Presentacin en hexadecimal Presentacin en hexadecimal Presentacin como >cadena Valor b c Sintaxis printf("%'*14b",17) printf("%'*14c",97) Resultado *********10001 a

printf("%'*14d",17.83)

************17

Tipo

f o x X s

printf("%'*14f",17.45) printf("%'*14o",17) printf("%'*14x",170) printf("%'*14X",170) printf("%'*14s",170)

*****17.450000 ************21 ************aa ************AA ***********170

Cadenas alfanumricas (I) Funciones sobre cadenas


Algunas de las funciones que permiten manejar los formatos de las cadenas de caracteres son estas: chr(n)

Devuelve el carcter cuyo cdigo ASCII es n. ord(cadena)

Devuelve el cdigo ASCII del primero de los caracteres de la cadena. strlen(cadena)

Devuelve la longitud (nmero de caracteres) de la cadena. Los espacios son considerados como un caracter ms. strtolower(cadena)

Cambia todos los caracteres de la cadena a minsculas. strtoupper(cadena)

Convierte en maysculas todos los caracteres de la cadena. ucwords(cadena)

Convierte a maysculas la primera letra de cada una de las palabras de la cadena. ucfirst(cadena)

Convierte a maysculas la primera letra de la cadena y pone en minsculas todas las dems. ltrim(cadena)

Elimina todos los espacios que pudiera haber al principio de la cadena. rtrim(cadena)

Elimina todos los espacios que existieran al final de la cadena. trim(cadena)

Elimina los espacios tanto al principio como al final de la cadena.

chop(cadena)

Elimina los espacios al final de la cadena. Es idntica a rtrim.

Cuidado! Tanto trim, como ltrim y rtrim eliminan, adems de los espacios, las secuencias: \n, \r, \t, \v y \0; llamadas tambincaracteres protegidos.
substr(cadena,n)

Si el valor de n es positivo extrae todos los caracteres de la cadena a partir del que ocupa la posicin ensima a contar desde la izquierda. Si el valor de n es negativo sern extrados los n ltimos caracteres contenidos en la cadena. substr(cadena,n,m)

Si n y m son positivos extrae m caracteres a partir del que ocupa la posicin ensima, de izquierda a derecha. Si n es negativo y m es positivo extrae m (contados de izquierda a derecha) a partir del que ocupa la posicin ensima contada de derecha a izquierda. Si n es positivo y m es negativo extrae la cadena comprendida entre el ensimo carcter (contados de izquierda a derecha) hasta elemsimo, contando en este caso de derecha a izquierda Si n es negativo y m tambin es negativo extrae la porcin de cadena comprendida entre el emsimo y el ensimo caracteres contando, en ambos casos, de derecha a izquierda. Si el valor absoluto de n es menor que el de m devuelve una cadena vaca. strrev(cadena)

Devuelve la cadena invertida str_repeat(cadena, n)

Devuelve la cadena repetida tantas veces como indica n. str_pad(cadena, n, relleno, tipo)

Aade a la cadena los caracteres especificados en relleno (uno o varios, escritos entre comillas) hasta que alcance la longitud que indica n (un nmero) El parmetro tipo puede tomar uno de estos tres valores (sin comillas): STR_PAD_BOTH (rellena por ambos lados) STR_PAD_RIGHT(rellena por la derecha) STR_PAD_LEFT (rellena por la izquierda). Si se omite la cadena de relleno utilizar espacios y si se omite el tipo rellenar por la derecha str_replace(busca, sustituto, cadena)

Busca en la cadena las subcadenas de texto cuyo contenido es igual a busca, las reemplaza por el valor sustituto

substr_replace(cadena, sustituto, comienzo, longitud)

Sustituye por sustituto un nmero de caracteres igual a longitud contados a partir del que ocupa la posicin comienzo dentro de lacadena original. Cuando el valor de comienzo es negativo contar de derecha a izquierda para determinar el lugar de comienzo de la sustitucin. Si el valor de longitud es negativo no sustituir al final de la cadena un nmero de carcteres igual al valor absoluto de longitud. Estos son algunos ejemplos de aplicacin de las funciones de manejo de cadenas Cdigo ASCII y viceversa
Funcin chr(cdigo ASCII) ord("cadena") Ejemplo chr(97) ord("abadesa") Resultado a 97

Longitudes y conversiones maysculas/minsculas


Funcin strlen("cadena") strtolower("cadena") strtoupper("cadena") ucwords("cadena") ucfirst("cadena") Ejemplo strlen("Mide la longitud de esta cadena") strtolower("CONVIERTE A MINSCULAS") strtoupper("pasa a maysculas") ucwords("todas empiezan por mayscula") ucfirst("mayscula al principio") Resultado 31 convierte a minsculas PASA A MAYSCULAS Todas Empiezan Por Mayscula Mayscula al principio

Eliminar espacios
Funcin ltrim("cadena") rtrim("cadena") trim("cadena") chop("cadena") Ejemplo ltrim("\n \nEliminar espacios") rtrim("Eliminar espacios\n \n") trim("\n \nEliminar espacios\n \n") chop("\n \nEliminar espacios\n \n") Resultado Eliminar espacios Eliminar espacios Eliminar espacios Eliminar espacios

Extraer porciones de una cadena


Funcin substr("cadena",n) substr("cadena",n) substr("cadena",n) substr("cadena",n) substr("cadena",n,m) substr("cadena",n,m) substr("cadena",n,m) substr("cadena",n,m) substr("cadena",n,m) substr("cadena",n,m) Ejemplo substr("Extrae caracteres",3) substr("Extrae caracteres",0) substr("Extrae caracteres",-5) substr("Extrae caracteres",-2) substr("Extrae caracteres",2,6) substr("Extrae caracteres",0,8) substr("Extrae caracteres",2,-3) substr("Extrae caracteres",-7,5) substr("Extrae caracteres",-7,-5) substr("Extrae caracteres",-5,-7) Resultado rae caracteres Extrae caracteres teres es trae c Extrae c trae caracte acter ac

Modificaciones de cadenas
Funcin strrev("cadena") str_repeat("cadena",n) str_pad("cadena",n,"Relleno",Tipo) str_pad("cadena",n,"Relleno",Tipo) str_pad("cadena",n,"Relleno",Tipo) str_pad("cadena",n,"Relleno",Tipo) str_replace ("lo que dice",lo que dira,"Cadena") str_replace ("lo que dice",lo que dira,"Cadena") str_replace ("lo que dice",lo que dira,"Cadena") substr_replace ("Cadena",lo que dira,n,m) substr_replace ("Cadena",lo que dira,n,m) substr_replace ("Cadena",lo que dira,n,m) substr_replace ("Cadena",lo que dira,n,m) Ejemplo strrev("Invierte la cadena") str_repeat("Rep",5) str_pad("Pepe",10,"*",STR_PAD_BOTH) str_pad("Pepe",10,"*",STR_PAD_LEFT) str_pad("Pepe",10,"*",STR_PAD_RIGHT) str_pad("Pepe",10,"*") str_replace("e","a","Pepe") str_replace("pe","pa","Pepepe") str_replace("Pepe","Luis","Pepe") substr_replace("Esta es una cadena es de prueba","*",5,2) substr_replace("Esta es una cadena es de prueba","*",5,-2) substr_replace("Esta es una cadena es de prueba","*",-5,2) substr_replace("Esta es una cadena es de prueba","*",-5,-2) Resultado anedac al etreivnI RepRepRepRepRep ***Pepe*** ******Pepe Pepe****** Pepe****** Papa Pepapa Luis Esta * una cadena es de prueba Esta *ba Esta es una cadena es de p*eba Esta es una cadena es de p*ba

Formatos en cadenas
La funcion prinf tiene un comportamiento idntico al comentado en la pgina anterior.

printf(cadena de formato,variable1,variable2,..) Cadena de formato


Dentro de la cadena de formatos deben repetirse tantos formatos como variables se pretenda manejar "%[rell1][alin1][anc1][prec1][tipo1][sepa1]%[rell1][alin1][anc1][prec1][tipo1][sepa1]"

Hemos de mencionar aqu los separadores ya que no fueron mencionados en la pgina anterior Se puede introducir una cadena de separacin al final de una cadena de formato que puede hacer, entre otras, funcin de separacin entre dos cadenas. Por ejemplo, printf("%'*15.2f Euros",1475.875) nos devolvera: ********1475.88 Euros La funcin printf() permite presentar varios valores o variables con distintos formatos utilizando la sintaxis que se indica ms arriba. Este ejemplo : printf("%'*15.2f Euros=%'*18.0f Pesetas",1475.875,1475.875*166.386) devuelve como resultado: ********1475.88 Euros=************245565 Pesetas

Existe otra funcin PHP con caractersticas muy similares a la anterior. Se trata de sprintf(). La sintaxis es idntica sprintf (cadena de formato, variable1,variable2, ...) y su nica diferencia con printf es que, mientras que printf()imprime las variables utilizando el formato indicado, sprintf() puede guardar en una nueva variable la cadena resultante de la aplicacin del formato.

Cadenas alfanumricas (II) Funciones sobre cadenas


Como complemento a las descritas en la pgina anterior, aadimos aqu algunas otras funciones PHP que tambin permiten manejarcadenas de caracteres. AddSlashes(cadena) Inserta el carcter \ delante los siguientes: "(comillas dobles), ' (comillas simples), \ (escape) y NUL (el bit nulo). stripslashes(cadena) Quita las marcas aadidas a una cadena con la funcin AddSlashes().

chunk_split(cadena, n caracteres, separador ) Devuelve la cadena cadena despus de haberle insertado, cada n caracteres, la cadena indicada en el parmetro separador. Si no se indica separador PHP pondr un espacio. Si no se establece el parmetro n caracteres insertar el separador cada 76 caracteres. Esta funcin coloca siempre un separador al final de la cadena. parse_str(cadena) Devuelve las variables con su valor indicadas dentro de la cadena (observa la sintaxis del ejemplo). Dentro de la cadena cada variable se denomina con un nombre que va seguido de un signo igual. Los espacios se sealan con el signo + y los separadores de variables son signos & explode(separador, cadena,numero) Devuelve un array cuyos elementos contienen cada una de las porciones de la cadena (cadena) comprendidas entre dos de los caracteres sealados como (separador) hasta el mximo de porciones sealadas (numero). Los caracteres separadores no son includos en las cadenas resultantes. Si no se indica la cantidad de porciones, ser fraccionada toda la cadena. Si se indica numero el ltimo trozocontendr toda la cadena restante. implode(separador, array) Devuelve una cadena formada por todos los elementos del array separados mediante los caracteres indicados en separador. join(separador, array) Es idntica a implode. strtok(cadena, separador) Esta funcin divide la cadena cadena en trozos delimitados por el separador que se indica en separador. Cuando se invoca la primera vez extrae el primer trozo debe llevar las sintaxis strtok(cadena,separador). Al invocarla sucesivamente, se escribe solo strtok(" ") e ir recogiendo de forma secuencial los trozos sucesivos. Marcas, divisiones y uniones de cadenas
Variable cadena $a="Esta ' y \ y tambin NUL" $a="Esta \' y \\ y tambin NUL" $a="Esta es una cadena larga que presuntamente ser troceada" $a="Esta es una cadena larga que presuntamente ser troceada" $a="Esta es una cadena larga que presuntamente ser troceada" $todo="v1=Esto+sera+una+variable&v2=esto+otra&p[]=incluso+un+array" Divide la cadena $todo en sus componentes $a="Esta cadena sera devuelta en trozos" $trozo1=explode(" ",$a); echo $trozo1[0]; echo $trozo1[1]; echo $trozo1[2]; echo $trozo1[3]; echo $trozo1[4]; echo $trozo1[5]; > $trozo2=explode("a",$a); echo $trozo2[0]; echo $trozo2[1]; echo $trozo2[2]; echo $trozo2[3]; echo $trozo2[4]; Esta cadena sera devuelta en trozos Est c den ser devuelt en trozos parse_str($todo); echo $v1; echo $v2; echo $p[0]; Esto sera una variable esto otra incluso un array Sintaxis AddSlashes($a) stripslashes($a) chunk_split($a,5,"") chunk_split($a,5) chunk_split($a,76,"-") Resultado $a="Esta \' y \\ y tambin NUL" Esta ' y y tambin el nulo Esta es una cadena larga que presuntamente ser troceada Esta es un a cad ena l arga que p resun tamen te se r tr ocead a Esta es una cadena larga que presuntamente ser troceada-

Recoger en un array cada uno de los trozos delimitados por los separadores

Recoger en un array cada uno de los trozos delimitados por los separadores

echo $trozo2[5]; Recoger en un array cada uno de los trozos delimitados por los separadores hasta un mximo de 3 Anteponemos @ a print para evitar mensajes de error en los valores vacos $trozo3=explode(" ",$a,3); Esta @print $trozo3[0]; cadena @print $trozo3[1]; sera devuelta en trozos @print $trozo3[2]; @print $trozo3[3]; @print $trozo3[4]; @print $trozo3[5]; $trozo4=explode("a",$a,3); Est @print $trozo4[0]; c @print $trozo4[1]; dena sera devuelta en trozos @print $trozo4[2]; @print $trozo4[3]; @print $trozo4[4]; @print $trozo4[5]; Esta cadena sera devuelta en trozos Est* c*den* ser* devuelt* en trozos Esta-cadena-sera devuelta en trozos Est: c:dena sera devuelta en trozos Esta cadena sera devuelta en trozos Est* c*den* ser* devuelt* en trozos Esta-cadena-sera devuelta en trozos Est: c:dena sera devuelta en trozos Esta cadena ser dividida con la funcin strtok Esta cadena Esta Est c den ser dividid con l funcin strtok

Recoger en un array cada uno de los trozos delimitados por los separadores hasta un mximo de 3 Anteponemos @ a print para evitar mensajes de error en los valores vacos implode(" ",$trozo1) implode("*",$trozo2) implode("-",$trozo3) implode(":",$trozo4) join(" ",$trozo1) join("*",$trozo2) join("-",$trozo3) join(":",$trozo4) $cadena="Esta cadena ser dividida con la funcin strtok" $trocin = strtok ($cadena," "); while ($trocin) { echo "$trocin<br>"; $trocin = strtok (" "); } $trocin = strtok ($cadena," "); echo $trocin,"<br>"; $trocin1 = strtok (" "); echo $trocin1,"<br>"; $trocin2 = strtok (" "); echo $trocin2,"<br>"; $trocin = strtok ($cadena,"a"); while ($trocin) { echo "$trocin<br>"; $trocin = strtok ("a"); }

Encriptacin de cadenas
PHP dispone de funciones que permiten codificar o encriptar cadenas de caracteres. bin2hex(cadena) Devuelve una cadena ASCII que contiene la representacin hexadecimal de la cadena. La conversin se realiza byte a byte, con los 4 bits superiores primero. crypt(cadena) Devuelve la cadena encriptada utilizando una semilla aleatoria de dos caracteres. Por su caracter aleatorio, si se ejecuta dos veces seguidas tal como puedes observar en el ejemplo dar dos resultados diferentes. crypt(cadena,"xx") Devuelve la cadena encriptada utilizando como semilla los dos caracteres (entre comillas) que se escriben como segundo parmetro de la funcin. Tanto en este supuesto como en el anterior, los dos primeros caracteres de la cadena encriptada coinciden con los que han sido utilizados como semilla.

md5(cadena) Aplica el algoritmo md5 y devuelve la huella digital generada por l. Este algoritmo presenta como peculiaridades que tenga la dimensin que tenga la cadena a la que se aplique genera siempre una huella digital que no es otra cosa que una cadena formada por 32 caracteres y que no dispone de ningn mecanismo inverso. Seguramente habrs vivido esta experiencia. En muchos espacios de Internet grupos de noticias, cuentas de correo web, etctera que requieren un login y una contrasea cuando utilizas la opcin de recuperar contraseas no te envan tu contrasea anterior, sino que te generan y envan una nueva. Esto ocurre porque, por razones evidentes de seguridad, las contraseas se almacenan usando estas huellas digitales y resulta imposible recuperar los valores originales. La nica solucin en estos casos es crear una nueva contrasea (suelen hacerlo con las funciones de nmeros aleatorios), enviarla de forma automtica por correo electrnico y sustituir el valor anterior del registro de usuarios por el resultado de la codificacin md5 de la nueva contrasea. crc32(cadena) Aplica el algoritmo crc32 de comprobacin de integridad y devuelve el valor del mismo. Se utiliza muchsimo en los programas decompresin y descompresin de ficheros. Se aplica en el momento de comprimir y se incluye el valor obtenido dentro del fichero comprimido. Despus de la descompresin se vuelve a aplicar el mismo algoritmo y se comparan ambos valores. La coincidencia ser la garanta de que el fichero obtenido es idntico al original. Encriptaciones y codificaciones
Variable cadena $a="Esta es la cadena" $a="Encriptame" $a="Encriptame" $a="Encriptame" $a="Encriptame" $a="Encriptame" $a="Encriptame" $a="Encriptame" $a="Encriptame" Sintaxis bin2hex($a) crypt($a) crypt($a) crypt($a,"zq") crypt($a,"zq") crypt($a,"@$") md5($a) md5($a) crc32($a) Resultado 45737461206573206c6120636164656e610a $1$b81rcmj0$p63mW.bk0jMSf51dZiLV10 $1$ci1i4JWI$LEpFUE5kkRytnOFmXdmS// zqQ4qOeELzPFg zqQ4qOeELzPFg @$MB08wYjH9to 67c3ca0aefda2595138168a85e7b33a0 67c3ca0aefda2595138168a85e7b33a0 3166777410

Bsquedas y recuentos de caracteres


Variable cadena $a="Contando caracteres" $a="Contando caracteres" $a="Contando caracteres" $a="Pepe Perez el perverso pecador en penitencia" $a="Pepe Perez el perverso pecador enpenitencia" Sintaxis count_chars($a,0) Resultado Array

$b=count_chars($a,0); 3 echo $b[97]; $b=count_chars($a,0); 2 echo $b[ord("o")] substr_count($a,"Pe"); 2 substr_count($a,"pe"); 4

La funcin count_char($a,0) devuelve un array cuyos ndices son los cdigos ASCII de los caracteres y cuyos valores son el nmero de veces que se repite cada uno de ellos. La funcin substr_count($a,"cadena") determina el nmero de veces que aparece la cadena dentro de $a. Diferencia entre maysculas y minsculas.

Etiquetas HTML Dos interpretaciones


Recordemos que cuando un documento tiene extensin php es objeto de dos interpretaciones antes de ser visualizado en el navegador. En primer lugar es PHP quien ejecuta sus scripts y devuelve al cliente el documento resultante y, ms tarde, ser el propio navegador quien realice una segunda interpretacin del documento recibido cuyo resultado ser la visualizacin de la pgina. Cualquier salto de lnea que se inserte en un documento ser respetado por PHP y enviado al navegador, pero, como ste solo entiende como tales sus propias etiquetas <br>, no sern visualizados, aunque s estarn en el cdigo fuente de la pgina visualizada. Hemos de considerar un nuevo concepto. PHP permite utilizar algunos caracteres especiales que son transformados durante la ejecucin del script. Uno de ellos no es el nico es \n que es interpretado y convertido por el intrprete de PHP en un salto de lnea cuyo efecto ser visible en el cdigo fuente del documento enviado al navegador, pero que por no ser una etiqueta <br> no producir efecto alguno en la visualizacin de la pgina. nl2br($A)

Esta funcin inserta de forma automtica etiquetas HTML de salto de lnea (<br>). Por cada salto de lnea que exista en el texto de la cadena inserta una etiqueta <br> en la salida HTML. strtr($array,$diccionario)

Busca en la cadena $a las palabras coincidentes con los ndices del array asociativo $diccionario y las sustituye por los valoresasociados a esos ndices. get_meta_tags($a)

Devuelve un array asociativo cuyos ndices son los valores de la propiedad name de las etiquetas <meta> (escritas siempre en minsculas, sin comillas, y reemplazando, en el caso de que fuera necesario, los caracteres especiales por un guin bajo _) de la pgina web cuya direccin (absoluta o relativa) se indica en la cadena $a. Los valores de los elementos del array son los contenidos de esas etiquetas. htmlspecialchars($a)

Convierte en entidades de HTML los caracteres &, ", < y >. Con ello se consigue su visualizacin y se impide que sean interpretados como signos del lenguaje HTML. htmlentities($a) Es una funcin similar a la anterior, pero en este caso afecta a todos los caracteres que tienen equivalentes como entidad HTMLutilizando el juego de carcteres ISO-8859-1. Recuerda que son stos. Este es un ejemplo de uso de la citadas funciones

<?php /* definamos algunas variables de cadena tal como se describe en sus contenidos e incluyamos caracteres especiales \n

*/

$cadena1="Este texto est escrito en varias lneas y hemos saltado de una a otra pulsando enter";

$cadena2="Aqu\nseparamos\nlas\nlneas\ncon\nsin\npulsar\nenter"; $cadena3=<<<Prueba Nuevamente texto en varias lineas ahora usando sintaxis de documento incrustado. Seguiremos probando Prueba; $cadena4=<<<OtraPrueba Ahora\ninsertar\nalgo\ncomo\nesto OtraPrueba; # definamos una variable conteniendo saltos de linea HTML # y vayamos construyendo una variable de salida # en la que uniremos las variables anteriores insertando # entre ellas saltos de linea para facilitar la visualizacin # en el navegador $saltador="<br><br><br>"; $salida=$cadena1.$saltador; $salida .=$cadena2.$saltador; $salida .=$cadena3.$saltador; $salida .=$cadena4.$saltador; # visualicemos el resultado print $salida; #apliquemos ahora a la variable salida # la funcion nl2br y veamos el resultado print $saltador.nl2br($salida); ?>
ejemplo39.php

Si ejecutas el ejemplo y visualizas el cdigo fuente a travs del navegador podrs observar como los resultados del primer printgeneran saltos de lnea en ste. Y en el caso del cdigo correspondiente al segundo print, podrs visualizar etiquetas <BR /> que son el resultado de la aplicacin de la funcin nl2br Las cadenas y las etiquetas HTML
Cadenas $a="Esto es\nun texto escrito\n en varias lineas\nsin etiquetas<BR>"; $dicc=array ( "Lundi"=>"Lunes", "good"=>"bueno", "sun" =>"sol"); $a="Lundi es un dia good si hace sun" $a="index.php" $a="index.php" Sintaxis nl2br($a) Resultado Esto es un texto escrito en varias lineas sin etiquetas<BR> Lunes es un dia bueno si hace sol Programacin, PHP, Apache, MySQL Materiales para un curso a distancia

strtr($a,$dicc)

$b=get_meta_tags($a); echo $b['keywords'] $b=get_meta_tags($a); echo $b['description'] echo $a echo htmlspecialchars($a)

$a="<H1>A</H1>"

A
<H1>A</H1>

$a="<H1>A</H1>"

La tabla de sustituciones de htmlspecialchars es esta: Sustitye & por &amp; " por &quot;

< por &lt; > por &gt;

Operadores bit a bit Comentario previo


Incluimos la sintaxis de este tipo de operadores a ttulo meramente informativo. Rara vez ser necesario utilizarlos en nuestras aplicaciones PHP. Su utilidad suele limitarse a la gestin de perifricos y algunas operaciones de clculo de carcter muy reiterativo en la que se puede conseguir un rendimiento muy superior a los operadores tradicionales. En el mbito propio del PHP pueden tener algn inters a la hora de elaborar rutinas para encriptar el cdigo fuente de algunos scripts que por su importancia pueden requerir ese tipo de proteccin. Los que s han de resultarnos de gran inters sern el resto de los operadores. Los iremos viendo en pginas sucesivas.

Operadores bit a bit


$A & $B

El operador & compara los valores binarios de cada uno de los bits de las cadenas $A y $B y devuelve 1 en el caso que ambos sean 1, y 0 en cualquier otro caso. Cuando las variables $A y $B son cadenas compara los valores binarios de los cdigos ASCII de sus caracteres y devuelve los caracteres ASCII correspondientes al resultado de esa comparacin. El operador &
Nmeros Variables $a=12 $b=23 $a&$b=4 1100 10111 100 Nmeros como cadenas Valores binarios Variables $A="12" $B="23" $A&$B=02 Valores binarios 110001110010 110010110011 110000110010 Cadenas alfanumricas Variables $A1="Rs" $B1="aZ" $A1&$B1=@R Valores binarios 10100101110011 11000011011010 10000001010010

En los casos de cadenas hemos diferenciado en rojo el valor binario correspondiente al primer carcter. Esos valores binarios corresponden a la forma binaria del cdigo ASCII de cada uno de los caracteres

Un caso de aplicacin prctica podra se la determinacin de la condicin de par o impar de un nmero. El resultado de una comparacin $a & 1 significara que si el valor asignado a $a fuera un nmero impar su forma binaria tendra como ltimo carcter (por la derecha) un uno. Por el contrario, si fuera par ese ltimo carcter sera cero. Luego la comparacin mediante el operador & arrojara 1 (coincidencia) en el primero caso y 0 (no coincidencia en el segundo). Si ejecutamos este script: $a=13; print ($a & 1); veramos que el resultado es 1 mientras que si hiciramos lo mismo con $a=14; print ($a & 1); resultara 0. Sera una opcin alternativa a la de ver si el resto de dividir el valor de la variable entre 2 ($a=13; print ($a % 2);) es 1 (no divisible y en consecuencia impar) o si $a=14; print ($a % 2); da 0(divisible, ya que su resto es cero, y en consecuencia se trata de un nmero par). $A | $B

Funciona de forma idntica al anterior y devuelve 1 cuando al menos el valor de uno de los bits comparados es 1, y devolver 0 cuandoambos sean 0. El operador |
Nmeros Variables $a=12 Valores binarios 1100 Nmeros como cadenas Variables $A="12" Valores binarios 110001110010 Cadenas alfanumricas Variables $A1="Rs" Valores binarios 10100101110011

$b=23 $a|$b=31

10111 11111

$B="23" $A|$B=33

110010110011 110011110011

$B1="aZ" $A1|$B1=s{

11000011011010 11100111111011

Puedes observar que el tratamiento es distinto cuando los mismos valores numricos se asignan como entero y como cadena. Al asignarlos como cadena opera los valores binarios de los cdigos ASCII de los caracteres, mientras que cuando se trata de nmeros compara los valores de las expresiones binarias de los valores de cada uno de ellos $A ^ $B

Devuelve 1 cuando los bits comparados son distintos, y 0 cuando son iguales. El operador ^
Nmeros Variables $a=12 $b=23 $a^$b=27 Valores binarios 1100 10111 11011 Nmeros como cadenas Variables $A="12" $B="23" $A^$B=  Valores binarios 110001110010 110010110011 000011000001 Cadenas alfanumricas Variables $A1="Rs" $B1="aZ" $A1^$B1=3) Valores binarios 10100101110011 11000011011010 01100110101001

$A << $B

Realiza la operacin $A * 2 . Hace el clculo aadiendo $B CEROS (binarios) a la derecha de la cadena binaria $A. El operador <<
Nmeros Variables $a=12 $b=2 $a<<b=48 Valores binarios 1100 10 110000 Nmeros como cadenas Variables $A="12" $B=2 $A<<$B=48 Valores binarios 110001110010 10 110000 Cadenas alfanumricas Variables $A1="Rs" $B1=2 $A1<<$B1=0 Valores binarios 10100101110011 10

$B

El operador << multiplica el valor de la primera cadena por 2 elevado al valor de la segunda. Al ser un operador matemtico solo tiene sentido cuando ambas variables son nmeros naturales. En las cadenas alfanumricas extrae los nmeros que pudiera haber al comienzo y, en caso de no haberlos, toma valor cero. $A >> $B

Divide el valor $A entre 2 . Hace la operacin en la cadena binaria quitando $B CEROS (por la derecha) de la cadena $A. El operador >>
Nmeros Variables $a=12 $b=2 $a>>b=3 Valores binarios 1100 10 11 Nmeros como cadenas Variables $A="12" $B=2 $A>>$B=3 Valores binarios 110001110010 10 11 Cadenas alfanumricas Variables $A1="Rs" $B1=2 $A1>>$B1=0 Valores binarios 10100101110011 10

$B

Para este operador (>>) son aplicables los mismos comentarios hechos en el prrafo anterior.

~ $A

Invierte los valores de los bits de la cadena $A convirtiendo los CEROS en UNO y los UNO en CERO. El operador ~
$a=12 1100 ~$a=-13 1111111111111111111111111111111111111111111111111111111111110011

Operadores de comparacin
Si es este tu primer contacto con el mundo de la programacin es probable que ests pensando que todo esto est muy bien pero que a ti lo que te interesa es hacer cosas. En una palabra, que quieres usar PHP como herramienta para el desarrollo de tus proyectos. Esta pgina y las siguientes van a ser bsicas para el xito en ese lgico y razonable afn utilitarista. Pensemos en nuestro da a da. En cada momento de nuestra vida hacemos algo. Cada cosa que hacemos suele requerir casi siempre esta secuencia de acciones:comparar, evaluar, optar y hacer. Supongamos que queremos cambiar de coche. Lo ms prudente ser empezar por comparar las caractersticas (potencia, diseo, precio, etc.) de los diferentes modelos. Salvo en casos excepcionales, no tomaramos una decisin de compra a travs de un solo parmetro sino que haramos una evaluacin conjunta de todos esos factores (menos potencia pero mejor precio y diseo muy similar, por citar un ejemplo) y sera a travs de esa evaluacin como optaramos por una marca o modelo. Una vez ejercida la opcin y no antes sera el momento de realizar la compra del nuevo coche. PHP, y en general todos los lenguajes de programacin, disponen de herramientas que permiten emular cada uno de esos procesos de la conducta humana. Los iremos viendo en esta pgina y en las siguientes.

Operadores de comparacin
PHP dispone de los siguientes operadores de comparacin: $A == $B

El operador == compara los valores de dos variables y devuelve 1 (CIERTO) en el caso de que sean iguales y el valor NUL carcter ASCII 0 (FALSO) cuando son distintas. Mediante este operador se pueden comparar variables de distinto tipo. Para comparar una cadena con un nmero se extrae el valor entero de la cadena (si lleva dgitos al comienzo los extrae y en caso contrario le asigna el valor cero) y utiliza ese valor para hacer la comparacin. Cuando se comparan cadenas discrimina entre maysculas y minsculas ya que utiliza los cdigos ASCII de cada uno de los caracteres para hacer la comparacin que se hace de izquierda a derecha y devuelve 1 (CIERTO) slo en el caso que coincidan exactamente los contenidos de ambas cadenas. El operador ==
A $A=123 $A=123.0 $A=123 $A=123 $A=123 $A=123 $A="abc" $A="abc" $A="abc" B $B=123 $B=123 $B="123" $B="123ABC" $B=124 $B=124 $B="ABC" $B="abc" $B="abcd" Operador == == == == == == == == == Sintaxis $A==$B $A==$B $A==$B $A==$B $A==$B ord($A==$B) $A==$B $A==$B $A==$B 1 0 Resultado 1 1 1 1

Los valores de la columna sealada como Resultados se obtienen mediante la funcin echo($A==$B); Podemos ver que, en los casos que es cierta la igualdad, imprime un 1, mientras que cuando es falsa no imprime nada. Se justifica este extremo porque en caso de no coincidencia el valor devuelto es NUL (cdigo ASCII 0) y ese carcter carece de smbolo grfico. Hemos marcado en rojo una excepcin. En ese caso, la instruccin es echo ord($A==$B); y como recordars dado que ord, que devuelve el cdigo ASCII del caracter contenido en el parntesis que le acompaa, podemos comprobar a travs del cero de este resultado, que, efectivamente, la no coincidencia devuelve NUL.

$A === $B

El operador === es similar al anterior, pero realiza la comparacin en sentido estricto. Para que devuelva 1 es necesario que sean iguales los valores de las variables y tambin su tipo. El operador ===
A $A=123 $A=123.0 $A=123 $A=123 $A=123 $A=123 $A="abc" $A="abc" $A="abc" B $B=123 $B=123 $B="123" $B="123ABC" $B=124 $B=124 $B="ABC" $B="abc" $B="abcd" Operador === === === === === === === === === Sintaxis $A===$B $A===$B $A===$B $A===$B $A===$B ord($A===$B) $A===$B $A===$B $A===$B 1 0 Resultado 1

Observa que los valores sealados en rojo a diferencia de lo que ocurre con el operador anterior devuelvenNUL como resultado. En este caso no slo compara valores sino que tambin compara tipos de variables. Al ser una de ellas tipo numrico y la otra cadena alfanumrica el resultado no puede ser otro que NUL.

$A != $B

El operador != devuelve 1 cuando los valores de las variables son distintos (en general ! indica negacin, en este caso podramos leerno igual) y devuelve NUL cuando son iguales. Este operador no compara en sentido estricto, por lo que puede considerar iguales los valores de dos variables de distinto tipo. El operador !=
A $A=123 $A=123.0 $A=123 $A=123 $A=123 $A=123 $A="abc" $A="abc" $A="abc" B $B=123 $B=123 $B="123" $B="123ABC" $B=124 $B=124 $B="ABC" $B="abc" $B="abcd" Operador != != != != != != != != != Sintaxis $A!=$B $A!=$B $A!=$B $A!=$B $A!=$B ord($A!=$B) $A!=$B $A!=$B $A!=$B 1 1 49 1 Resultado

En los ejemplos sealados en rojo Puedes comprobar el carcter no estricto de este operador. Devuelve NUL porque considera que no son distintos, lo que equivale a interpretar que los considera iguales pese a que las variables sean de distinto tipo.

$A < $B

El operador < devuelve 1 cuando los valores de $A son menores que los de $B . Los criterios de comparacin son los siguientes: Los valores numricos siguen el criterio matemtico. Cuando se trata de un nmero y una cadena extrae el valor numrico de sta (cero si no hay ningn dgito al principio de la misma) y hace una comparacin matemtica. En el supuesto de dos cadenas, compara uno a uno de izquierda a derecha los cdigos ASCII de cada uno de los carcteres (primero con primero, segundo con segundo, etctera). Si al hacer esta comprobacin encuentra en la primera cadena un caracter cuyo cdigo ASCII es mayor que el correspondiente de la segunda cadena, o encuentra que todos son iguales en ambas cadenas devuelve NUL. Solo en el caso de no exitir ninguno mayor y s haber al menos uno menor devolver UNO. Cuando las cadenas tengan distinta longitud, consider (a efectos de la comparacin) que los caracteres que faltan en la cadena ms corta son NUL (ASCII 0). El operador <
A $A=123 $A=123 $A=123.0 $A=123 $A=123 $A=123 $A="abc" $A="abc" $A=" bcd" $A="aacd" $A="abc" $A="abcd" $A="A" $A="a" $A="aBC" $A="123" $A=123 B $B=123 $B="123" $B="123" $B="123ABC" $B=124 $B=124 $B="ABC" $B="abc" $B="abcd" $B="abcd" $B="abcd" $B="abc" $B="a" $B="A" $B="A" $B=124 $B="124" Operador < < < < < < < < < < < < < < < < < Sintaxis $A<$B $A<$B $A<$B $A<$B $A<$B ord($A<$B) $A<$B $A<$B $A<$B $A<$B $A<$B $A<$B $A<$B $A<$B $A<$B $A<$B $A<$B 1 1 1 1 1 1 1 49 Resultado

Observa los ejemplos sealados en rojo. Cuando las cadenas tienen distinta longitud este operador considera que los caracteres que faltan en la cadena ms corta son NUL. Esa es la razn por la que en el primer caso devuelve CIERTO (NUL es menor que d) y el segundo FALSO (d no es menor que NUL).

$A <= $B

Se comporta de forma idntica al anterior. La nica diferencia es que ahora aceptar como ciertos los casos de igualdad tanto en el caso de nmeros como en el de cdigos ASCII. El operador <=
A $A=123 $A=123.0 $A=123 $A=123 $A=123 $A=123 B $B=123 $B=123 $B="123" $B="123ABC" $B=124 $B=124 Operador <= <= <= <= <= <= Sintaxis $A<=$B $A<=$B $A<=$B $A<=$B $A<=$B ord($A<=$B) Resultado 1 1 1 1 1 49

$A="abc" $A="abc" $A="abc" $A="A" $A="a" $A="aBC" $A="123" $A=123

$B="ABC" $B="abc" $B="abcd" $B="a" $B="A" $B="A" $B=124 $B="124"

<= <= <= <= <= <= <= <=

$A<=$B $A<=$B $A<=$B $A<=$B $A<=$B $A<=$B $A<=$B $A<=$B 1 1 1 1 1

Hemos modificado la instruccin marcada en rojo para comprobar el cdigo ASCII de caracter que devuelve, en el caso de ser cierto, el resultado de la comparacin. El valor que aparece (49) como resultado es el cdigo ASCII del carcter 1.

$A > $B

Es idntico en el modo de funcionamiento a $A < $B. Solo difiere de ste en el criterio de comparacin que ahora requerir que los valores de $A sean mayores que los de la variable $B. El operador >
A $A=123 $A=123 $A=123 $A=123 $A=123 B $B=123 $B="123" $B=124 $B=124 Operador Sintaxis > > > > > > > > > > > > $A>$B $A>$B $A>$B $A>$B ord($A>$B) 0 $A>$B $A>$B $A>$B $A>$B $A>$B $A>$B $A>$B $A>$B 1 1 1 Resultado

$B="123ABC" >

$A="abc" $B="ABC" $A="abc" $B="abc" $A="abc" $B="abcd" $A="A" $A="a" $B="a" $B="A"

$A="aBC" $B="A" $A="123" $B=124 $A=123 $B="124"

$A >= $B

Aade al anterior la posibilidad de certeza en caso de igualdad. El operador >=


A $A=123 $A=123 $A=123 $A=123 $A=123 B $B=123 $B="123" $B=124 $B=124 Operador Sintaxis >= >= >= >= >= >= >= >= >= >= >= >= $A>=$B $A>=$B $A>=$B $A>=$B ord($A>=$B) 0 $A>=$B $A>=$B $A>=$B $A>=$B $A>=$B $A>=$B $A>=$B $A>=$B 1 1 1 1 Resultado 1 1 1

$B="123ABC" >=

$A="abc" $B="ABC" $A="abc" $B="abc" $A="abc" $B="abcd" $A="A" $A="a" $B="a" $B="A"

$A="aBC" $B="A" $A="123" $B=124 $A=123 $B="124"

Operadores lgicos Operadores lgicos


Mediante operadores lgicos es posible evaluar un conjunto de variables lgicas, es decir, aquellas cuyos valores sean nicamente: VERDADERO o FALSO (1 NUL). El resultado de esa evaluacin ser siempre 1 NUL. $A AND $B

El operador AND devuelve VERDADERO (1) en el caso de que todas las variables lgicas comparadas sean verdaderas, y FALSO (NUL) cuando alguna de ellas sea falsa. El operador AND
Variables Ejemplo de sintaxis Otra sintaxis Condicin A $a>$b $a>$b $a>$b $a<$b $a<$b $a<$b $a>$b $a<$b $a=32; $b=0; $c=-7; $d=4.32; $f="23 Ptas" $x=$a>$b;$y=$a>$c;$z=$a>$f; echo ($x AND $y AND $z); echo ($a>$b AND $a>$c AND $a>$f); Condicin B Condicin C A $a>$c $a>$c $a<$c $a>$c $a<$c $a>$c $a<$c $a<$c $a>$f $a<$f $a>$f $a>$f $a>$f $a<$f $a<$f $a<$f 1 1 1 1 1 1 B 1 1 1 1 1 C 1 Resultado 1

$A && $B

El operador && se comporta de forma idntica al operador AND. La nica diferencia entre ambos es que operan con distinta precedencia. Ms abajo veremos el orden de precedencia de los distintos operadores. El operador &&
Variables $a>$b $a>$b $a>$b $a<$b $a<$b $a<$b $a>$b $a<$b $a=32; $b=0; $c=-7; $d=4.32; $f="23 Ptas" B 1 1 1 1 1 1 1 1 C 1 Resultado 1 $a>$c $a>$c $a<$c $a>$c $a<$c $a>$c $a<$c $a<$c $a>$f $a<$f $a>$f $a>$f $a>$f $a<$f $a<$f $a<$f 1 1 1 Condicin A Condicin B Condicin C A

$A OR $B

Para que el operador OR devuelva VERDADERO (1) es suficiente que una sola de las variables lgicas comparadas sea verdadera. nicamente devolver FALSO (NUL) cuando todas ellas sean FALSAS. El operador OR

Variables $a>$b $a>$b $a>$b $a<$b $a<$b $a<$b $a>$b $a<$b

$a=32; $b=0; $c=-7; $d=4.32; $f="23 Ptas" B 1 1 1 1 1 1 1 1 C 1 Resultado 1 1 1 1 1 1 1 $a>$c $a>$c $a<$c $a>$c $a<$c $a>$c $a<$c $a<$c $a>$f $a<$f $a>$f $a>$f $a>$f $a<$f $a<$f $a<$f

Condicin A Condicin B Condicin C A 1 1 1

$A || $B

El operador || se comporta de forma idntica al operador OR. Su nica diferencia es el orden de precedencia con el que opera. El operador ||
Variables $a>$b $a>$b $a>$b $a<$b $a<$b $a<$b $a>$b $a<$b $a=32; $b=0; $c=-7; $d=4.32; $f="23 Ptas" B 1 1 1 1 1 1 1 1 C 1 Resultado 1 1 1 1 1 1 1 $a>$c $a>$c $a<$c $a>$c $a<$c $a>$c $a<$c $a<$c $a>$f $a<$f $a>$f $a>$f $a>$f $a<$f $a<$f $a<$f 1 1 1 Condicin A Condicin B Condicin C A

$A XOR $B

El operador XOR devuelve VERDADERO (1) slo en el caso de que sea cierta una sola de las variables, y FALSO (NUL) cuando ambas sean ciertas o ambas sean falsas. El operador XOR
Variables $a>$b $a>$b $a<$b $a<$b $a=32; $b=0; $c=-7; $d=4.32; $f="23 Ptas" A 1 1 1 B 1 1 1 Resultado $a>$c $a<$c $a>$c $a<$c Condicin A Condicin B

! $A

Este operador NOT (negacin) devuelve VERDADERO (1) si la variable lgica $A es FALSA y devuelve FALSO (NUL) si el valor de esa variable $A es VERDADERO.

Sintaxis alternativa
Tal como hemos descrito los distintos operadores lgicos sera necesario que $A y $B contuvieran valores lgicos, y eso requerira un paso previo para asignarles valores de ese tipo. Habra que recurrir a procesos de este tipo:

$A = $x>$y; $B= $x >=$z; $A && $B;

pero se obtendra el mismo resultado escribiendo: $x>$y && $x >=$z;

que, aparte de ser la forma habitual de hacerlo, nos evita dos lneas de instrucciones. Aunque el propio ejemplo se auto comenta, digamos que al utilizar operadores lgicos se pueden sustituir las variables lgicas por expresiones que den como resultado ese tipo de valores.

Orden de precedencia
Cuando se usan los operadores lgicos se plantean situaciones similares a lo que ocurre con las operaciones aritmticas. Dado que permiten trabajar con secuencias de operaciones sera posible, por ejemplo, una operacin de este tipo: $a<$b OR $c<$b && $a<3

Surgiran preguntas con estas: qu comparacin se hara primero OR &&? se haran las comparaciones en el orden natural? alguno de los operadores tiene prioridad sobre el otro? Igual que en las matemticas, tambin aqu, hay un orden de prioridad que es el siguiente: NOT, &&, ||, AND, XOR y, por ltimo, OR. De esta forma la operacin && se realizara antes que ||, mientras que si pusiramos AND en vez de && sera la operacin || la que se hara antes y, por lo tanto, los resultados podran variar de un caso a otro. Aqu tambin es posible, de la misma manera que en la aritmtica, utilizar parntesis para priorizar una operacin frente a otra. Es muy importante prestar atencin a la construccin correcta de estas estructuras. Un descuido en la atencin a las prioridades puede ser origen lo es frecuentemente de resultados incoherentes que suelen ser detectados bajo una apariencia aleatoria. Ten muy en cuenta que al depurar programas no siempre se ven fcilmente este tipo de errores de programacin. Puede que para determinados valores los resultados sean los esperados y que, sin embargo, al utilizar otros distintos pueda manifestarse la incoherencia. Si te ocurriera esto no pienses que es el ordenador el que est haciendo cosas raras, procura revisar los parntesis y los criterios de prioridad de los distintos operadores contenidos en la estructura lgica.

<?php # asignemos valores a cuatro variables $a=3; $b=6; $c=9; $d=17; # utilicemos operadores de comparacin # y recojamos sus resultados en nuevas variables $x= $a<$b; $y= $a<$b; $z=$c>$b; # apliquemos un operador lgico (por ejemplo &&) # e imprimamos el resultado print("Resultado FALSO si no sale nada: ".($y && $z)."<br>");

# hagamos la misma comparacin sin utilizar la variables $y y $z # que deber darnos el mismo resultado print("<br>Resultado FALSO si no sale nada: ".($a<$b && $c> $b)."<br>"); /* veamos ahora qu ocurre al ampliar la estructura qu ocurrira si escriberamos $a <$b OR $c> $b && $d<$a ? El operador && tiene preferencia ante OR, luego hara primero la comparacin $c>$b && $d<$a 9 > 6 es cierto, 17 < 3 es falso, luego como && solo devuelve cierto cuando ambos sean ciertos el resultado de esa opcin es FALSO. Veamos qu ocurre al comparar $a<$b OR falso (resultado anterior) como 3 < 6 es cierto OR operar con cierto y falso que dar como resultado CIERTO, ya que basta que se cumpla una de las condiciones */ /* vamos a comprobarlo mediante este operador condicional no conocemos aun su sintaxis pero adelntemosla un poco... si el contenido del parntesis que va detrs del if es cierto imprimir cierto y en caso contrario imprimir falso Aqui debera imprimirnos cierto */ if($a <$b OR $c>$b && $d<$a) { print "cierto<br>"; }else{ print "falso<br>"; } # Cambiemos la estructura anterior por $a<$b || $c>$b AND $d<$a # ahora se operar primero || que como antes dar cierto # pero ese resultado operado mediante AND con falso dar FALSO # AL CAMBIAR LOS OPERADORES POR SUS SIMILARES el resultado el DISTINTO if($a<$b || $c>$b AND $d<$a) { print "cierto<br>"; }else{ print "falso<br>"; } # un parntesis nos devolver a la situacin anterior # escribamos $a<$b || ($c>$b AND $d<$a) # veremos que el resultado es CIERTO como ocurra en el primer caso if($a<$b || ($c>$b AND $d<$a)) { print "cierto<br>"; }else{ print "falso<br>"; } ?>
ejemplo40.php

Operadores de incremento Operadores de incremento


Los caracteres ++ y -- escritos al lado del nombre de una variable producen incrementos o decrementos de una unidad en el valor de la misma. De igual forma, los operadores +=n y -=n escritos a la derecha del nombre de una variable producen incrementos o decrementos de nunidades en el valor de la variable.

Como veremos a continuacin, los operadores ++ y -- se comportan de distinta forma segn estn situados a la izquierda o a laderecha de la variable. Estas operaciones slo tienen sentido en variables numricas enteras o no, pero si se aplican a variables de cadena les asignan previamente valor cero, salvo en una curiosa excepcin que puedes ver en la primera de las tablas que tienes aqu a la derecha.

Operadores de pre incremento


++$A y --$A

Este operador incrementa el valor de la variable en una unidad (+1 o -1) antes de ejecutar el contenido de la instruccin. El operador ++$A
Variables numricas Valor inicial Sintaxis $a=23 $a=23 echo ++$a 24 Variables alfanumricas Resultado Valor inicial Sintaxis $b="pepe" echo ++$b Resultado pepf

echo ++$a*2 48

$b="pepe" echo ++$b*2 0

El operador $A
Variables numricas Valor inicial Sintaxis $a=23 $a=23 echo $a 22 Variables alfanumricas Resultado Valor inicial Sintaxis $b="pepe" echo --$b Resultado pepe

echo --$a*2 44

$b="pepe" echo $b*2 0

$A+=n y $A-=n

Este operador incrementa el valor de la variable en n unidades (+n o -n) y luego ejecuta el contenido de la instruccin. El operador $A +=n
Variables numricas Valor inicial Sintaxis $a=23 $a=23 echo $a+=5; echo $a 28 28 Variables alfanumricas Resultado Valor inicial Sintaxis echo $b+=5; $b="pepe" echo $b $b="pepe" Resultado 5 5

echo 2*$a+=5; 56 echo 2*$a 56

echo 2*$b+=5; 10 echo 2*$b 10

El operador $A =n
Variables numricas Valor inicial Sintaxis $a=23 $a=23 echo $a-=5; echo $a 18 18 Variables alfanumricas Resultado Valor inicial Sintaxis echo $b-=5; $b="pepe" echo $b $b="pepe" Resultado -5 -5

echo 2*$a-=5; 36 echo 2*$a 36

echo 2*$b-=5; -10 echo 2*$b -10

Operadores de post incremento


$A++ y $A--

Cuando los operadores ++ o -- estn situados a la derecha de la variable los incrementos no se producen hasta que se ejecute lainstruccin siguiente.

El operador $A++
Valor inicial de la variable Sintaxis $a=23 $a=23 echo $a++; echo $a Resultado 23 24

echo 2*$a++; 46 echo 2*$a 48

El operador $A-Valor inicial de la variable Sintaxis $a=23 $a=23 echo $a--; echo $a Resultado 23 22

echo 2*$a--; 46 echo 2*$a 44

Operadores condicionales Operadores condicionales


Este tipo de operadores son el autntico cerebro de cualquier aplicacin que desarrollemos en PHP o en cualquier otro lenguaje de programacin. Los operadores condicionales son la herramienta que permite tomar decisiones tales como: hacer o no hacer, y tambin:hacer algo bajo determinadas condiciones y otra cosa distinta en caso de que no se cumplan. Aunque para simplificar los ejemplos vamos a utilizar en ellos una sola condicin, este operador permite incluir como tal cualquier estructura lgica, del tipo que hemos visto en la pgina anterior, por compleja que esta sea.

Alternativas de sintaxis
Como iremos viendo a lo largo de estas lneas, este operador permite diferentes formas de sintaxis que podemos utilizar segn nuestra conveniencia. La forma ms simple es: if(condicin) ..instruccin... ;

Si se cumple la condicin establecida en el parntesis se ejecutar la primera instruccin que se incluya a continuacin de ella. Cualquier otra instruccin que hubiera despus de ella no se vera afectada por el condicional ejecutndose en cualquier circunstancia.

<?php # Definamos dos variables y asignmosles valores. # Hubieran podido obteners por cualquier otro procedimiento: # desde un array, # a travs de un formulario cuya action ejecute este script, etc. $A=3; $B="3"; if ($A==$B) print ("A es igual B"); # # # # # cualquier otra instruccin que incluyramos de aqu en adelante se ejecutara independientemente de que la condicin se cumpla o no ya que esta forma de if (sin llaves) nicamente considera la primera instruccin comprobmoslo en este otro supuesto

if ($A<$B) print ("A es menor que B"); print("<br>A no es menor que b, pero esto saldr<br>"); print("Esta es la segunda instruccin. No la condicionar el if"); ?>

ejemplo41.php

if(condicin){ ..instruccin 1... ; ..instruccin 2... ; .... ; }

Es una ampliacin del caso anterior. Cuando es necesario que en caso de que se cumpla la condicin o condiciones se ejecutems de una instruccin, se aade una { para indicar que habr varias instrucciones, se escriben estas y se seala el final mediante }. if(condicin) : ..instruccin 1... ; ..instruccin 2... ; .... ; endif;

Esta otra forma del condicional se comporta como la anterior pero con otra sintaxis. Se sustituye la { de apertura por : y la } de cierre por endif

<?php $A=3; $B="3"; # en este caso cerraremos entre llaves las lneas # que deben ejecutarse si se cumple la condicin if ($A==$B){ print ("A es igual B"); echo "<br>"; echo "Este if tiene varias instrucciones contenidas entre llaves"; } # una sintaxis alternativa a las llaves # sustituyamos la { por : y la } por endif if ($A==$B): print ("A es igual B"); echo "<br>"; echo "Hemos cambiado {} por : endif"; endif; ?>
ejemplo42.php

if(condicion){ ?> ..Etiquetas HTML... ; ..HTML... ; .... ; <? } ?>

PHP permite la utilizacin del operador condicional if con esta sintaxis. Un primer script PHP establece la condicin. Todo lo contenido entre ese primer script y el de cierre: <?}?> ser cdigo HTML (est fuera del script), que se insertar en el documento slo en el caso de que se cumpla la condicin. if(condicion) : ?> ..Etiquetas HTML... ; ..HTML... ; .... ; <? endif; ?>

Idntica a la anterior, con la sintaxis : y endif.

<?php $a=5; # observa que ponemos la etiqueta de fin de script # despus de la llave de apertura if ($a==5){ ?> <!-- Aqu estamos poniendo HTML puro no estamos dentro del script PHP //--> <H1>Esto no ha sido interpretado por PHP</H1> <!-- en la lnea siguiente a este comentario volveremos a PHP para insertar la llave que indica el fin del if //--> <? } ?> <? # hagamos lo mismo cambiando {} por : endif if ($a==5): ?> <!-- Aqu estamos poniendo HTML puro no estamos dentro del script PHP //--> <H2>Esto tampoco sido interpretado por PHP</H2> <!-- en la lnea siguiente a este comentario volveremos a PHP para insertar la llave que indica el fin del if //--> <? endif; ?>
ejemplo43.php

If ... else
El operador condicional tiene una interesante ampliacin. En conjuncin con else permite aadir instrucciones que slo seran ejecutadas en caso de no cumplirse la condicin. Esta nueva opcin se habilita mediante la siguiente sintaxis: if(condicion){ ... instrucciones a ejecutar cuando se cumple la condicin } else { ... instrucciones a ejecutar cuando NO se cumple la condicin }

<?php $A=3; $B="4"; if ($A==$B){ #estas instrucciones se ejecutaran si se cumple la condicin print ("A es igual B"); echo "<br>"; echo "Este if tiene varias intrucciones"; }else{ # estas se ejecutaran en el caso de no cumplirse # las condiciones epecificadas en el fi print("A no es igual que B"); echo "<br>"; echo ("La estructura de control se ha desviado al else"); } ?>
ejemplo44.php

Permite tambin la sintaxis alternativa :, endif, aunque en este caso hay que hacer una precisin -puedes verla aqu debajo la llave de cierre que iba delante de else se elimina y no es sustituida por ningn caracter ni smbolo especial.

<?if(condicion): ?> ... cdigo HTML a incluir cuando se cumple la condicin <? else: ?> ... codigo HTML a incluir cuando NO se cumple la condicin <? endif; ?>

<?php $a=3; # observa que ponemos la etiqueta de fin de script # despus de los dos puntos if ($a==5): ?> <!-- Aqu estamos poniendo HTML puro no estamos dentro del script PHP //--> <H1>Esto no es PHP. A es igual 5</H1> <!-- en la lnea siguiente a este comentario volveremos a PHP para insertar el else seguido de dos puntos y cerramos de nuevo el script con ?>//--> <? else: ?> <!-- Aqu ms HTML para el (else) caso de que no se cumpla la condicin //--> <H2>Esto no es PHP. Es el resultado del ELSE</H2> <!-volveremos a PHP para insertar en endif que indica el fin del if //--> <? endif; ?>
ejemplo45.php

En algunos casos resulta til y cmodo el uso de esta otra posibilidad de sintaxis conocida como operador condicional ternario (condicin) ? (opcion1) : (opcion2)

Si se cumple la condicin se ejecuta la opcion1. En el caso de que no se cumpla se ejecutar la opcion2.

<?php $a=5; ($a==8) ? ($B="El valor de a es 8"): ($B="El valor de a no es 8"); echo $B; ?>
Ejemplo con a=8 Ejemplo con a=5

If ... elseif .. else


Otra posibilidad dentro de la estructura de los operadores condicionales es la inclusin de elseif. Esta es la sintaxis. Dentro del ejemplo tienes los comentarios explicativos. if(condicion1){ ... instrucciones a ejecutar cuando se cumple la condicin1 }elseif(condicion2){ ... instrucciones a ejecutar cuando se cumple la condicin2 sin cumplirse condicin1 } else { ... instrucciones a ejecutar cuando NO se cumple ni la condicin1 ni la condicion2 }

<?php $a=1; if ($a==1){ echo "El valor de la variable A es 1"; }elseif ($a==2){ echo "El valor de la variable A es 2"; }elseif ($a==3){ echo "El valor de la variable A es 3"; }else{ echo "La variable A no es 1, ni 2, ni 3"; } ?>
Ejemplo con a=3 Ejemplo con a=-7

<?php $a=1; if ($a==1): ?> <H1>A es igual a 1</H1> <? elseif($a==2): ?> <H1>A es igual a 2</H1> <? elseif($a==3): ?> <H1>A es igual a 3</H1> <? else: ?> <H1>A no es igual ni a 1, ni a 2, ni a 3</H1> <? endif; ?>
Ejemplo con a=2 Ejemplo con a=8

Condicionales anidados
El anidado no es otra cosa que el equivalente a los parntesis dentro de parntesis en las matemticas. Y este operador lo permite, con una nica condicin, que vers en esta muestra de sintaxis. if(condicin1){ ... instrucciones para le caso de que se cumpla la condicin1.... if(condicin2){ ... instrucciones cuando se cumple la condicion1 y la condicion2... } else { ...instrucciones cuando se cumple la condicion 1 y no se cumple la condicion 2 } }else{ ... instrucciones para el caso de que no se cumpla la condicion 1 }

Observa que todo el bloque if.. else... marcado en azul se cierra antes de abrir la opcin else marcada en marrn. Es obligatorio que as sea. De igual forma, podramos insertar bloques sucesivos hasta llegar a crear una estructura tan amplia como fuera necesaria. Como ves, todo un mundo de posibilidades.

La funcin exit()
PHP dispone de una funcin exit() muy til a los efectos del comentario anterior. Cuando se ejecuta exit() se interrumpe la ejecucin del script con lo que la respuesta del servidor a la peticin del cliente incluir nicamente los contenidos generados antes de su ejecucin.

La funcin switch La funcin switch


Una alternativa al uso de condicionales del tipo if es la funcin switch. Se trata de un condicional que evala una variable y, segn su valor, ejecuta unas instrucciones u otras. Su sintaxis es la siguiente: switch ( variable ) { case n1: ...instrucciones a ejecutar en el caso de que la variable sea igual a n1... case n2: ..instrucciones a ejecutar en el caso de que la variable sea igual a n2... } Cuando se usa esta sintaxis se ejecutan todas aquellas instrucciones que han sido incluidas a partir de la etiqueta en la que el valor que sigue a case coincide con el valor de la variable. Es decir, si en la expresin anterior la variable es igual a n1 se ejecutaran todas las instrucciones, tanto las que van detrs de case n1 como las que van detrs de case n2. La forma ms habitual de uso de esta funcin es esta: switch ( variable ) { case n1: ...instrucciones a ejecutar en el caso de que la variable sea igual a n1... break; case n2: ..instrucciones a ejecutar en el caso de que la variable sea igual a n2... break; }

Esta opcin incluye antes de cada nuevo case la funcin de ruptura break. Cuando PHP encuentra el break interrumpe la ejecucin yno la reanuda hasta la instruccin siguiente a la } que cierra el switch. Insertando break en cada una de las opciones case, slo se ejecutaran las instrucciones contenidas entre case num y ese break. default:

Bajo este nombre (default:) se pueden incluir dentro de la funcin switch un conjunto de instrucciones que solo sern ejecutadas en el caso de que el valor de la variable no coincida con ninguno de los case. Su comportamiento es equivalente a else en el condicional if.

Ejemplos con switch


<?php # esta es la variable que controlar la funcin switch $i=1; switch ($i) { #insertamos la etiqueta case 0 y a continuacin # las instrucciones correspondientes case 0: print "i es igual a 0 - No he puesto el break<br>"; # # # # # insertamos la etiqueta case 1 y a continuacin las instrucciones correspondientes como no hemos puesto break y en este ejemplo $i=1 se ejecutarn todas las instrucciones escritas de aqu en adelante

case 1: print "i es igual a 1 - No he puesto el break<br>"; case 2: print "i es igual a 2 - No he puesto el break<br>"; }; # ahora incluiremos break al final de las intrucciones de cada case # con ello lograremos que solo se ejecuten las intrucciones correspondientes # a cada uno de ellos switch ($i) { case 0: print "i es igual a 0 - Ahora lleva break<br>"; break; case 1: print "i es igual a 1 - Ahora lleva break<br>"; break; case 2: print "i es igual a 2 - Ahora lleva break<br>"; break; } ?>
ejemplo53.php

<?php $i=3; switch ($i) { case 0: print "La variable i es 0<br>"; break; case 1: print "La variable i es 1<br>"; break; case 2: print "La variable i es 2<br>"; break; # al intoducir default y dado que $i=3 se ejecutarn # las instrucciones contenidas aqu ya que la variable # no coincide con ninguno de los case establecidos default: print "La variable i es mayor que dos o menor que cero"; break; } ?>
ejemplo54.php

Bucles while Los bucles


La necesidad de repetir la ejecucin de instrucciones es algo habitual en el mundo de la programacin. Frente a la alternativa poco prctica de reescribir las instrucciones todos los lenguajes de programacin disponen de funciones que pueden ejecutar un bloque de instrucciones de forma repetitiva.

La instruccin while
Como ocurra en el caso de if, el parmetro condicin permite cualquier estructura lgica, y tambin dispone de distintas opciones de sintaxis.

while(condicin) ...instruccin que se ejecutar mientras se cumpla la condicin

Con esta sintaxis estaremos indicando que la instruccin siguiente (slo una instruccin) ha de ejecutarse continua y repetidamente hasta que deje de cumplirse la condicin establecida.

<?php # asignemos un valor a la variable $A $A=0; /* establezcamos la condicin menor que cinco e insertemos dentro de la instruccin algo que modifique el valor de esa variable de modo que en algn momento deje de cumplirse la condicin; de no ocurrir esto, el bucle se repetira indefinidamente en este ejemplo el autoincremento ++ de la variable har que vaya modificndose su valor*/ while ($A<5) echo "El valor de A es: ",$A++,"<br>"; # comprobemos que este while solo ejecuta una instruccin # la delimitada por el punto y coma anterior print("Esto solo aparecer una vez. While no lo incluye en su bucle"); ?>
ejemplo55.php

while(condicin) { ...instruccin que se ejecutar mientras se cumpla la condicin... ....otra ...instruccin que se ejecutar mientras se cumpla la condicin... .......... }

De forma similar a la utilizada en el caso de if, tambin en este caso, las llaves hacen la funcin de contenedores de las instrucciones cuya ejecucin debe repetirse mientras se cumpla la condicin.

<?php $A=0; /* utilicemos ahora el bucle para crear un tabla HTML empecemos escribiendo la etiqueta de apertura de esa tabla fuera del bucle (ya que esa se repite una sola vez) y utilicemos el bucle para escribir las celdas y sus contenidos */ print ("<table width=300 border=2>"); while ($A<=5){ echo "<tr><td align=center>"; print $A; # esta instruccin es importantsima # si no modificamos el valor de $A el bucle sera infinito $A++; print("</td></tr>"); } # cerremos la etiqueta table print "</table>"; ?>
ejemplo56.php

while(condicin) : ...instruccin que se ejecutar mientras se cumpla la condicin... ....otra ...instruccin que se ejecutar mientras se cumpla la condicin... ..........

endwhile;

Tambin aqu se mantiene la similitud con la sintaxis del condicional if. La llave ({) pueden sustituirse por (:) y en este caso en vez de (}) habra que escribir endwhile.

<?php # utilicemos whiles anidados para construir una tabla de $filas=5; $columnas=3; # insertemos la etiqueta de apertura de la tabla print ("<table border=2 width=400 align=center>"); # un primer while rojo que utiliza la condicin filas mayor que cero # en este caso, la variable tendr que ir disminuyendo su valor con $filas-# para escribir las etiquetas <tr> y </tr> # y el modificador de la variable filas # y un segundo while (magenta) para insertar las etiquetas correspondientes # a las celdas de cada fila while ($filas>0): echo "<tr>"; $filas--; while ($columnas>0): echo "<td>"; print "fila: ".$filas." columna: ".$columnas; print ("</td>"); $columnas--; endwhile; /* muy importante!. Tendremos que reasignar a la variable columnas su valor inicial para que pueda ser utilizado en la prxima fila ya que el bucle (magenta) va reduciendo ese valor a cero y en caso de no restaurar el viejo valor no volvera a ejecutarse ya que no cumple la condicin de ser mayor que cero */ $columnas=3; echo "</TR>"; endwhile; # por ultimo la etiqueta de cierre de la tabla print "</table>"; ?>
ejemplo57.php

Incluimos a continuacin un nuevo ejemplo en el hemos hecho una ligera modificacin del anterior incluyendo un condicional if. No incluimos aqu el cdigo fuente para evitarte la monotona de repetir ntegramente y con ligeras modificaciones el supuesto anterior. Utilizaremos un nuevo recurso de visualizacin tal como puedes comprobar si pulsas en el enlace Ver cdigo fuente. Esta opcin utiliza la funcin show_source('pagina');

que permite visualizar el cdigo fuente del documento que se indica en el parmetro 'pagina'. Es muy til para nuestros propsitos pero presenta un problema de seguridad. Si escribes en el parmetro pag la direccin completa de una web cualquiera (que tenga extensin php) se visualizar su contenido, salvo que el PHP instalado en el servidor que la aloja la tenga expresamente desactivada. Recuerda que en HTML se puede asignar el color fondo a una celda incluyendo bgcolor=RGB(x,y,z) siendo x, y ,z los valores de las componentes de cada color primario dentro de la etiqueta <TD>.
Ver nuevo ejemplo Ver cdigo fuente

while(condicin) : ?> ...etiquetas HTML que se insertaran repetidamente mientras se cumpla la condicin

..... <? endwhile; ?>

Tambin while permite cerrar el script PHP despus de (:) o de la sintaxis alternativa ({) e insertar etiquetas HTML, indicando ms tarde el final del bucle con <? } ?> o <? endwhile; ?>, segn proceda.

Whiles anidados
Una nueva similitud sintctica con if. En el caso de while tambin es posible insertar un while dentro de otro while utilizando una sintaxis de este tipo: while(condicin1): ...instruccin while(condicin2) { ...instruccin ..... } ..... endwhile;

En esta descripcin hemos utilizado dos sintaxis distintas. Por si acaso dudaras de si es necesario o no hacerlo de esa forma, te diremos que no es necesario nunca. El hecho de la anidacin no limita un pice las posibilidades de la sintaxis.

Bucles do ... while El bucle do... while


Estamos ante una variante del bucle while que hemos visto en la pgina anterior. La sintaxis es la siguiente: do { .... instruccin 1... .... instruccion2... } while(condicin) ;

Se diferencia de while en que en este caso se comprueba la condicin despus de haber ejecutado las instrucciones contenidas en el bucle, con lo cual, en el caso de que desde el comienzo no se cumplieran las condiciones establecidas en while las instrucciones del bucle se ejecutaran una vez. Respecto a la sintaxis, como puedes observar, detrs de do se inserta una llave ({) que seala el comienzo de las instrucciones pertenecientes al bucle. El final de esas instrucciones lo seala la otra llave (}) que precede a while(condicin). break

La funcin break de forma similar a lo que ocurra en el caso de switch permite interrumpir la ejecucin de bucle. Tal como puede verse en el ejemplo, podra entre otras posibilidades utilizarse para evitar la primera ejecucin de las instrucciones contenidas en el bucle, en el caso de que, desde un primer momento, no se cumplieran las condiciones establecidas en while. No lo hemos comentado en la pgina anterior pero break se comporta en el caso de while de forma idntica a la descrita aqu.

<?php $A=0; do { ++$A; echo "Valores de A usando el do: ",$A,"<br>";

} while($A<5); $B=7; do { echo "Pese a que B es mayor que 5 se ejecuta una vez. B= ",$B,"<br>"; } while($B<5); ?>
ejemplo59.php

<?php $A=500; do { if ($A>=500) { echo "No puede ejecutarse el bucle, porque no se cumple la condicion"; break; } ++$A; echo "Valores de A usando el do: ",$A,"<br>"; } while($A<500); echo "<BR>He salido del bucle porque A es: ",$A; ?>
ejemplo60.php

El ejemplo que tienes aqu debajo es similar al ejemplo n. 57 de la pgina anterior. Slo hemos sustituido los bucles while que all habamos utilizado por otros del tipo do ... while.
ejemplo61.php Ver cdigo fuente

Bucles for El bucle for


Se trata de una nueva forma de uso bastante habitual que permite establecer un bucle que se repetir mientras una variable numrica se mantenga dentro de intervalo especificado en la sintaxis del propio bucle indicndose tambin en la propia instruccin el criterio de modificacin de esa variable en cada ejecucin del bucle. La sintaxis es la siguiente: for ( desde ; hasta ; incremento ){ ......... ...instrucciones.... ......... }

El parmetro desde permite asignar un valor inicial a una variable ($var=num) que har funciones de controladora de iteraciones. El parmetro hasta establece la condicin que limita el valor mximo que puede alcanzar la variable de control y el parmetro incremento (con una sintaxis del tipo $variable++; $variable--; ++$variable; --$variable; $variable +=n o $variable =n establece los incrementos odecrementos de la variable controladora en cada iteracin del bucle. Las instrucciones contenidas entre { } sern ejecutadas cada vez que se reitere el bucle.

<?php for ($i = 1; $i <= 10; $i++) { print $i."<br>"; }

?>
ejemplo62.php

Variantes del bucle for


El bucle for permite algunas variantes respecto a su forma ms general. Son estas: for ( desde ; ; incremento ){ ......... ...instrucciones.... ......... }

En este caso se omite el valor del parmetro hasta (observa que no se omite el separador de parmetros (;) con lo que en realidad se est asignando a hasta el valor NUL. Cuando se utiliza esta sintaxis, el bucle se repetira de forma indefinida (la variable podra tomar cero como valor, pero cero es distinto de NUL) salvo que -tal como puedes ver en el ejemplo- se escriba en las instrucciones un operador condicional con una opcin de ruptura del bucle -el famoso break que ya hemos visto al estudiar la instruccin while y otras anteriores.

<?php for ($i = 1;;$i++) { if ($i > 10) { break; } print $i."<br>"; } ?>
ejemplo63.php

for ( ; ; ){ ......... ...instrucciones.... ......... }

En este caso no se inserta ningn parmetro pero si se escriben los ; delimitadores de los mismos. Si observas el ejemplo vers que el control se realiza fuera del for. El valor de la variable contador se asigna fuera del bucle, los incrementos de esa variable estn escritos en las lneas de instrucciones y llevan un operador condicional con la funcin break para permitir la salida.

<?php $i = 1; for (;;) { if ($i > 10) { break; } print $i."<br>"; $i++; } ?>
ejemplo64.php

for( desde ; hasta ; instrucciones, incremento )

Esta nueva variante de for permite insertar instrucciones a travs del tercer parmetro de la funcin. Si insertamos como tercer parmetro un conjunto de instrucciones, separadas por comas, se ejecutarn de igual forma que si estuvieran contenidas entre { y } En este caso, el modificador de la variable de control (incremento) se incluye como una instruccin ms separada por una coma de las contenidas en ese tercer parmetro de la funcin.

<?php for ($i = 1; $i <= 10; print $i."<br>", $i++) ; ?>


ejemplo65.php

for ( desde ; hasta ; incremento ): ......... ...instrucciones.... ......... endfor;

Esta sintaxis es alternativa a la primera de las descritas. Sustituye la { por dos puntos (:) y la } por endfor.

<?php for($i = 1; $i <=10;$i++) : echo $i,"<br>"; endfor; ?>


ejemplo66.php

<?php for ($i = 1; $i <= 10;$i++):?> <H1>Esto se repetir 10 veces</H1> <? endfor; ?>
ejemplo67.php

Como puedes observar en este ltimo ejemplo tambin es aplicable aqu la sintaxis de los dos sripts PHP. El primero contiene las instrucciones del bucle y el segundo seala el final del mismo. Entre ambos scripts se escribe el cdigo HTML

Cuidado! A la hora de programar bucles hay que evitar el riesgo de convertirlo en un bucle indefinido. Cuando esto ocurre el error es humano al abrir la pgina que lo contiene parecer que nuestro navegador se ha quedado colgado aunque en realidad estar esperando a que sea atendida la peticin. Si llega a plantersete ese problema, tendrs que recurrir a la socorrida solucin de pulsar ALT+CTRL+DEL para abortar la peticin del navegador.

Bucles foreach El bucle foreach


El bucle foreach es especfico de los array y aplicable a ellos tanto si son escalares como si su tipo es asociativo. Tiene dos opciones uso. Mediante una de ellas lee nicamente los valores de los elementos del array. La segunda opcin permite leer el ndice y el valor de cada elemento.

Lectura de valores
Utilizando la sintaxis:

foreach ( array as $valor ) { ...instrucciones... }

donde array es el nombre del array (sin incluir ndices ni corchetes), as es una palabra obligatoria y $valor el nombre de una variable (puede ser creada al escribir la instruccin ya que no requiere estar previamente definida) que ir recogiendo los valores de los sucesivoe elementos del array. Las instrucciones escritas entre las { } permiten el tratamiento o visualizacin de los valores obtenidos. La variable $valor no podr ser utilizada para guardar valores. Hemos de tener en cuenta que su valor se rescribe en cada iteracin del bucle y que al acabar este slo contendr el ltimo de los valores ledos.

<?php /* definimos un array escalar utilizando la sintaxis nombre del array=array (valores de los elemento separados por comas) si los valores son nmeros no es necesario encerrarlos entre comillas */ $a=array("a","b","c","d","e"); /* definamos ahora un nuevo array, esta vez asociativo utilizando la sintaxis clave => valor tal como puedes ver */ $b=array( "uno" =>"Primer valor", "dos" =>"Segundo valor", "tres" =>"Tecer valor", ); # establecemos el bucle que leer el array $a # recogiendo en la variable $pepe los valores extrados # y escribimos los valores foreach($a as $pepe) { echo $pepe,"<br>"; }; # repetimos el mismo proceso, ahora con $b que es un array asociativo foreach($b as $pepe) { echo $pepe,"<br>"; }; ?>
ejemplo68.php

Lectura de ndices y valores


Con una sintaxis como la que sigue se pueden leer no slo los valores de un array sino tambin sus ndices. foreach ( array as $indices => $valores ) { ...instrucciones... }

donde array es el nombre de la matriz, as es una palabra obligatoria, $indices es el nombre de la variable que recogern los ndices, los caracteres => (son obligatorios) son el separador entre ambas variables y, por ltimo, $valores es el nombre de la variable que recoge el valor de cada uno de los elementos del array. Tanto esta funcin como la anterior realizan una lectura secuencial que comienza en el primer valor del array.

<?php $a=array("a","b","c","d","e"); $b=array( "uno" =>"Primer valor", "dos" =>"Segundo valor", "tres" =>"Tecer valor", );

# # # #

en este caso extraeremos ndices y valores de ambos arrays usaremos $pepe para recoger los ndices y $pepe para recoger los valores y separaremos ambas variables por => que es el separador obligatorio para estos casos Valor: ",$pepa,"<br>"; Valor: ",$pepa,"<br>";

foreach($a as $pepe=>$pepa) { echo "Indice: ",$pepe," }; foreach($b as $pepe=>$pepa) { echo "Indice: ",$pepe," }; ?>
ejemplo69.php

Arrays bidimensionales
Cuando se trata de arrays bidimensionales la lectura de los valores que contienen sus elementos requiere el uso de dos buclesanidados. Cuando un array de este tipo es sometido al bucle foreach se extrae como ndice el primero de los indices y como valor un array unidimensional que tiene como ndice el segundo de los del array original y como valor el de aquel. La lectura de los valores de cada elemento requiere utilizar un segundo bucle que extraiga la informacin del array unidimensional obtenido como valor en la primera lectura. La sintaxis sera de este tipo: foreach ($array as $indice1=>$nuevo_array) { foreach($nuevo_array as $indice2 => $valor) { .... $indice1 es el primer ndice.... .... $indice2 es el segundo ndice.... .... $nuevo_array nuevo array ..... $valor es el valor .... } }

En el caso de arrays con dimensiones superiores sera necesario proceder del mismo modo, y habra que utilizar tantos buclesforeach como ndices contuviera el array.

<?php # definamos un array bidimensional $z=array( 0 => array ( 0 => 34, 1 => 35, 2 => 36, ), 1 => array ( 0 => 134, 1 => 135, 2 => 136, ) ); # intentemos leer ndices y valores mediante un bucle foreach # y veamos como los valores que extraemos son Arrays (unidimensionales) # consecuencia del caracter bidimensional del array original

foreach($z as $pepe=>$pepa) { echo "Indice: ",$pepe," Valor: ",$pepa,"<br>"; }; /* anidemos dos bucles foreach de la siguiente forma en el primero extraemos un array que es tratado por el segundo foreach para extraer el segundo ndice y el valor realmente contenido en ese elemento bidimensional */ foreach($z as $ind1=>$valor1) { foreach($valor1 as $ind2=>$valorReal) { echo "Ind. 1: ",$ind1,"Ind. 2: ",$ind2," Valor: ",$valorReal,"<br>"; }; }; ?>
ejemplo70.php

La instruccin continue La instruccin continue


Si la instruccin break permite interrumpir el desarrollo de un bucle, mediante continue se puede impedir que, bajo unas condiciones determinadas, se ejecuten algunas o todas las instrucciones de un bucle sin que por ello se interrumpa la ejecucin de las iteraciones siguientes. Esta instruccin es aplicable tanto a bucles for como a los de tipo while o do while. Seguramente los ejemplos nos ayudarn a aclarar un poco ms la idea. En este primer ejemplo (un bucle for) tiene comocondicin(if): $i % 2 == 0 que, como recordars, significa que el resto de la divisin de $i entre dos($i % 2) sea igual (==) a cero. En este supuesto (condicin de mltiplo de dos) se activar la opcin continue y por lo tanto en esa iteracin no se ejecuta la instruccin echo y en consecuencia no se imprimirn en pantalla los mltiplos de 2.

<?php for ($i=0;$i<=10;$i++){ #condicin de mltiplo de 2 if ($i % 2 ==0 ) { continue ; } echo "La variable I vale ",$i,"<br>"; } ?>
ejemplo71.php

Este otro ejemplo (caso de bucle while) la condicin establecida para que se ejecute continue es que el valor de la variable no sea mltiplo de tres, en cuyo caso echo slo imprimir los mltiplos de 3.

<?php $i = 0; while ($i++ < 14) { #condicin de no mltiplo de 3 usando para distinto la sintaxis != if ($i % 3 !=0){ continue ; }

echo "El valor de i es: ",$i,"<br>"; } ?>


ejemplo72.php

En este nuevo ejemplo utilzaremos un bucle do ... while para presentar en pantalla los mltiplos de 11.

<?php $i = 0; do { # condicin de no mltiplo de 11. fjate en la sintaxis alternativa # observa que aqu distinto lo hemos escrito <> if ($i % 11 <>0 ){ continue ; } echo "El valor de i es: ",$i,"<br>"; }while ($i++ < 100) ?>
ejemplo73.php

La instruccin continue n
La instruccin continue puede utilizar un parmetro n con valor entero positivo que, cuando no se indica de forma expresa, toma por defecto el valor 1. La idea es la siguiente. Cuando tenemos bucles anidados el intrprete de PHP los considera numerados correlativamentede dentro hacia fuera a partir de UNO. Cuando se ejecuta continue n se redirecciona la iteracin al bucle cuyo nmero coincide con el valor de n. Obviamente, el valor de nno puede ser nunca mayor que el nmero de bucles anidados en el script. Analicemos algunos ejemplos. En este caso el bucle for sera el nmero UNO y el while sera el nmero DOS. Cuando se cumpla la condicin que activa continue 2 ($i=3) se redirecciona la iteracin al paso siguiente de while (bucle nmero DOS).

<?php $j=0; while (++$j <5) { for($i=1;$i<5;$i++){ if ($i==3){ continue 2; } echo "El valor de j es: ",$j, " y el de i es: ",$i,"<br>"; } } ?>
Caso continue 1 Caso continue 2

En este otro ejemplo hemos anidado a tres niveles y hemos escrito continue 3, aunque a la hora de ejecutar los ejemplos podrs ver las tres variantes posibles de ese script modificando los valores de continue n.

<?php $j=0;$k=0; do { //n=3 while (++$j <=5) { // n=2 for($i=1;$i<=5;$i++){ // n=1 if ($i==2){continue 3;} echo "El valor de k es: ",$k," y el valor de j es: ",$j, " y el de i es: ",$i,"<br>"; } } }while ($k++ <=5); ?>
Caso continue 1 Caso continue 2 Caso continue 3

Expresiones regulares Bsqueda y reemplazamiento de textos


PHP dispone de varias opciones para realizar tareas de bsqueda y reemplazamiento de textos. La ms antigua, POSIX (PortableOperating System Interface uniX), se anuncia como deprecated a partir de PHP 5.3. Por esa razn centraremos nuestro anlisis en la llamadaPCRE (Perl Compatible Regular Expressions) que parece ser la opcin con ms futuro. Una expresin regular o patrn de bsqueda, es una forma de describir un conjunto de cadenas de carcteres sin enumerar sus elementos. En el caso de las expresiones regulares compatibles con Perl (PCRE) hemos de empezar diciendo que han tener sealado su comienzo y su final por dos caracteres idnticos llamados delimitadores pudiendo realizar esa funcin cualquier carcter no alfanumrico. Expresiones tales como: #tomate#, *tomate* o /tomate/ seran patrones vlidos, delimitados por #, * o /, para la bsqueda de la palabra tomate. Empezaremos considerando el caso de que una coincidencia requiera encontrar una identidad plena con el patrn. Ms adelante incidiremos sobre el tema de los patrones de bsqueda y el manejo de su amplsimo abanico de opciones. Aunque lo trataremos con detalle un poco ms adelante vamos a empezar a manejar el modificador i. Cuando este carcter es aadido detrs del ltimo delimitador modifica el patrn de bsqueda para considerar las coincidencias sin hacer distincin entre maysculas y minsculas. Si no se incluyera i la bsqueda atendera al criterio de que mayscula y minscula son caracteres diferentes.

El reemplazamiento
Para poder ilustrar de forma grfica las caractersticas de los diferentes patrones de bsqueda empezaremos por conocer el manejo de la funcin: preg_replace ( patron, sustituta, cadena, limite_coincidencias, $contador ) dnde patron es el patrn de bsqueda, sustituta la cadena que va a sustituir las coincidencias, cadena la cadena en la que pretendemos realizar la bsqueda y sustitucin, limite_coincidencias el nmero mximo de coincidencias a las que aplicaremos el reemplazamiento y $contador ser el nombre de una variable que puede utilizarse como contador del nmero de cambios efectuados.

<?php /* definimos la cadena en la que pretendemos realizar la bsqueda y sustitucin */ $original = <<<Cadena Esta es la cadena que utilizaremos como original. Sobre ella efectuaremos algunos cambios utilizando EXPRESIONES REGULARES

Cadena; /*establecemos lo que queremos buscar*/ $buscar="es"; /*establecemos lo que queremos sustituya a lo anterior que ser marcar en rojo con fondo amarillo los mismos caracteres*/ $sustituto="<span style='color:red;background-color:yellow'>es</span>"; /*elegimos un delimitador para el patrn de bsqueda ( / ) */ $delimitador="/"; /* establecemos el modificador i para buscar sin diferencias maysculas de minsculas */ $modificador="i"; /* recogemos en la variable $patron la expresin regular formada por el delimitador inicial, la cadena a buscar, el delimitador final y, en este caso, el modificador i */ $patron=$delimitador.$buscar.$delimitador.$modificador; print "<br />Mediante el patrn de bsqueda: <b><i>".$patron."</i></b>"; print " buscaremos <b><i>".$buscar."</i></b> en la cadena:<br />"; print "<i>".$original."</i><br>"; print " reemplazando <b><i>".$buscar."</i></b> por "; print "<b><i>".$sustituto."</i></b><br />"; print " Este es el resultado: <b><br />"; print preg_replace ($patron,$sustituto,$original); print "</b><br /><br />"; print "Agregemos una restriccin en cuanto a coincidencias (1)<br /><b>"; print preg_replace ($patron,$sustituto,$original,1); print "</b><br /><br />Incluyamos un contador de coincidencias <br><b>"; print preg_replace ($patron,$sustituto,$original,-1,$z); print "</b><br /><br />Hemos realizado ".$z." cambios"; /* cambiemos el modificador para que sea sensible a maysculas/minusculas */ $modificador=""; /* actualicemos la variable patrn con el ltimo cambio */ $patron=$delimitador.$buscar.$delimitador.$modificador; print "<br /><b>Bsqueda sensible a maysculas/minsculas</b><br>"; print "<br />Mediante el patrn de bsqueda: <b><i>".$patron."</i></b>"; print " buscaremos <b><i>".$buscar."</i></b> en la cadena:"; print "<i>".$original."</i><br>"; print " reemplazando <b><i>".$buscar."</i></b> por "; print "<b><i>".$sustituto."</i></b>"; print " Este es el resultado: <b>"; print preg_replace ($patron,$sustituto,$original); print "</b><br /><br />"; print "Agregemos una restriccin en cuanto a coincidencias (1)<br /><b>"; print preg_replace ($patron,$sustituto,$original,1); print "</b><br /><br />Incluyamos un contador de coincidencias <br><b>"; print preg_replace ($patron,$sustituto,$original,-1,$z); print "</b><br /><br />Hemos realizado ".$z." cambios"; ?>
ejemplo79.php

Si se omiten los parmetros limite_coincidencias y $contador se reemplazarn todos los valores posibles sin recoger en ninguna variable el nmero de cambios. En el caso de que queramos indicar de forma explcita que se efecten todos los cambios posibles asignaremos al cuarto parmetro (limite_coincidencias) el valor -1. El parmetro patron puede ser un array en el que cada elemento ser un patrn de bsqueda. Cuando se da esa circunstancia ysustituta es una cadena, las coincidencias de cada uno de los diferentes patrones son reemplazadas por la cadena sustituta. En el caso de que sustituta fuera un array, las coincidencias del patron contenido en cada elemento de array sern reemplazadas por el valor del elemento de sustituta de igual ndice tal como puede verse en los ejemplos de la tabla que incluimos a

continuacin. Hemos utilizado en todos los casos el modificador i razn por la cual las bsquedas sern insensibles a maysculas y minsculas.
Cdigo Ver fuente ejemplo Ver Ver Ver Probar Probar Probar

Funcin preg_replace($patron, $sustituto, $original) preg_replace($patron, $sustituto, $original,n) $contador=0; preg_replace($patron, $sustituto, $original, -1, $contador) $patron=array('/xxx/','/yyy/'); preg_replace($patron, $sustituto, $original) $patron=array('/xxx/','/yyy/'); preg_replace($patron, $sustituto, $original,n) $contador=0; $patron=array('/xxx/','/yyy/'); preg_replace($patron, $sustituto, $original,n,$contador) $contador=0; $patron=array('/xxx/','/yyy/'); $sustituto=array('/zzz/','/ppp/');preg_replace($patron, $sustituto, $original) $contador=0; $patron=array('/xxx/','/yyy/'); $sustituto=array('/zzz/','/ppp/');preg_replace($patron, $sustituto, $original) $contador=0; $patron=array('/xxx/','/yyy/'); $sustituto=array('/zzz/','/ppp/');preg_replace($patron, $sustituto, $original)

Descripcin Devuelve una cadena sistituyendo, sin lmite de coincidencias, el contenido del patrn por la cadena de reemplazamiento Devuelve una cadena sistituyendo el contenido. El cuarto parmetro (n) establece que solo se reemplazarn las n primeras coincidencias Devuelve una cadena sistituyendo el contenido. El cuarto parmetro (-1) establece que se reemplazarn todas las coincidencias. La variable contador, incluida como quinto parmetro recoge el nmero de ocurrencias Cuando el patrn es un array (cada elemento ha de incluir los delimitadores) se sustituye cada coincidencia con cualquiera de los elementos del array por la cadena de reemplazamiento En el caso de un patrn en forma de array el lmite de coincidencias trata individualmente cada elemento del array Si se incluye el parmetro contador se cuantificarn todos los cambios realizados. Aqu utilizaremos dos arrays. Uno para establecer los patrones y otro para establecer los reemplazamientos asociados con aquellos

Ver Ver Ver

Probar Probar Probar

Ver

Probar

Cuando el patron es un array de mayor longitud que el sustituto las sustituciones Ver no definidas sern consideradas como cadenas vacas

Probar

Cuando el patron es un array de menor longitud que el sustituto los elementos sobrantes de este no producirn ningn efecto

Ver

Probar

Patrones de bsqueda
La autntica potencia de las expresiones regulares radica en el enorme abanico de opciones bsqueda que se pueden configurar utilizando: metacaracteres, indicadores de codicia, secuencias de escape, anclas, indicadores de alternancia, agrupadores, subpatrones y los diferentes tipos de modificadores. Veamos la utilidad de cada una de estas herramientas.

Metacaracteres
Llamaremos metacaracteres a un conjunto de carcteres que tienen un significado especial cuando se incluyen en una expresin regular. A ttulo puramente enumerativo, forman parte de ese conjunto los siguientes: ., +, *, {, }, [, ], -, \, ^, $, |, (, ) y ?. Veamos sus significados: . Cuando incluimos un punto como metacaracter en un patrn de bsqueda estamos indicado que se admite cualquier carcter en la posicin que ocupa el punto. Es decir, el patrn p. considerara coincidencia tanto pa, como pz, como p3. + Cuando un patrn incluye un signo ms se est especificando que el carcter que le precede puede repetirse una o ms veces. Es decir pa+ considerara coincidencias a: pa, paa, paaa y tambin a paaaaaaa. * Este metacaracter es ligeramente diferente al anterior. Tambin permite repeticiones pero no obliga a que aparezca el carcter que le precede. Es decir, el patrn pa* considerara coincidencias a: pa, paa, paaa y tambin p3 y pz que no incluyen ninguna a detrs de la p.

{m,n} Cuando se incluyen esta expresin (en la que m y n son dos nmeros naturales) a continuacin de un caracter cualquiera se especifica que se considerar coincidencia cualquier cadena que contenga ese carcter repetido un nmero veces comprendido entre m y n ambos inclusive. Quiere decir que pa{3,5} considerar coincidencias a paaa, paaaa y paaaaa pero no considerar tal coincidencia en el caso de paa o de paaaaaa. Existen casos particulares. Cuando se incluye {m} se est estableciendo que solo se considerar coincidencia cuando el caracter se repita exactamente m veces. Si se especifica {m,} (se incluye la coma pero falta el segundo valor) estaremos indicando que seconsiderar coincidencia cuando el carcter se repita m o ms veces. [] Mediante los corchetes se pueden incluir rangos de caracteres en el patrn de bsqueda. Si se especifican letras o nmeros sin ningn separador se considerar coincidencia cualquiera de ellos. Si se separan por medio de un guin dos nmeros o dos letras se considerar coincidencia cualquiera del rango delimitado por ellos. Puedes verlo en los ejemplos. ^ Cuando este smbolo (acento circunflejo) se incluye como primer carcter dentro de un corchete ser interpretado como negacin, es decir, no se considerar coincidencia la expresin que le preceda.
Patrn de bsqueda Cdigo fuente Ver Ver Ver Ver Ver Ver Ver ejemplo Probar Probar Probar Probar Probar Probar Probar Probar Probar Probar Probar Probar Probar

Descripcin Escribe una "o" marcada con colores sustituyendo a cada "o" de la cadena original sin diferenciar maysculas de minsculas. Es idntico al caso del los ejemplos anteriores Considerar coincidencias todas las d junto su carcter siguiente sea cual fuere (el punto indica que puede ser un carcter cualquiera). Cada coincidencia la reemplazar por do sin diferenciar maysculas de minsculas Considerar coincidencias todas las "d" seguida de una "o" repetida cero o ms veces. Cada coincidencia ser reemplazada por "do" Considerar coincidencia cada "d" seguida de una "o" repetida una o ms veces y reemplazar cada coincidencia por "do" Considerar coincidencia tres "o" consecutivas (ooo) y reemplazar cada coincidencia por una "a" Considerar coincidencia cada uno de los grupos cada "o", "oo", "ooo..." sin importar cuantas "o" formen el grupo reemplazando cada coincidencia por una "o" coloreada

o d. do* do+ o{3} o{1,} o{2,4} [abcd] [^abcd] [a-h] [^a-h] [0-9] [^0-9]

Considerar coincidencia los grupos "oo", "ooo" "oooo" (entre 2 y 4 repeticiones) y reemplazar por por una "a" cada una Ver de las coincidencias Considera coincidencia uno cualquiera de los caracteres incluidos en el corchete y las sustituye por * Considera coincidencia cualquiera de los caracteres distintos a los incluidos en el corchete y sustituir cada una de ellas por un * Considera coincidencia cualquier caracter comprendido entre a y h (ambos inclusive) Considera coincidencia cualquier caracter no comprendido entre a y h (ambos inclusive) Considera coincidencia cualquier dgito comprendido entre 0 y 9 (ambos inclusive) Considera coincidencia cualquier dgito no comprendido entre 0 y 9 (ambos inclusive) Ver Ver Ver Ver Ver Ver

Cuando se utilizan expresiones del tipo[0-9], [A-Z] los extremos de los intervalos se delimitan por los valores de los cdigos ASCII del primero y ltimo de los caracteres entendiendo como valores pertenencientes a ese rango aquellos carcteres cuyo cdigo ASCII pertenezca a ese intervalo. El cdigo ASCII de A es 65, el de Z es 90, el de a es 97 y el de z es 122. Hemos de prestar mucha atencin a los extremos ya que si estableciramos un rango como [a-Z] estaramos indicando un intervalo inaceptable ya que comenzara en 97 y acabara en 90 (ha de ser siempre mayor el segundo valor que el primero) y nos dara error tal como puedes ver en este enlace

Los signos utilizados como metacaracteres pueden plantear problemas en los casos en los que pretendamos incluirlos como un carcter ms en un patrn de bsqueda. Para utilizarlos de esta forma es necesario escaparlos, es decir, anteponerles el carcter \. De esa forma seran interpretados como texto. Adems de la utilidad mencionada en los prrafos anteriores, cuando se antepone el carcter de escape a algunos carcteres (distintos de los metacaracteres) se activan algunas condiciones especiales tal como puedes ver en la tabla de ejemplos que tienes a la derecha. La funcin: $r= preg_quote($c, $d) recoge en la variable $r el resultado de aplicar esa secuencia de escape a la cadena contenida como parmetro en la variable $c. El parmetro $d deber recoger el carcter delimitador del patrn de bsqueda.

En esta tabla recogemos algunos ejemplos del uso de las secuencias de escape en los patrones de bsqueda.
Patrn de bsqueda Cdigo Ver fuente ejemplo Ver Ver Ver Ver Probar Probar Probar Probar Probar Probar Probar Probar Probar

Descripcin Considera coincidencia cualquier caracter que sea un dgito comprendido entre 0 y 9 (ambos inclusive). Equivale a [0-9] Considera coincidencia cualquier caracter que no sea un dgito comprendido entre 0 y 9 (ambos inclusive). Equivale a [^09] Considera coincidencia los espacios en blanco Considera coincidencia cualquier caracter que no sea un espacio en blanco

\d \D \s \S \w \W \n \/

Considera coincidencia cualquier carcter de la "a" a la "z" (excluyendo la y caracteres con tilde) o cualquier nmero del 0 Ver al 9. No incluye los espacios entre las coincidencias Considera NO COINCIDENCIA cualquier carcter de la "a" a la "z" (excluyendo la y caracteres con tilde) o cualquier nmero del 0 al 9 Considera coincidencia los saltos de lnea (no se consideran como tal las etiquetas <br>) Al anteponerle el \ a un metacaracter es considerado como un carcter normal en la cadena de bsqueda. Si no lo hiciramos nos dara un mensaje de error En este ejemplo puede verse la utilidad de la funcin preg_quote Ver Ver Ver Ver

Alternacias
La alternancia utiliza el carcter | para permitir una eleccin entre dos o ms alternativas. Cuando se conjugan incluidas entre parntesis y teniendo en cuenta que los parntesis pueden agruparse y/o anidarse pueden construirse expresiones tan complejas como necesitemos.
Patrn de bsqueda Cdigo Ver fuente ejemplo Ver Ver Probar Probar

Representa a Se considera coincidencia la presencia de uno cualquiera de los caracteres. Todas la coincidencias se reemplazarn por * Se considera coincidencia la presencia de uno cualquiera de los caracteres del primer parntesis segudio de uno de los caracteres del segundo. Sern coincidencias: ac, ad, bc y bd. Todas la coincidencias se reemplazarn por *

a|b|c (a|b)(c|d)

Anclas
En los ejemplos que hemos visto hasta ahora las coincidencias podran producirse en cualquier parte de la cadena en la que efectuamos la bsqueda. Estas condiciones pueden modificarse restringiendo la bsqueda al principio o al final de la cadena de bsqueda. Para el primer caso se antepone al patrn el metacaracter ^.

Cuidado! El metacaracter ^ tiene dos utilidades manifiestamente distintas. Dentro de un corchete [^a] significa negacin (no igual a 'a' en este caso) y fuera de l y como primer carcter del patrn ^[abc] o ^pepe hace labores de ancla para restringir la bsqueda al principio de la cadena.

El uso del modificador A produce el mismo efecto que el metacaracter ^. Cuando se trata de buscar coincidencias nicamente al final de la cadena es necesario recurrir al metacarcter $ que debe ser incluido detrs del patrn de bsqueda. Tanto este metacarcter como ^ cambian su funcionalidad cuando se incluye el modificador m. Cuando se da esta situacin considerar comienzo y final tanto el comienzo y el final de la cadena como las posiciones anteriores y posteriores al carcter de salto de lnea \n tal como puedes ver en algunos de los ejemplos de la tabla siguiente.
Patrn de bsqueda Cdigo Ver fuente ejemplo Ver Ver Probar Probar

Representa a Considera coincidencia slo si uno de los caracteres incluidos en el corchete aparece al comienzo de la cadena Utilizando el modificador A en el patrn (en este caso incluimos los caracteres delimitadores en el patrn) se logra el

^[abcd] /[abcd]/A

mismo objetivo que en el ejemplo anterior

[abcd]$ /^[abcd]/mi /[abcd]$/mi

Considera de los caracteres incluidos entre corchetes al final de la cadena Utilizando el modificador m en el patrn se comprueban las coincidencias de los caracteres situados al comienzo de cada lnea. Se considera perteneciente a una nueva lnea cada el carcter que vaya inmediatamente despus de la secuencia \n

Ver Ver

Probar Probar Probar

Utilizando el modificador m en el patrn se comprueban las coincidencias de los caracteres situados al final de cada lnea. Ver Se considera ltimo carcter de una lnea al que precede a la secuencia \n

Codicia
Se dice que las expresiones regulares son codiciosas porque, salvo que se especifique lo contrario, procuran que la coincidencia abarque el mayor nmero de caracteres posibles. Eso significara que un patrn de bsqueda del tipo a.*z considerar como una sola coincidencia la porcin de texto delimitado por la primera "a" de la cadena y la ltima "z". La codicia puede invertirse de dos maneras. Una de ellas es modificar el patrn de bsqueda agregando el signo ? inmediatamente despus de un indicador de repeticiones (+,* o {m,n}). De esa forma a.*?z considerara como coincidencia la porcin de texto delimitado por cada "a" de la cadena y la primera de las "z" que aparezcan despus de ella. La segunda forma de invertir la codicia es agregar el modificador U con lo cual la cadena patrn podra ser similar a esta: /a.*z/U con los mismos resultados descritos en el prrafo anterior.
ejemplo119.php Ver cdigo fuente

Subpatrones
Cuando una expresin regular se encierra en un parntesis pasa a constituir un subpatrn de captura que, por defecto, tiene dos utilidades prcticas. La primera es su condicin de ser parte del patrn que la contenga incluidas las eventuales condiciones de alternancia(a|b) que pueda contener. Junto con esa funcin los subpatrones disponen de otra muy importante: la captura. Las coincidencias son almacenadas en memoria con la opcin de poder ser utilizadas a travs de lo que se conoce como retro referencias. Fuera de una clase carcter, una barra invertida seguida por un dgito mayor que 0 es una retro-referencia a un subpatrn de captura anterior. La retro-referencia no recoge el subpatrn sino el valor de la cadena coincidente con el subpatrn al que alude. Las retro referencias pueden marcarse as: \\n, \\gn o \\g{n} siendo en los tres casos n el nmero de orden del subpatrn contando de izquierda a derecha. Veamos su comportamiento con un ejemplo. Si comparamos la cadena "Me gusta el atn rojo con tomate" con el patrn el((atn|bonito)(blanco|rojo)) vamos a encontrar una coincidencia del patrn completo (atn rojo), y las coincidencias de cada uno de los subpatrones: atn en el caso del primero, y rojo en el caso del segundo. Tales coincidencias son numeradas para su uso como retro referencias por medio de nmeros naturales 1, 2 y 3 que se corresponden con los parntesis contados de izquierda a derecha. Por ese criterio de asignacin la retro referencia \1 (siempre se antepone \ para aludir a ellas) recoger el valor atn rojo, \2 contendratn y \3 incluir rojo. Hay situaciones en las que no es necesario usar retro referencias y, dado que pueden ralentizar la operacin y requerir abundante espacio de memoria, puede resulte conveniente desactivarlas. Para ello basta con que incluyamos despus del parntesis de apertura del patrn (o del subpatrn) los metacaracteres ?:. Aqu tienes algunos ejemplos de utilizacin de retro referencias.
Cdigo Ver fuente ejemplo Ver Ver Ver Probar Probar Probar

Patrn de bsqueda

Representa a El subpatrn buscar el carcter a o b. El resultado ser capturado como \1. Incluyendo la referencia a esa captura como carcter siguiente sern coincidentes con el patrn las cadenas aa y bb. El primer carcter ser una letra nmero (\w) que ha de coincidir con el cuarto carcter de la cadena (\\1). El segundo puede ser tambin cualquier letra (\w) que ha de coincidir con el tercer carcter de la cadena(\\2) El primer subpatrn (identificado mediante \1) sera el ms exterior de todos (marcado en rojo). Incluye dos

(a|b)\\1 (\w)(\w)\\2\\1 ((\w)(\w))\\3\\2\\1

subpatrones que numerados de izquierda a derecha resultarn identificados por \\2 y \\3 (verde y azul respectivamente)

((a|b)(c|d))\\1 (?:a|b)\\1 (?:a|b) ((?:a|b)(?:c|d))\\1

El primer subpatrn ha de contener una de las cadenas ac, ad, bc, o bd y, adems ha de repetirse (\\1) por tanto sern coincidencias: acac, adad, bcbc y bdbd Dar error ya que ?: es el indicador de no captura lo cual hace invlida la referencia \\1 Eliminando la retroreferencia \\1 del ejemplo anterior funciona correctamente Funciona exactamente igual que el ltimo ejemplo de la tabla anterior. Las referencias eliminadas no estn incluidas en el patrn de bsqueda y por tanto no influyen en el resultado

Ver Ver Ver Ver

Probar Probar Probar Probar

Subpatrones especiales
Subpatrones modificadores
Entre los tipos especiales de subpatrones cabe hablar de los conocidos como subpatrones modificadores. Su funcin es la deincluir o excluir modificadores a lo largo del patrn de bsqueda. Dada su condicin de subpatrones han de comienzar y terminar por parntesis (). Por su carcter especial han de llevar ? despus del parntesis de apertura (?) y a continuacin pueden incluir uno o varios modificadores. Si se trata de activarlo basta con poner el carcter representativo (A, i, m, etctera) y para desactivarlos se incluye un signo menos (-) delante de ese carcter. Por ejemplo (?A-im) activara el modificador A, desactivara el i y activara el m siempre a partir de la posicin del patrn de bsqueda en el que es incluido este subpatrn.
Subpatrones modificadores Patrn de bsqueda Representa a El primer subpatrn activa la opcin sensible a maysculas/minsculas y la aplica al primer carcter. Para los siguientes caracteres el subpatron (?i) vuelve a desactivar esa opcin. Cdigo Ver fuente ejemplo Ver Probar

(?-i)[A-Z](?i)[a-z]*

Subpatrones con aserciones


Otra situacin especial es el caso de las aserciones. En este caso se contemplan cuatro posibilidades. En subpatrn y(?=x) donde xe y son condiciones, exige que se cumpla la condicin x inmediatamente despus de hacerlo la condicin y. Si cambiramos el signo = por! la expresin y(?!x) ser interpretada como exigencia de que NO se cumpla la condicin x despus de hacerlo la condicin y Anteponiendo un < al signo = (o a !) podran plantearse expresiones del tipo (?<=x)y (?<!x)y que seran exigencias del cumplimiento (o no cumplirse si se trata de !) de la condicin x inmediatamente antes de que se cumpla la condicin y.
Comprobacin de los caracteres siguientes o anteriores - Aserciones o declaraciones Patrn de bsqueda Representa a Cdigo Ver fuente ejemplo Probar Probar Probar Probar

(?<=[0-9])[a-z] (?<![0-9])[a-z] [0-9](?=[A-Z]) [0-9](?![A-Z])

Considera coincidencia cualquier letra ([a-z]) qu est situada detrs de un nmero comprendido entre Ver 0 y 9 ([0-9]) Considera coincidencias cualquier letra ([a-z]) qu NO EST situada detrs de un nmero comprendido entre 0 y 9 ([0-9]) Considera coincidencia cualquier nmero ([0-9]) qu vaya delante (lleve detrs) de una letra ([A-Z]) Ver Ver

Considera coincidencia cualquier nmero ([0-9]) qu NO VAYA delante (NO lleve detrs) una letra ([AVer Z])

Subpatrones condicionales
Tambin existen los subpatrones condicionales que se comportan de una forma similar a los operadores condicionales. Mediante la sintaxis (?(x)y|z) o (?(x)y) se establecen dos posibilidades de coincidencia. Cuando se cumple la condicin x ser usado el patrn de bsqueda(o subpatrn) x. En caso de que no se cumpla la condicin se utilizara, en caso de haber sido especificado, el patrn z.

Las condiciones slo pueden ser establecidas por retro referencias o mediante aserciones. Cuando se utilizan retro referencias no se aluden de la forma tradicional (\\n, \\gn o \\g{n}). En este caso bastara incluir dentro del parntesis que contiene la condicin x el nmero de la retro referencia (n) sin anteponerle ningn otro carcter. Puedes verlo en los ejemplos de la tabla. En la tabla que tienes a continuacin hemos incluido una serie de ejemplos que contemplan algunas de las mltiples posibilidades que ofrecen los subpatrones condicionales. Es particularmente importante prestar mucha atencin a la elaboracin de los patrones para evitar resultados inesperados. En los ejemplos incluimos comentarios relativos a algunos de esos resultados que, de no tenerlos previstos, pueden parecer desconcertantes.
Caso en los que la condicin es una retroreferencia Patrones de bsqueda Representan a Cdigo Ver fuente ejemplo Ver Todos estos ejemplos tienen marcado en rojo el condicional, dentro de l van la retro referencia, el Ver patrn que usar si se cumple la condicin y el patrn que usar si no se cumple la condicin. Ver Ver Los ejemplos anteriores sin incluir patrn para el caso en que no se cumple la condicin. Ver En los ejemplos se comenta lo relativo a los caracteres precedidos del smbolo \. Ver Ver Ahora hemos quitado a los ejemplos iniciales el patrn para el caso de que se cumpla la condicin. Ver Ver Ver Aqu hemos eliminado del condicional ambos patrones. Ver Ver Probar Probar Probar Probar Probar Probar Probar Probar Probar Probar Probar Probar

([0-9]*)(?(1)[a-c]|[d-z]) (\"|\')(\<.*?)*(?(2)\\1|.*?\\1) ((a)|(b))(?(3) f| c) ([0-9]*)(?(1)[a-c]) (\"|\')(\<.*?)*(?(2)\\1) ((a)|(b))(?(3) f) ([0-9]*)(?(1)|[d-z]) (\"|\')(\<.*?)*(?(2)|.*?\\1) ((a)|(b))(?(3)| c) ([0-9]*)(?(1)) (\"|\')(\<.*?)*(?(2)) ((a)|(b))(?(3))
Caso en los que la condicin es el resultado de una comparacin de igualdad o desigualdad Patrn de bsqueda Representa a

Cdigo Ver fuente ejemplo Probar

(?(?<=[0-9][a-z])H|ms) (?(?<![0-9][a-z])H|ms) H(?(?=[0-9][a-z])|ms)

Si se cumple la condicin verde(un nmero delante de una letra) agrupa esa condicin a la H para conformar la palabra a buscar. Si no se cumple aquella condicin considera patrn de bsqueda Ver la palabra "ms" Si se cumple la condicin verde(un nmero delante de una letra) agrupa esa condicin a la H para conformar la palabra a buscar. Si no se cumple aquella condicin considera patrn de bsqueda Ver la palabra "ms" Si se cumple la condicin verde(un nmero delante de una letra) agrupa esa condicin a la H para conformar la palabra a buscar. Si no se cumple aquella condicin considera patrn de bsqueda Ver la palabra "ms"

Probar

Probar

Utilizando las opciones que nos ofrecen cada uno de los elementos que hemos ido viendo a lo largo de esta pgina podremos componer patrones de bsqueda que satisfagan casi todas nuestras necesidades. Es evidente que a medida que aumentemos los niveles de exigencia los patrones pueden ir adquiriendo una estructura bastante compleja. Veamos, en la pgina siguiente, los usos que podemos dar a los patrones en PHP.

Otras funciones con expresiones regulares


La funcin preg_match
Cuando se trata nicamente de conocer la existencia o inexistencia de texto dentro de una cadena o de un fichero puede resultar til la funcin: preg_match( patron, cadena, $coincidencias ) realiza una bsqueda en la cadena por medio de la expresin regular incluida en el patron. Si encuentra alguna coincidencia devuelve el valor booleano TRUE, en caso contrario devuelve FALSE.

El parmetro $coincidencias es opcional. Cuando se incluye recoger en un array con ese nombre los resultados de la bsqueda.

Informacin sobre variables Obtener informacin sobre variables


Veremos aqu algunas de las mltiples funciones que nos permiten obtener informacin sobre arrays y variables. sizeof(variable) La funcin sizeof devuelve el nmero de elementos de un array. Si se aplica sobre una variable (no array) devolver uno y tanto si se aplica sobre un array vaco, una variable con valor nulo o sobre una variable no definida, devolver cero. count(variable) Tiene idntica funcionalidad a la de sizeof.

<?php $a=array("Lunes","Martes","Miercoloes","Jueves", "Viernes","Sbado","Domingo"); $b=array( "Precio" => "17340 euros", "Color" => "Rojo", "Llantas" => "Aluminio"); $c=47; $d=""; $e=array(); echo "<h3>Valores usando sizeof()</h3>"; @print @print @print @print @print @print " " " " " " a b c d e f tiene: tiene: tiene: tiene: tiene: tiene: ".sizeof($a)." ".sizeof($b)." ".sizeof($c)." ".sizeof($d)." ".sizeof($e)." ".sizeof($f)." elementos<br>"; elementos<br>"; elementos<br>"; elementos<br>"; elementos<br>"; elementos<br>";

print "<h3>Valores usando count()</h3>"; @print " a tiene: ".count($a)." elementos<br>"; @print " b tiene: ".count($b)." elementos<br>"; @print " c tiene: ".count($c)." elementos<br>"; @print " d tiene: ".count($d)." elementos<br>"; @print " e tiene: ".count($e)." elementos<br>"; @print " f tiene: ".count($f)." elementos<br>"; ?>
ejemplo149.php

isset(variable) La funcin isset comprueba si una variable est definida. Si est definida incluso con valor nulo o como array vaco isset devolverUNO, en caso contrario devolver NUL. Esta funcin puede ser un complemento de sizeof o de count dado que permitira comprobar si estn definidas las variables en las que aquellas funciones devuelven dimensin cero. empty(variable) La funcin empty comprueba si una variable est vaca o no est definida. Si est vaca (valor nulo o array vaco) o no est definidaempty devolver UNO, en caso contrario devolver NUL.

Cuidado! No confundas isset con empty. No devuelven los mismos resultados. Mientras que isset slo comprueba si una variable est definida (tiene un valor aunque sea nulo) la funcin empty comprueba que la variable no est definida y, si lo est, que su valor sea nulo.
is_array(variable) Devuelve UNO (verdadero) en el caso de que la variable sea tipo array y NUL en el caso contrario. is_long(variable) o is_int(variable) o is_integer(variable) Estas tres funciones que son idnticas devuelven UNO en el caso de que la variable sea de tipo entero y NUL en el caso contrario. is_float(variable) o is_double(variable) Estas dos funciones tambin idnticas devuelven UNO en el caso de que la variable sea de tipo coma flotante y NUL en el caso contrario. is_string(variable) Devuelve UNO en el caso de que la variable sea tipo string y NUL en caso contrario. unset(variable) Destruye la variable indicada. Si despus de aplicar unset sobre una variable aplicamos de nuevo la funcin isset, nos devolver NUL indicando que ya no est definida. La funcin unset se puede aplicar tanto sobre variables como sobre un array y tambin sobre un elemento de un array.

<?php $a=array("Lunes","Martes","Miercoloes","Jueves", "Viernes","Sbado","Domingo"); $b=array( "Precio"=>"17340 euros", "Color" =>"Rojo", "Llantas" =>"Aluminio"); $c=47; $d=""; $e=array(); echo "<h3>Variables definidas</h3>"; echo echo echo echo echo echo " " " " " " Esta Esta Esta Esta Esta Esta definida definida definida definida definida definida la la la la la la variable variable variable variable variable variable a b c d e f ? ? ? ? ? ? ",isset($a),"<br>"; ",isset($b),"<br>"; ",isset($c),"<br>"; ",isset($d),"<br>"; ",isset($e),"<br>"; ",isset($f),"<br>";

echo "<h3>Identificacin de tipos de variables</h3>"; echo echo echo echo " " " " La La La La variable variable variable variable a a a a es es es es un array ? ",is_array($a),"<br>"; tipo double ? ",is_double($a),"<br>"; un entero ? ",is_int($a),"<br>"; un entero ? ",is_long($a),"<br>";

echo "<h3>Eliminando variables</h3>"; echo "La dimensin de a es: ",count($a),"<br>"; unset($a[0]); echo "Nueva dimensin de a: ",count($a),"<br>"; echo "La dimensin de b es: ",count($b),"<br>"; unset($b); @print "Nueva dimensin de b: ".count($b)."<br>"; echo " Sigue definida la variable b ? ",isset($b),"<br>"; print "<h1>Diferencias entre empty e isset</h1>"; print "<br />Cuando una variable no est definida ( \$sin_definir)<br /><br />"; print "El resultado de empty es (cero si no escribe nada): "; print empty($sin_definir); print "<br />El resultado de isset es (cero si no escribe nada): "; print isset($sin_definir); $soy_nula=""; print "<br /><br />Cuando una variable est definida con valor nulo ( \$soy_nula)<br />"; $definida; print "<br />El resultado de empty es (cero si no escribe nada): "; print empty($soy_nula); print "<br />El resultado de isset es (cero si no escribe nada): "; print isset($soy_nula); ?>
ejemplo150.php

Recuentos en arrays Recuento de los valores contenidos en una matriz


Algunas de las posibilidades de obtener informacin sobre los contenidos de un array son las siguientes: $recuento=array_count_values(array)

Con array_count_values la variable $recuento ser un nuevo array cuyos ndices son cada uno de los valores distintos que contengaarray y cuyos valores sern el resultado de contar el nmero de veces que se repite este nuevo ndice en el array inicial. Distingue entremaysculas y minsculas. Cuando los valores del array inicial (array) son nmeros enteros (sea array escalar o asociativo) $recuento ser unarray escalar. En caso contrario, ser asociativo.

Bsqueda de elementos en un array


claves=array_keys(array)

Devuelve un array escalar (claves) que contiene como valores los ndices del array inicial (array). claves=array_keys(array, valor)

Devuelve un array escalar (claves) que contiene como valores los ndices de los elementos del array inicial cuyo valor coincide con el indicado mediante el parmetro valor. valores=array_values(array) Esta funcin recoge en una nueva matriz (valores) todos los valores contenidos en el array. Es una forma de conversin de un array asociativo en otro escalar.

<?php $a=array(1,2,3,1,1,2,3,3,4,4,4,0,1); $b=array("blanco","azul","blanco","blanco","azul","Blanco","Azul"); $c=array( "a"=>"rojo", "b" =>"verde", "c" =>"rojo", "d" =>"rojo", "e" =>"verde", "f" =>"Rojo", "g" =>"Verde"); echo "<h3>Cuenta valores del array()</h3>"; $contador=array_count_values($a); foreach($contador as $valor=>$veces){ echo "El valor ",$valor," se repite ", $veces," veces en la matriz a<br>"; } echo $contador[0],"<br>"; echo $contador[1],"<br>"; echo $contador[2],"<br>"; echo $contador[3],"<br>"; echo $contador[4],"<br>"; $contador1=array_count_values($b); foreach($contador1 as $valor=>$veces){ echo "El valor ",$valor," se repite ", $veces," veces en la matriz a<br>"; } echo $contador1["blanco"],"<br>"; echo $contador1["azul"],"<br>"; echo $contador1["Azul"],"<br>"; echo $contador1["Blanco"],"<br>"; $contador2=array_count_values($c); foreach($contador2 as $valor=>$veces){ echo "El valor ",$valor," se repite ",$veces," veces en la matriz a<br>"; } echo $contador2["rojo"],"<br>"; echo $contador2["Verde"],"<br>"; echo $contador2["verde"],"<br>"; echo $contador2["Rojo"],"<br>"; echo "<h3>Devuelve las claves de un array</h3>"; $claves=array_keys($a); foreach($claves as $v){ echo "El valor ",$v," es una de las claves<br>"; } $claves1=array_keys($a,1); foreach($claves1 as $v){ echo "El valor ",$v," es una de las claves de elementos de la matriz cuyo valor es <b>1</b><br>"; } echo "<h3>Devuelve los valores de un array</h3>"; $valores=array_values($c); foreach($valores as $v){ echo $v," Este es un de los valores de de la matriz c<br>"; } ?>
ejemplo151.php

Ordenacin de arrays (I)

Localizacin de valores en una matriz


in_array(valor,array)

La funcin in_array busca en la matriz (array) el valor (numrico o cadena) contenido en el parmetro valor. Si lo encuentra devuelve 1, y si no existiera devolvera NUL.

Posicionamientos en una matriz


Mediante estas funciones se puede modificar la posicin del puntero interno de una matriz y determinar los ndices de los elementos a los que apunta en cada momento. key(array)

Devuelve el ndice del elemento de la matriz al que apunta en ese momento el puntero interno de la matriz. reset(array)

Desplaza el puntero interno a la posicin del primer ndice del array. end(array)

Desplaza el puntero interno a la posicin del ltimo ndice del array. pos(array)

Mantiene el puntero interno en la posicin del actual. next(array)

Avanza el puntero interno en una posicin respecto a la actual. prev(array)

Retrocede el puntero interno en una posicin respecto a la actual.

Moviendo el puntero interno


<?php $a=array(1,2,3,1,1,2,3,3,4,4,4,0,1); $b=array("blanco","azul","blanco","blanco","azul","Blanco","Azul"); $c=array( "a"=>"rojo", "b" =>"verde", "c" =>"rojo", "d" =>"rojo", "e" =>"verde", "f" =>"Rojo", "g" =>"Verde"); echo "<h3>Busca un valor en una matriz</h3>";

echo " Busca el valor en la "#</b> Si no ha puesto echo " Busca el valor en la "#</b> Si no ha puesto echo " Busca el valor en la "#</b> Si no ha puesto echo " Busca el valor en la "#</b> Si no ha puesto

matriz: nada no matriz: nada no matriz: nada no matriz: nada no

<b>#",in_array(3,$a), estaba, si 1 lo encontr <BR>"; <b>#",in_array(7,$a), estaba, si 1 lo encontr <BR>"; <b>#",in_array("gris",$b), estaba, si 1 lo encontr <BR>"; <b>#",in_array("blanco",$b), estaba, si 1 lo encontr <BR><br>";

echo "<h3>Posicionandose y determinando indices actuales</h3>"; echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo ?>
ejemplo152.php

"Este el valor asoaciado al indice 3 de la matriz a: ",$a[3],"<br>"; "El puntero interno apunta a la clave: ",key($a),"<br>"; "Este es el valor siguiente al anterior: ",next($a),"<br>"; "El puntero interno apunta a la clave: ",key($a),"<br>"; "Este es el primer valor de la matriz a: ",reset($a),"<br>"; "El puntero interno apunta a la clave: ",key($a),"<br>"; "Este es el ultimo valor de la matriz a: ",end($a),"<br>"; "El puntero interno apunta a la clave: ",key($a),"<br>"; "Este es el penltimo valor de la matriz a: ",prev($a),"<br>"; "El puntero interno apunta a la clave: ",key($a),"<br>"; "Este es el mismo valor anterior: ",pos($a),"<br>"; "El puntero interno apunta a la clave: ",key($a),"<br>"; "Este el valor asoaciado al indice 4 de la matriz b: ",$b[4],"<br>"; "El puntero interno apunta a la clave: ",key($b),"<br>"; "Este es el valor siguiente al anterior: ",next($b),"<br>"; "El puntero interno apunta a la clave: ",key($b),"<br>"; "Este es el primer valor de la matriz a: ",reset($b),"<br>"; "El puntero interno apunta a la clave: ",key($b),"<br>"; "Este es el ultimo valor de la matriz a: ",end($b),"<br>"; "El puntero interno apunta a la clave: ",key($b),"<br>"; "Este es el penltimo valor de la matriz a: ",prev($b),"<br>"; "El puntero interno apunta a la clave: ",key($b),"<br>"; "Este es el mismo valor anterior: ",pos($b),"<br>"; "El puntero interno apunta a la clave: ",key($b),"<br>";

Ordenacin de arrays (II) Ordenaciones de arrays


Los elementos de un array se van ordenando segn se van definiendo. Por tanto, su orden no es el mismo que el de los valores de sus ndices. Las funciones PHP que ordenan los elementos de un array permiten dos opciones. Con una de ellas es posible la ordenacin de los elementos sin modificar los valores de los ndices, mientras que la otra s modifica los ndices. En el segundo de los casos la modificacin puede afectar incluso al tipo de ndices dado que los resultados de las ordenaciones tanto si hemos partido de un array escalar como si lo hemos hecho desde uno asociativo es siempre un array escalar.

Ordenacin por valores sin mantener ndices


sort(array)

Ordena los valores del array en sentido creciente y lo reindexa asignando ndice CERO al menor de los valores.

rsort(array)

Ordena la matriz en sentido decreciente de sus valores y la reindexa asignando ndice CERO al mayor de estos.

Ordenacin por ndices


ksort(array)

Ordena la matriz segn sus ndices y en sentido creciente de estos. krsort(array)

Ordena la matriz por ndices en sentido decreciente de los mismos.

Ordenacin por valores manteniendo ndices


asort(array)

Ordena la matriz segn sus valores en sentido creciente y mantiene los ndices del array original. arsort(array)

Ordena la matriz por valores en sentido decreciente y sigue manteniendo los ndices originales.

Ordenacin mediante funcin definida por usuario


PHP permite que el usuario pueda definir funciones en las que establezca sus criterios particulares de ordenacin. Las funciones PHP que permiten usar esta caracterstica son las siguientes: uasort(array, funcion)

Ordena la matriz utilizando los criterios establecidos por la funcin definida por el usuario y mantiene los ndices del array. usort(array, funcion)

Ordena la matriz por valores utilizando los criterios definidos en la funcin de usuario y modifica los ndices. uksort(array, funcion)

Ordena la matriz por claves utilizando los criterios definidos en la funcin. En el ejemplo hemos definido una funcin de comparacin siguiendo el criterio de ser o no ser mltiplo de 2. Trataremos lasfunciones en un tema aparte. La utilidad de la que hemos incluido en el ejemplo es la siguiente: Si el valor de la variable es par le asignamos un nmero negativo como respuesta y en caso contrario uno positivo. De esta forma los valores del array que devuelven negativos se consideran anteriores en la ordenacin a los que dan como resultado un nmero positivo.

<?php $a=array(1,2,3,1,1,2,3,3,4,4,4,0,1); $b=array("blanco","azul","blanco","blanco","azul","Blanco","Azul"); $c=array( "b" =>"verde",

"c" =>"rojo", "e" =>"verde", "f" =>"Rojo", "g" =>"Verde", "a"=>"rojo", "d" =>"rojo",); sort ($a); echo "<h3>Ordenacin por valores usando sort</h3>"; foreach ($a as $clave=>$valor){ echo "Clave: ",$clave," Valor: ",$valor, "<br>"; } sort ($c); echo "<h3>Ordenacin por valores usando sort</h3>"; foreach ($c as $clave=>$valor){ echo "Clave: ",$clave," Valor: ",$valor, "<br>"; } rsort($a); echo "<h3>Ordenacin inversa por valores usando rsort</h3>"; foreach ($a as $clave=>$valor){ echo "Clave: ",$clave," Valor: ",$valor, "<br>"; } ksort($b); echo "<h3>Ordenacin por claves usando ksort</h3>"; foreach ($b as $clave=>$valor){ echo "Clave: ",$clave," Valor: ",$valor, "<br>"; } krsort($b); echo "<h3>Ordenacin inversa por claves usando krsort</h3>"; foreach ($b as $clave=>$valor){ echo "Clave: ",$clave," Valor: ",$valor, "<br>"; } asort($c); echo "<h3>Ordenacin por valores manteniendo indices </h3>"; foreach ($c as $clave=>$valor){ echo "Clave: ",$clave," Valor: ",$valor, "<br>"; } arsort($c); echo "<h3>Ordenacin inversa por valores manteniendo indices arsort</h3>"; foreach ($c as $clave=>$valor){ echo "Clave: ",$clave," Valor: ",$valor, "<br>"; } echo "<h3>Ordenacin por valores mediante funcin de usuario manteniendo indices</h3>";

/* esta funcin recoge el valor de la variable $a y aplicar el operador de comparacin ternario de forma que si el valor de la variable es impar devuelve como valor -2 y si es par devuelve 2 el 2 y el menos 2 nicamente establecen criterios de comparacin de modo que los valores -2 sern considerados anteriores a los valores +2 */ function micomparar (&$a) { return ($a%2!=0) ? -2 : 2; } uasort ($a, 'micomparar'); foreach ($a as $clave=>$valor){ echo "Clave: ",$clave," Valor: ",$valor, "<br>"; } echo "<h3>Ordenacin por clave mediante funcin de usuario </h3>"; uksort ($a, 'micomparar'); foreach ($a as $clave=>$valor){ echo "Clave: ",$clave," Valor: ",$valor, "<br>"; } echo "<h3>Ordenacin por valores mediante funcin de usuario </h3>"; usort ($a, 'micomparar'); foreach ($a as $clave=>$valor){ echo "Clave: ",$clave," Valor: ",$valor, "<br>"; } ?>
ejemplo153.php

Modificacin de arrays Modificaciones en arrays


var= range(inferior, superior)

Crea una nueva matriz escalar (var) en la que los valores de los elementos sern los nmeros enteros (ordenados) pertenecientes al intervalo comprendido entre los valores inferior y superior, incluidos estos. Tanto inferior como superior deben ser nmeros enteros. shuffle(array)

Intercambia de modo aleatorio los valores de un array y los reindexa. Igual que ocurra en el caso de los nmeros aleatorios, la funcinshuffle deber ir precedida de una semilla del tipo srand. En el ejemplo hemos usado como semilla la funcin: srand(time()).

var= array_flip(array)

Devuelve un array (var) que contiene como valores los ndices de la matriz array y como ndices los valores del propio array. Como quiera que los valores pueden estar repetidos y no es posible que lo estn los ndices, esta funcin, en caso de valores repetidos, toma cada uno de esos valores una sola vez, lo utiliza como ndice del nuevo array y asigna como valor del nuevo elemento el mayor de los ndices del array original de los elementos que contuvieran ese valor.

Insertando elementos en un arrays


array_unshift(arr, v1,v2,..)

Inserta al principio de la matriz arr los valores v1, v2, etctera que pueden ser tantos como se deseen y deben estar separados por comas. array_push(array, v1,v2,..)

Inserta al final de la matriz array los valores v1, v2, etctera, que igual que en el caso anterior, pueden ser tantos como se deseen y deben estar separados por comas. Tanto array_unshift como array_push asignan a los nuevos elementos ndices numricos. array_pad(array, n, var)

Inserta nuevos elementos en array y les asigna el valor contenido en var. Insertar tantos nuevos elementos como sea necesario para que el array alcance una longitud de n elementos. Si el valor de n es positivo inserta los elementos al final del array, si fuera negativo los insertara al comienzo del mismo. A los nuevos elementos del array se les asignan ndices numricos. array_merge($a, $b)

Crea un nuevo array escalar en el que se incluyen todos los elementos contenidos en los arrays $a y $b.

Quitar elementos de un array


array_shift($a)

La funcin array_shift extrae el primer elemento del array $a. array_pop($a)

La funcin array_pop extrae el ltimo elemento del array $a. array_slice($a,n)

La funcin array_slice extrae n elementos del array $a. Si el valor de n es positivo extraer todos los elementos a partir del que ocupa la posicin n contando desde el primero hasta el ltimo segn el orden de creacin de los elementos. Si el valor de n es negativo extraer todos los elementos a partir del ensimo, esta vez contando desde el ltimo hasta el primero. array_slice($a,n, m)

La funcin array_slice con dos parmetros permite extraer una parte de los valores de una matriz siguiendo estos criterios:

Si n y m son positivos, extraer m elementos a partir del que ocupa la posicin ensima de primero a ltimo. Cuando n es negativo y m es positivo se extraern m elementos contados a partir del ensimo, esta vez recorriendo el array deltimo a primero. En el caso en que n tenga valor positivo y m sea negativo extraer los comprendidos entre el ensimo contado de primero a ltimoy el emsimo contado desde el ltimo hasta el primero. Si n es negativo y m es tambin negativo extraer los caracteres comprendidos entre el ensimo contado de ltimo a primero y elemsimo contado en el mismo sentido. En este caso se requiere que el valor absoluto de n sea mayor que el de m. En caso de no cumplirse esta condicin devolver un array vaco.

Invertir el orden de un array


array_reverse(array)

Devuelve un nuevo array cuyos elementos estn en orden inverso al del array original. De esta forma el elemento que ocupaba la ltima posicin pasa a ocupar la primera y as sucesivamente.

Cuidado!
Recuerda que las posiciones iniciales de los elementos de un array no tienen relacin con sus ndices sino con la secuencia en la que fueron creados. Y otra cosa, mucho cuidado con la aplicacin de todas estas funciones y con los ndices de los arrays resultantes. Fjate en los ejemplos y vers que algunas estas funciones reindexan los resultados y los convierten en escalares an en el caso de que originalmente fueran asociativos. <?php $a=array(1,2,3,1,1,2,3,3,4,4,4,0,1); $b=array("blanco","azul","blanco","blanco","azul","Blanco","Azul"); $c=array( "b" =>"verde", "c" =>"rojo", "e" =>"verde", "f" =>"Rojo", "g" =>"Verde", "a"=>"rojo", "d" =>"rojo"); $C=array( "b" =>"verde", "c" =>"rojo", "e" =>"verde", "f" =>"Rojo", "g" =>"Verde", "a"=>"rojo", "d" =>"rojo"); echo "<h3>Crea una matriz de nmeros enteros</h3>"; $r=range(7,11); foreach($r as $clave=>$valor){ echo "Clave: ",$clave," Valor: ",$valor,"<br>"; } echo "<h3>Intercambia aleatoriamente elementos en una matriz</h3>"; srand (time()); shuffle ($r);

foreach($r as $clave=>$valor){ echo "Clave: ",$clave," Valor: ",$valor,"<br>"; } echo "<h3>Intercambia valores e indices</h3>"; $p=array_flip($a); foreach($p as $clave=>$valor){ echo "Clave: ",$clave," Valor: ",$valor,"<br>"; } echo "<br>"; $q=array_flip($c); foreach($q as $clave=>$valor){ echo "Clave: ",$clave," Valor: ",$valor,"<br>"; } echo "<h3>Inserta elementos al principio de una matriz</h3>" array_unshift($a,97,"Pepe",128); foreach($a as $clave=>$valor){ echo "Clave: ",$clave," Valor: ",$valor,"<br>"; } echo "<br>"; array_unshift($c,97,"Pepe",128); foreach($c as $clave=>$valor){ echo "Clave: ",$clave," Valor: ",$valor,"<br>"; } echo "<h3>Inserta elementos al final de una matriz</h3>"; array_push($a,3.4,"Luis",69); foreach($a as $clave=>$valor){ echo "Clave: ",$clave," Valor: ",$valor,"<br>"; } echo "<br>"; array_push($c,3.4,"Luis",69); foreach($c as $clave=>$valor){ echo "Clave: ",$clave," Valor: ",$valor,"<br>"; } echo "<h3>Inserta elementos iguales al principio o al final de una matriz</h3>"; $wz1=array_pad($a,25,"relleno"); foreach($wz1 as $clave=>$valor){ echo "Clave: ",$clave," Valor: ",$valor,"<br>"; } echo "<br>"; $wz2=array_pad($c,-17,"relleno"); ;

foreach($wz2 as $clave=>$valor){ echo "Clave: ",$clave," Valor: ",$valor,"<br>"; } echo "<h3>Fusiona dos matrices</h3>"; $wz3=array_merge($a,$b); foreach($wz3 as $clave=>$valor){ echo "Clave: ",$clave," Valor: ",$valor,"<br>"; } echo "<h3>Extrae el primer elemento de una matriz</h3>"; array_shift ($a); foreach($a as $clave=>$valor){ echo "Clave: ",$clave," Valor: ",$valor,"<br>"; } echo "<br>"; array_shift ($c); foreach($c as $clave=>$valor){ echo "Clave: ",$clave," Valor: ",$valor,"<br>"; } echo "<h3>Extrae el ultimo elemento de una matriz</h3>"; array_pop($a); foreach($a as $clave=>$valor){ echo "Clave: ",$clave," Valor: ",$valor,"<br>"; } echo "<br>"; array_pop ($c); foreach($c as $clave=>$valor){ echo "Clave: ",$clave," Valor: ",$valor,"<br>"; } echo "<h3>Extrae elementos de una matriz</h3>"; $zz1=array_slice($a,3); foreach($zz1 as $clave=>$valor){ echo "Clave: ",$clave," Valor: ",$valor,"<br>"; } echo "<br>"; $zz2=array_slice($a,-3); foreach($zz2 as $clave=>$valor){ echo "Clave: ",$clave," Valor: ",$valor,"<br>"; } echo "<br>"; $zz3=array_slice($b,3,4); foreach($zz3 as $clave=>$valor){ echo "Clave: ",$clave," Valor: ",$valor,"<br>"; }

echo "<br>"; $zz4=array_slice($b,3,-2); foreach($zz4 as $clave=>$valor){ echo "Clave: ",$clave," Valor: ",$valor,"<br>"; } echo "<br>"; $zz5=array_slice($b,-5,-2); foreach($zz5 as $clave=>$valor){ echo "Clave: ",$clave," Valor: ",$valor,"<br>"; } echo "<h3>Invierte los elementos de la matriz</h3>"; $inv=array_reverse($C); foreach($inv as $clave=>$valor){ echo "Clave: ",$clave," Valor: ",$valor,"<br>"; } ?>
ejemplo154.php

Funciones de usuario Qu son las funciones de usuario?


De igual forma que lo hace el navegador en el caso del HTML, PHP lee e interpreta las instrucciones contenidas en los scripts de forma secuencial. Es decir, las instrucciones se van ejecutando en el mismo orden en el que aparecen en el documento original, con laexcepcin de las funciones ya que estas son bloques de instrucciones son puestos a disposicin de PHP que no se ejecutarn hasta el momento en que sean requeridas de forma expresa.

Dnde deben insertarse?


Aunque en versiones antiguas de PHP era necesario definir la funcin antes de invocarla, a partir de la versin 4 no es necesaria esa organizacin secuencial. La funcin pueden estar escrita dentro de cualquier script y en cualquier parte del documento, sin que tenga importancia alguna el lugar en el que se incluya la llamada a la misma. Tambin es posible y bastante habitual incluir funciones de uso frecuente en documentos externos de modo que pueden sercompartidas. En este caso, adems de invocarla es necesario indicar a PHP el lugar donde debe buscarla. Hablaremos de ello cuando estudiemos lo relativo a include.

Definicin de la funcin
Las funciones de usuario requieren la siguiente sintaxis: function nombre ( ) { ..... ... instrucciones ... ..... }

Es imprescindible respetar estrictamente la sintaxis que requiere de forma obligatoria los siguientes elementos:

La palabra function debe estar escrita en minsculas. El nombre de la funcin, que debe seguir criterios similares a los de los nombres de variables, aunque en este caso no se antepone el smbolo $ ni ningn otro. Los parntesis (), incluso cuando no contengan nada. Las llaves de apertura ({) y cierre (}) entre las que se escribirn las instrucciones correspondientes a la funcin.

Ejecucin de la funcin
Las funciones PHP no se ejecutan en tanto no sean invocadas. Para invocar una funcin la sintaxis es la siguiente: nombre()

Al ser llamada con esta sintaxis desde cualquier script se ejecutarn las instrucciones contenidas en ella. Con este primer ejemplo obtendremos una pgina en blanco. El script contiene una funcin pero no hay ninguna instruccin que la invoque y por lo tanto no se ejecutara.

<?php function a1(){ for($i=1;$i<=10;$i++){ echo $i,"<br>"; } } ?>


ejemplo155.php

<?php a1(); ?> <!-- Hemos escrito un script con una llamada a la funcin a1 que an no est definida. Tendremos que hacerlo, pero no importa la parte del documento en la que lo hagamos La pondremos en este nuevo script PHP //--> <?php function a1(){ for($i=1;$i<=10;$i++){ echo $i,"<br>"; } } ?>
ejemplo156.php

mbito de las variables


Resumamos lo ya comentado cuando tratamos el tema de las variables. Las funciones no leen valores de variables definidas fuera de su mbito salvo que dentro de la propia funcin se definan de forma expresa como globales. Si una funcin modifica el valor de una variable global, el nuevo valor persiste despus de abandonar la funcin.

Si dentro de una funcin se utiliza un nombre de variable idntico al de otra externa a ella (sin definirla global) la nueva variable se inicia con valor nulo y los eventuales valores que pudiera ir conteniendo se pierden en el momento en que se acaba su ejecucin.

<?php # definamos dos variables y asignmosles un valor $a=5; $b=47; # escribamos una funcin a1 y pidmosle que imprima sus valores function a1(){ @print "Este es el valor de $a en la funcin a1: ".$a."<br>"; @print "Este es el valor de $b en la funcin a1: ".$b."<br>"; } # hagamos una llamada a la funcin anterior # no nos escribir ningn valor porque esas variables no pertenecen # al mbito de la funcin y sern consideradas como vacas # en el mbito de la funcin a1(); # escribamos una nueva funcin, definamos como global $a # y comprobemos que ahora si la hemos incluido en el mbito # de la funcin function a2(){ global $a; @print "Este es el valor de $a en la funcin a2: ".$a."<br>"; @print "Este es el valor de $b en la funcin a2: ".$b."<br>"; } # invoquemos esta nueva funcin y veamos que ahora # si se visualiza el valor de $a pero no el de $b a2(); # creemos una nueva funcin y ahora modifiquemos dentro de ella # ambas variables function a3(){ global $a; $a +=45; @$b -=348; echo "Este es nuevo valor de $a en la funcin a3: ",$a,"<br>"; echo "Este es el valor de $b en la funcin a3: ",$b,"<br>"; } # invoquemos la funcin a3 a3(); # comprobemos -desde fuera del mbito de la funcin # que ocurri con los valores de las variables echo "El valor de $a HA CAMBIADO despues de ejecutar a3 es: ",$a,"<br>"; echo "El valor de $b NO HA CAMBIADO despues de ejecutar a3 es: ",$b,"<br>"; # probemos que ocurre con una variable superglobal # veremos que sin ser definida expresamente en a4 # si pertenece a su mbito y por lo tanto visualizamos su contenido function a4(){ print "La superglobales si estn: ".$_SERVER['SERVER_NAME']."<br>"; } # invoquemos esta nueva funcin a4(); ?>
ejemplo157.php

Asignacin de valores a variables


A las variables no globales se les pueden asignar sus valores iniciales de dos formas: Incluyndolas en una lnea de instrucciones contenida en la propia funcin.

Insertando los nombres de variable y sus valores dentro del parntesis que de forma obligatoria debe seguir al nombre de la funcin. En este ltimo caso la sintaxis sera: function nombre_funcion ($variable1=valor1,$variable2=valor2)

donde $variable1 y $variable2 son nombres de variables a utilizar en el mbito de la funcin y valor1 y valor2 los valores asignados a cada una de ellas. En este parntesis pueden incluirse separndolas con comas cuantas parejas variable = valor sean necesarias. Una forma alternativa a la anterior sera la siguiente: function nombre_funcion ($variable1,$variable2)

que requerira asignar los valores de cada una de la variables desde la llamada a la funcin, que ahora deber tener esta sintaxis: nombre (valor1, valor2,...);

y donde habra que escribir los valores separados por comas, y encerrados entre comillas cuando se trata de variables alfanumricas. Si el nmero de valores contenidos en la llamada fuera mayor que el nmero de variables definidas en la funcin, los excedentes seran ignorados y, si fuera inferior, se asignara valor nulo a las variables a las que no se transfiriera ningn valor. Tambin es posible incluir en la llamada a la funcin los nombres de algunas variables definidas en el mbito externo a la funcin. Se hara de la siguiente forma: nombre ($var1, $var2,...);

<?php $a=-13; $b=7482; $c="Ambrosio"; # esta es una forma alternativa de asignar valores a una variable # del mbito de la funcin function a1($a=56, $b=25){ echo "El valor de $$a en la funcin a1: ", $a,"<br>"; echo "El valor de $$b en la funcin a1: ", $b,"<br>"; } a1(); echo "El valor de $a despues de ejecutar la funcin es: ",$a,"<br><br>";

# Pasando valores desde la llamada a la funcin # /* Definamos una funcin fun1 e incluyamos dentro de su parntesis nombres de variables, separados por comas pero ahora sin asignarles ningn valor */ function fun1($x,$y,$z){ print "Valor de la variable x: ".$x."<br>"; print "Valor de la variable y: ".$y."<br>"; print "Valor de la variable z: ".$z."<br>"; }

# debemos hacer la llamada a la funcin pero ahora # lo haremos de forma distinta.

# Vamos a incluir en la llamada # los valores que queremos asignar a las variables de la funcin # Escribiremos dentro del parntesis de la llamada # los valores de cada una de las tres variables # separados por comas # (si se trata de una cadena, pongmosla entre comillas) # y veremos con la funcin recoge esos valores asignados #en la llamada fun1(14,"Robustiano",23.4); /* si esta llamada contuviera ms de tres valores los ltimos serian ignorados */ fun1(49.3,"Eustaquio",78,"Lupicio",456); # si contuviera menos de tres valores # PHP nos dara un mensaje de error # advirtiendo que falta un valor # pero nos devolvera los valores fun1("Desiderio","Bailador"); # esos mensajes de error podramos evitarlos # poniendo una arroba delante de la llamada a la funcin @fun1("Nuevo Desiderio","Nuevo Bailador"); # tambin podra utilizarse una sintaxis como esta # en la que dejamos en blanco (entre comillas) # el espacio correspondiente al segundo valor # aunque si incluimos las comas. # La variable que ocupa esa posicin # sera considerada como nula fun1("La luna",'',"verde"); # tambin podramos incluir en la llamada nombres de variables # definidas en el mbito general del sript # un este caso la funcin usaria esos valores fun1($a,$b,$c); ?>
ejemplo158.php

Pasar por referencia


Tal como hemos visto, las funciones PHP pueden recibir valores de variables externas y utilizar esos valores sin que el valor original de las mismas salvo que se les asigne la condicin de globales dentro de la funcin sufra modificacin. Una manera de lograr que los valores de una variable externa puedan ser modificados por una funcin, es lo que se llama en argot informtico pasar variables por referencia. La forma de hacerlo es esta: Hay que anteponer al nombre de la variable el smbolo & y PHP interpretar que la estamos pasando por referencia. El & puede anteponerse tanto en la definicin de la funcin como en la llamada a la funcin, tal como puedes ver en el ejemplo. La segunda de las opciones nos concede mayor libertad dado que permite usar una sola funcin y decidir en cada llamada la forma de pasar los parmetros.

<?php $a=3; $b=2; function a1($a,$b){

$a=pow($a,2); $b=pow($b,3); echo "El cuadrado de a dentro de la funcin es: ",$a, "<br>"; echo "El cubo de b dentro de la funcin es: ",$b, "<br><br>"; } a1($a,$b); echo "Al salir de la funcin a conserva la modificacin: ",$a, "<br>"; echo "Por el contrario, b no la conserva: ",$b, "<br><br>"; $c=8; $d=12; function b1($a,$b){ $a=pow($a,2); $b=pow($b,3); echo "El cuadrado de a dentro de la funcin es: ",$a, "<br>"; echo "El cubo de b dentro de la funcin es: ",$b, "<br><br>"; } b1(&$c,$d); echo "Al salir de la funcin c conserva la modificacin: ",$c, "<br>"; echo "Por el contrario, d no la conserva: ",$d, "<br><br>"; ?>

ejemplo159.php

Cuidado! Si tratas de ejecutar una funcin en la que colocas el & en la llamada a la funcin y te aparece un mensaje como este: Warning: Call-time pass-by-reference has been deprecated -argument passed by value; If you would like to pass it by reference, modify the declaration of function(). If you would like to enable call-time pass-by-reference, you can set allow_call_time_pass_reference to true in your INI file. lo que estar ocurriendo es que php.ini tiene configurada en Off la directiva allow_call_time_pass_reference Eso suele ocurrir con algunos hostings y tambin con la configuracin por defecto de algunas versiones de PHP. A partir de la versin 5.3.3 este mensaje sustituye Warning por Deprecated con lo cual nos advierte de que se trata de un funcin que se queda obsoleta y que, probablemente, ser desactivida en versiones posteriores de PHP. La manera de evitar esa advertencia es no incluir en smbolo & en la llamada a la funcin.

Otra forma de definir funciones de usuario


Existe otra opcin de definicin de funciones de usuario que puede resultar de mucho inters. En este caso la funcin se define en tres bloques: Definicin de la funcin, llave de apertura { y cierre del script PHP (?>). Contenido de la funcin formado exclusivamente por cdigo HTML que ser incluido en el documento cuando sea invocada la funcin que lo contiene. Cierre de la funcin (llave de cierre }) contenido en un script PHP, es decir, entre las etiquetas de apertura (<?php) y cierre (?>) de un script de PHP. Cuando es invocada una funcin definida de esta forma puedes verlo en el ejemplo PHP se limita a escribir en el documento final los textos contenidos entre la etiqueta de apertura y cierre de la funcin. Las funciones de esta forma son particularmente tiles para la construccin de espacios web que contienen una serie de pginas en las que se repiten las mismas estructuras.

<?php function Encabezado() { ?> <!-- Hemos abierto la funcin y cerrado la etiqueta PHP todo esto es cdigo HTML //--> <html> <head> <title>Titulo de mi pgina</title></head> <body bgcolor="#FF0000"> <!-- Esta nueva llamada a PHP insertando la llave de cierre de la funcin indicar a PHP que debe escribir todo lo contenido entre la { y esta } //--> <?php } ?> <?php function Pie() { ?> <HR> </body> </html> <?php } ?> <!-- Utilizaremos esas dos funciones para crear una pgina web. Llamamos a la funcin Encabezado luego escribimos un texto y por ltimo insertamos el Pie de pgina con la funcin Pie //--> <?php Encabezado(); ?> Este es texto que aparecer en el cuerpo de la pgina. Est fuera de los scripts de php y ser considerado como un texto HTML. Debajo aparecer la lnea horizontal que insertaremos mediante una nueva llamada a la funcin Pie <?php Pie(); ?>
ejemplo160.php

Funciones que devuelven valores Funciones que devuelven valores


Las funciones PHP pueden ser llamadas a partir de un script y posteriormente recoger en ese mismo script los resultados de su ejecucin. Para conseguir este resultado debemos escribir dentro de la funcin la instruccin return seguida de la variable o la instruccin cuyo resultado queremos que sea devuelto al script desde el que ha sido llamada la funcin. Tal como podemos ver en el ejemplo, los valores devueltos por return pueden ser presentados directamente en la pgina o recogidos por una variable. Tambin es posible que la funcin genere un array y que este sea devuelto a una variable que se convertira a ese tipo de forma automtica. Otra opcin de recoger los valores devueltos por return es invocar la funcin mediante una llamada del tipo: list(v1, v2,..)=llamada

Las variables v1, v2, etc. recogern los valores de los elementos del array devuelto por la funcin.

<?php # asignamos valores a dos variables $a=3; $b=5; # escribimos una funcin que eleva la variable a # a la potencia indicada en b # insertando return delante de la operacin

function a1($a,$b){ return pow($a,$b); } #incluimos en la instruccin echo una llamada # a la funcin y en ella pasamos los valores # recogidos en las variables a y b # return conseguir que se ejecute esa funcin # y que echo recoja e imprima el resultado echo "El valor de a elevado a b es: ",a1($a,$b),"<br>"; # esta otra funcin generar y devolver un array # con los resultados de la ejecucion del bucle for function a2($a,$b){ for ($i=0;$i<=$b;$i++){ $z[]=pow($a,$i); } return $z; } # hacemos una llamada a la funcin $p=a2($a,$b); # leemos el array devuelto desde fuera de la funcin foreach($p as $clave=>$valor){ echo "El valor de a (3) elevado a: ",$clave," es: ",$valor,"<br>"; } echo "<br>"; # otra forma de leer el array con los resultados de la funcin list($r,$s,$t)=a2($a,$b); echo "Este es el valor recogido en la variable r :",$r,"<br>"; echo "Este es el valor recogido en la variable s :",$s,"<br>"; echo "Este es el valor recogido en la variable t :",$t,"<br>"; ?>
ejemplo161.php

Funciones de fecha Funciones de fecha


PHP es prdigo en cuanto a posibilidades de manejo de fechas y horas. Para ello, cuenta, entre otras, con las siguientes funciones: date (cadena de formato)

Devuelve valores de fecha y hora actuales utilizando los parmetros que se sealan en la tabla para establecer el formato de salida de los datos. Dentro de la misma cadena de formato puede contener tantos parmetros como se deseen. Parmetros de formato de date()
Valor Funcionalidad Sintaxis Resultado

A a d j F M m n

AM-PM am-pm Da del mes en formato de 2 dgitos da del mes sin ceros a la izquierda Nombre del mes (texto completo) Nombre del mes (3 letras) N del mes (de 01 a 12) con dos dgitos N del mes (de 1 a 12) sin dos dgitos

date("A") PM date("a") pm date("d") 06 date("j") 6

date("F") June date("M") Jun date("m") 06 date("n") 6

Y y G H g h i s l D w z t L Z U S

Ao con cuatro dgitos Ao con dos dgitos Hora 0-23 sin ceros a la izquierda Hora 0-23 con dos dgitos Hora 1-12 sin ceros a la izquierda Hora 01-12 con dos dgitos Minutos de 00 a 59 con dos dgitos Segundos de 00 a 59 con dos dgitos da semana en texto completo Da de la semana (tres letras)

date("Y") 2012 date("y") 12 date("G") 18 date("H") 18 date("g") 6 date("h") 06 date("i") 12

date("s") 38 date("l") Wednesday

date("D") Wed

da semana de 0 (domingo) a 6 (sabado) date("w") 3 das transcurridos del ao actual Nmero de das mes actual Ao actual bisiesto (1), no bisiesto (0) Diferencia (seg.) horaria local con GMT Segundos Unix Epoch Sufijo ordinal ingls date("z") 157 date("t") 30

date("L") 1 date("Z") 7200 date("U") 1338999158 date("S") th

Como puedes ver en este ejemplo, respeta los caracteres separadores (espacios, dos puntos, guiones, etctera) que se hubieran incluido en la cadena de formato siempre que no coincidan con ninguno de los parmetros PHP para esta cadena. <?php echo "Son las ", date("h : i : s")," y hoy es ", date("j-n-Y")?> devolvera: Son las 06 : 12 : 38 y hoy es 6-6-2012

Cuidado! No olvides que PHP se ejecuta en el servidor que suele estar en un ordenador remoto. Por lo tanto, fecha y hora locales se refieren al lugar donde est instalado el servidor y que en nuestro caso servidor y cliente coinciden en un mismo equipo y coincidirn la hora del sistema con la del servidor. Pero si alojaras esta pgina en un hosting australiano, PHP nos devolvera los valores con hora y fecha de lasantpodas.
date (formato, nmero)

Esta funcin nos devuelve la fecha y hora del tiempo Unix indicado en el parmetro nmero. Recuerda que ese nmero indicasegundos contados a partir de la 0:00:00 (GMT) del da 1 de Enero de 1970. Este script devolver la fecha y hora en la que el tiempo Unix era de 456.573.426 segundos. <?php echo "Fu a las ", date("h:i:s",456073426)," del ", date("j-n-Y",456073426) ?> devolvera: Fu a las 05 : 03 : 46 del 14-6-1984 gmdate(cadena formato)

Se comporta de forma idntica a date() con la nica diferencia de que devuelve la hora y fecha GMT. Si te fijas en el ejemplo habr una o dos horas de diferencia segn accedas a esta pgina en verano o invierno. La fecha actual en hora GMT (observa la diferencia horaria): <?php echo "Son las ", gmdate("h : i : s")," y hoy es ", gmdate("j-n-Y")?> devuelve: Son las 04 : 12 : 38 y hoy es 6-6-2012 gmdate (formato, nmero)

Los mismos comentarios que con el caso anterior. La nica diferencia es que devuelve hora GMT. La fecha y hora GMT coincidente con el tiempo Unix 456.073.426 es: <?php echo "Fu a las ", gmdate("h:i:s",456073426)," del ", gmdate("j-n-Y",456073426) ?> devolvera: Fu a las 03 : 03 : 46 del 206-1984 checkdate(mes,da,ao)

Comprueba si los valores de los parmetros mes estn dentro del rango permitido (de 1 a 12), si el parmetro da es un valor vlido para ese mes (considera aos bisiestos) y si el valor del ao pertenece al rango 0 a 32767. Devuelve VERDADERO si los valores corresponden a una fecha correcta y FALSO en el caso de que no ocurra as. Ejemplos de checkdate()
Mes Da Ao Sintaxis Devuelve

10 32 1987 Checkdate(10,32,1987) 10 31 1987 Checkdate(10,31,1987) 1 2 2 gettimeofday() 29 2000 Checkdate(2,29,2000) 29 2001 Checkdate(2,29,2001)


1

Esta funcin devuelve un array asociativo con los siguientes ndices: sec El valor asociado a este ndice del array recoge la hora actual (Unix Each) expresada en segundos usec El valor asociado a usec recoge la fraccin en microsegundos de hora actual (Unix Each) minuteswest Devuelve los minutos al Oeste de Greenwich dsttime Devuelve el tipo de correccin horaria segn horarios de verano/invierno. El valor UNO corresponde a horario de verano, el valor CERO al de invierno y MENOS UNO en el caso en que sea desconocido. Ejemplos de gettimeofday()
Sintaxis $z= gettimeofday(); echo $z; echo $z['sec']; echo $z[usec]; echo $z['dsttime']; Devuelve Array 1338999158 727356 1

echo $z['minuteswest'']; -120

getdate()

Devuelve un array asociativo con parmetros de la fecha actual. Los ndices de este array y sus valores son los que puedes ver en la tabla. Ejemplos de getdate()
Funcionalidad Devuelve un array asociativo Sintaxis $s=getdate(); Devuelve Array

echo $s; Este ndice devuelve los segundos de la hora actual echo $s['seconds'] 38 Este ndice devuelve los minutos de la hora actual Este ndice devuelve la hora de la hora actual Este ndice devuelve el da del mes actual Este ndice devuelve el n del da de la semana Este ndice devuelve el n del mes Este ndice devuelve el ao Este ndice devuelve n del da en el ao actual Este ndice devuelve el da de la semana Este ndice devuelve el nombre del mes echo $s['minutes'] 12 echo $s['hours'] echo $s['mday'] echo $s['wday'] echo $s['mon'] echo $s[year] echo $s['yday'] echo $s['month'] 18 6 3 6 2012 157 June

echo $s['weekday'] Wednesday

getdate(nmero)

Interpreta el nmero como una fecha Unix Each (segundos transcurridos desde el da 1 de Enero de 1970) y devuelve un array asociativo con los valores relativos a esa fecha. Los ndices de este array y sus valores son idnticos a los de getdate() tal como puedes ver en esta tabla. Ejemplos de getdate(nmero)
Funcionalidad Devuelve un array asociativo Sintaxis Devuelve $s=getdate(127648); Array echo $s; 28 27 12 2 5 1 1970 1 Friday January echo $s['minutes'] echo $s['hours'] echo $s['mday'] echo $s['wday'] echo $s['mon'] echo $s['year'] echo $s['yday'] echo $s['weekday'] echo $s['month']

Este ndice devuelve los segundos de la hora actual echo $s['seconds'] Este ndice devuelve los minutos de la hora actual Este ndice devuelve la hora de la hora actual Este ndice devuelve el da del mes actual Este ndice devuelve el n del da de la semana Este ndice devuelve el n del mes Este ndice devuelve el ao Este ndice devuelve n del da en el ao actual Este ndice devuelve el da de la semana Este ndice devuelve el nombre del mes

time()

Esta funcin devuelve la hora actual en segundos expresada en tiempo Unix. <?php print "Han transcurrido ".time(). " segundos desde las cero horas del da 01-01-1970";?> devolvera: Han transcurrido 1338999158 segundos desde desde las cero horas del da 01-01-1970 microtime()

Esta funcin devuelve una cadena formada la fraccin de microsegundos de la hora actual expresada en tiempo Unix seguida de un espacio y de los segundos del tiempo Unix. <?php print "Estamos en la fraccin ".microtime(). " de segundo de la hora actual";?> devolvera: Estamos en la fraccin 0.72747400 1338999158 de segundo de la hora actual mktime (hora, minuto, segundo, mes, da, ao)

Devuelve el tiempo Unix de la fecha pasada como parmetro a la funcin. Es fundamental mantener la secuencia de los datos. Si se omiten argumentos (slo pueden omitirse por la derecha) tomar los de la fecha actual.

Cuando el parmetro da es cero devuelve el ltimo da del mes anterior, pero si pasamos cero como parmetro de mes nos dar un error. Ejemplos de mktime()
H Min Sec Mes Da Ao Tiempo Unix Fecha

23 12 57 6 23 12 57 6 25 12 57 6 23 97 57 6

16 1973 109116777 23:12:57 16-Jun-1973 16 1973 109116777 23:12:57 16-Jun-1973 16 1973 109123977 01:12:57 17-Jun-1973 16 1973 109121877 00:37:57 17-Jun-1973 1973 128902377 23:12:57 31-Jan-1974

23 12 57 14 16 1973 130284777 23:12:57 16-Feb-1974 23 12 57 14 0

En los ejemplos de esta tabla puede verse cmo para valores fuera de rango (mes mayor de 12, minutos mayor de 60, etctera) la funcin realiza la correccin correspondiente.

Cuidado! En versiones anteriores a PHP 5.3.3 la funcin mktime inclua un sptimo parmetro (que se agregaba detrs de valor ao) relativo a horarios de verano invierno. Ese parmetro era 0 si la fecha corresponde a horario de invierno y 1 -1 (segn versiones) en el caso de horario de verano. Actualmente esa opcin es considerada obsoleta por PHP. Por esta razn no usamos ese sptimo parmetro en nuestros ejemplos.

Funciones de calendario Los distintos calendarios


Das julianos
El sistema de das julianos fue creado por Joseph Justus Scaliger en 1582 y fue llamado as en recuerdo de su padre, Julius Cesar Scaliger. Se trata de un sistema de cuenta de das que tiene su origen en el 1 de Enero del ao 4713 a.C. y que acabar el 31 de Diciembre de 3267. Este ciclo es producto de multiplicar tres ciclos menores: uno de 28 aos denominado solar, otro de 19 aos, que incorpora las fases lunares y uno de 15 aos denominado de indiccin. El da juliano es el nmero resultante de contar los das transcurridos desde la fecha definida por Scaliger como comienzo del ciclo.

Calendario juliano
El emperador romano Julio Cesar orden en el ao 44 a.C. la reforma del calendario. Sustituy el lunar adoptando, con modificaciones, uno solar de origen egipcio que data del 4000 a.C. Con la asesora de Sosgenes de Alejandra fij la duracin de cada ao en 365,25 das, insertando un da suplementario en febrero cada cuatro aos, -bis sextus dies ante calendas Martii(dos sextos das antes de las calendas de marzo), haciendo bisiestos a todos los aos cuyo nmero de orden sea divisible por cuatro.

Calendario gregoriano
A lo largo la Edad Media se sigui manteniendo en gran parte de Europa el calendario juliano con la nica adaptacin de fijar la fecha de referencia de la cuenta de aos en el nacimiento de Cristo. Pero dado que la duracin real del ciclo de translacin de la tierra alrededor del sol es de 365,2422 das solares medios, el calendario juliano con aos de 365,25 das empezaba a acumular un error importante. El Papa Gregorio XIII realiz la correccin en el ao 1582. Se descontaron diez das y es por eso que en 1582, al cuatro de octubre le sigui el da quince (viernes).

Para evitar sucesivos desfases se modificaron las condiciones de los aos bisiestos que, en lo sucesivo, habran de cumplir la condicin de que su ordinal sea divisible por 4 y que no acabe en 00 con la excepcin de los mltiplos de 400 que tendran condicin bisiestos.

Calendario judo
La era juda comienza a contar desde un supuesto ao de la creacin del mundo, que se calcula sumando las edades de las distintas generaciones mencionadas en la Biblia. El ao judo se corresponde con el cristiano sumndole a ste 3.760 aos. El ao judo es solar como el cristiano, pero sus meses son lunares, por lo que cada dos o tres aos tiene que aadirse un mes bisiesto para adecuar al ao solar el cmputo de los meses lunares.

Calendario republicano francs


El Calendario Republicano fue adoptado por la Convencin Francesa partiendo de las propuestas tcnicas formuladas por el matemtico Lagrange. Es un intento de adaptar el calendario al sistema decimal y eliminar referencias religiosas. El comienzo del ao coincida con el da 22 de Septiembre, equinoccio de otoo, y se fij su da uno del ao uno el 22 de Septiembre de 1792, da de la proclamacin de la Repblica. Consta 12 meses de 30 das, a los que se aaden cinco das complementarios (seis en los aos que son divisibles por 4 y no por 100) que son festivos y no se asignan a ningn mes. Los meses se dividen en tres dcadas de 10 das. El calendario fue de aplicacin civil en Francia y sus colonias americanas y africanas hasta 1806.

Funciones PHP para el manejo de calendarios


PHP dispone de una serie de funciones que permiten convertir fechas segn los distintos calendarios. Son estas: gregoriantojd(mes,da,ao)

Realiza la cuenta de das julianos correspondiente a la fecha gregoriana pasada en los parmetros mes, da y ao. El script <?php echo gregoriantojd (9, 27, 1999) ?> nos devolver: 2451449 que es el da juliano correspondiente a la fecha gregoriana:27 de setiembre de 1999. Este otro script <?php echo gregoriantojd (date("n"), date("j"), date("Y")) ?> nos devolver el da juliano correspondiente a la fecha actual. As que, para tu conocimiento y efectos pertinentes, hoy da 6 -6-2012 estamos celebrando el da juliano nmero 2456085. jdtogregorian(n de das julianos) Esta funcin devuelve en fecha gregoriana con formato: mes, da y ao el da juliano pasado como parmetro. Por si quieres ir preparando las celebraciones del 2.500.000 da juliano debes saber que coincidir con la fecha 8/31/2132 jdtojulian(n de das julianos) Con esta funcin puedes obtener la fecha juliana a partir de un valor de la Cuenta de Das Juliana . Este script <?php echo jdtojulian(gregoriantojd (date("n"), date("j"), date("Y"))) ?> nos devuelve la fecha actual segn el calendario julianoque es 5/24/2012 segn el calendario juliano. juliantojd(mes,da,ao) Convierte a Cuenta de das Julianos la fecha pasada (mes, da y ao) del calendario juliano. Por ejemplo <?php echo juliantojd(7,25,2011) ?> nos devolver 2455781 que corresponde a la cuenta de das correspondiente a la fecha 25/7/2001 expresada segn el calendario juliano. jdtojewish(n de das julianos)

Esta funcin nos devuelve la fecha (mes, da y ao) segn el calendario judo a partir de una fecha expresada en das julianos. <?php echo jdtojewish (gregoriantojd (date("n"), date("j"), date("Y"))) ?> nos dar la fecha actual segn el calendario judo que es: 10/16/5772. jewishtojd(mes,da,ao) Nos devuelve el da juliano correspondiente a una determinada fecha del calendario judo. Por ejemplo: <?php echo jdtogregorian(jewishtojd(7,21,5758)) ?> nos devolver 3/19/1998 que es la fecha gregoriana correspondiente al da 21 del sptimo mes del ao 5758 segn el calendario judo. jdtofrench(n de das julianos) Esta funcin nos devuelve la fecha segn el calendario republicano francs correspondiente al da juliano especificado como parmetro. <?php echo jdtofrench (gregoriantojd (5, 7, 1796)) ?> nos dar la fecha del calendario republicano francs que se corresponde con el 7 de Mayo de 1796 (gregoriano) que segn parece es: 8/18/4. Slo convierte fechas comprendidas entre los aos 1 y 14 (fechas Gregorianas del 22 de septiembre de 1792 al 22 de septiembre de 1806) que se corresponden con el perodo de vigencia oficial de este calendario. frenchtojd(mes,da,ao) Convierte una fecha del calendario republicano francs en su equivalente en das julianos. Por ejemplo: <?php echo jdtogregorian(frenchtojd(6,7,8)) ?> nos devolver 2/26/1800, que es la fecha gregoriana correspondiente al da 7 del sexto mes del ao 8segn el calendario republicano francs. Igual que la funcin anterior slo convierte fechas comprendidas entres los aos 1 y 14 del calendario francs. jdmonthname(da juliano, calendario) Devuelve del nombre del mes correspondiente al da juliano en el calendario sealado. Ejemplos de jdmonthname()
Fecha Gregoriano Juliano Gregoriano Juliano gregoriana abreviado abreviado 3/1/1803 3/2/1803 3/3/1803 3/4/1803 3/5/1803 3/6/1803 3/7/1803 3/8/1803 3/9/1803 Jan Feb Mar Apr May Jun Jul Aug Sep January February March April May June July August October Dec Jan Feb Mar Apr May Jun Jul Sep January February March April May June July August October Judo Republicano francs Nivose Pluviose Ventose Germinal Floreal Prairial Thermidor Fructidor Vendemiaire Frimaire

December Tevet Shevat AdarI Nisan Iyyar Sivan Av Elul

Tammuz Messidor

September Aug November Oct December Nov

3/10/1803 Oct 3/11/1803 Nov 3/12/1803 Dec Parmetro 0 calendario

September Tishri November Kislev

Heshvan Brumaire

Los parmetros sealados en la fila inferior son los correspondientes a los tipos de nombres de mes sealados en los encabezados de la tabla.

Da de Pascua
El Da de Pascua fue fijado en el Concilio de Nicea (ao 325) como el domingo siguiente a la primera luna llena posterior al equinoccio de Primavera. Este equinoccio se supone que siempre coincide con el 21 de marzo.

El algoritmo que usa PHP para su clculo se basa en el que desarroll Dionisio Exiguo en el ao 532. Para los aos anteriores a 1753, (calendario Juliano) usa un ciclo simple de 19 aos para calcular las fases de la luna. En los aos posteriores a esa fecha (Calendario Gregoriano) se aaden dos factores de correccin que tratan de hacer ese ciclo ms preciso. Mediante la funcin: easter_date(ao) Devuelve -en tiempo Unix- la media noche del da de Pascua del ao establecido como parmetro. Esta funcin slo es vlida cuando los valores del ao estn comprendidos entre 1970 y 2037 (tiempo UNIX). El script echo date( "j-n-Y", easter_date(2011)) nos seala que la Pascua del ao 2006 ha sido el da 24-4-2011. easter_days(ao) Devuelve el nmero de das del perodo comprendido entre el 21 de marzo y el da de Pascua. Si no se especifica el ao, se asume el actual. No tiene las limitaciones de la funcin anterior y es aplicable a aos fuera del intervalo de tiempo UNIX. El script easter_days(2011) nos seala que la Pascua del ao 2011 ha sido 34 das despus del 21 de Marzo.

Cuidado! Si piensas en la posibilidad de utilizar estas funciones en alguna aplicacin concreta que pretendas publicar en unhosting de la red cercirate antes de que estn habilitadas.

La opcin INCLUDE Utilizacin de ficheros externos


PHP dispone de funciones que permiten insertar en un documento una parte o la totalidad de los contenidos de otro. Esta opcin resulta muy interesante, tanto desde el punto de vista operativo como en lo relativo a la seguridad. Estos son algunos de los recursos que permiten ese tipo de inclusiones: include("nombre del fichero")

El parmetro nombre del fichero es una cadena que contiene el path y el nombre del fichero cuyos contenidos pretendemos incluir. Pueden incluirse ficheros con cualquier extensin aunque es muy habitual utilizar archivos con extensin .inc.php. La primera parte (inc) nos permitir identificar este tipo de ficheros mientras que la extensin php obligara a que (si un usuario malicioso pretende visualizar el contenido del fichero) fuera interpretado por PHP y, como consecuencia de ello, solo devolvera el resultado sin permitir la visualizacin de informaciones privadas (contraseas por ejemplo) que pudiera contener. Este primer ejemplo de fichero a incluir contiene nicamente texto y etiquetas HTML pero no contiene ninguna llamada a ninguna funcin PHP, ni tampoco ningn script de este lenguaje. Lo hemos guardado con dos extensiones: ejemplo1.inc.php y ejemplo1.inc. Si pulsas sobre las opciones Ver ejemplo podrs comprobar que los resultados de visualizacin son distintos dependiendo de la extensin de cada fichero.

<h3><font color="#ff0000">Este sera un texto que se incluira dentro de la pgina mediante las funciones include o require</font></h3><br>
Ver ejemplo1.inc Ver ejemplo1.inc.php

Este tipo de ficheros pueden contener: texto, etiquetas HTML y funciones. Si no contiene funciones se podr insertar tantas veces como se invoque y se insertar, adems, todo su contenido tal como puedes ver en el ejemplo.

Si el fichero contiene funciones solo podr ser invocado una vez ya que si se hiciera una segunda llamada se producira un error por duplicidad en los nombres de las funciones. Como vers en el ejemplo, es posible incluir cualquier tipo de funciones tanto las de la forma: <?php function nombre { ?> ..... ... cdigo HTML ... ...... <?php } ?>

con las que se pueden incluir porciones de cdigo HTML en cualquier script, como las del tipo: function nombre { ..... ... instrucciones PHP ... ...... }

que permiten invocar funciones repetitivas a partir de cualquier documento PHP.

<?php function Encabezado() { ?> <html> <head> <title> Pruebas con la funcin include </title> </head> <BODY> <center><img src="./images/cabina.jpg"><br> <font size=6 face="Times" color="#0000ff">Pruebas PHP</font><br> <hr width=75%> <?php } ?> <?php function Pie() { ?> <center><hr width=50%> <font size=2 face="Arial" color="#ff0000">Luchando con PHP</font> <hr width=50%></center> </body> </html> <?php } ?> <?php } ?>
Ver ejemplo2.inc Ver ejemplo2.inc.php

function Calcula($a,$b) { return $a*$b;

Definidas las funciones en el fichero a incluir y colocado al comienzo de la pgina un script que contenga el include y la ruta de ese fichero, bastar con invocar cualquiera de las funciones, en cualquier punto del documento, para que esa llamada sea sustituida por el resultado de la ejecucin de la funcin. Como es lgico, solo sern visualizados en el navegador del cliente los resultados de la ejecucin de las funciones que hayan sidoinvocadas.

<!-- empezaramos incluyendo el fichero que contiene las funciones. No escribira nada hasta que las funciones que contiene no fueran invocadas //-->

<?php include("ejemplo2.inc.php") ?> <!-- Insertaremos un script PHP que invoque la funcin encabezado. Debe llevar las etiquetas de apertura y cierre <?php y ?> de PHP //--> <?php Encabezado() ?> <!-- Insertaremos cdigo HTML segn nuestra conveniencia //--> Aqu ira el contenido de la pgina<br> .... esto es texto HTML................<br> ...........................<br><br><br> <!-- Incluimos el fichero ejemplo1.inc.php y dado que no contiene ninguna funcin, insertar aqu todo su contenidos //--> <?php include("ejemplo1.inc.php") ?> <!-- Insertaremos ms cdigo HTML --> ....................<br> ...........................<br><br><br> <!-- Incluimos nuevamente el fichero ejemplo1.inc.php Puede repetirse la inclusin porque no contiene funciones, si las contuviera habra un conflicto de duplicidad porque una funcion no puede estar definida dos veces con el mismo nombre. La instruccin include como en todos los casos deber ir dentro de un script PHP y por tanto entre <?php y ?> //--> <?php include("ejemplo1.inc.php") ?> <!-- Ahora ejecutaremos la funcion PHP Calcula() pasando como parmetros 7 y 9. El return de la funcin nos devolver el resultado que imprimiremos aqu //--> <?php print "Aqu va el resultado de la multiplicacin: ".Calcula(7,9); ?> <!-- Por ltimo invocaremos la funcin Pie() --> <?php Pie() ?>
Ver ejemplo162.php

La funcin require()
Tiene la misma sintaxis que include y una funcionalidad similar, aunque con algunas diferencias. Igual que ocurra con aqul, cuando un fichero es invocado por require esa llamada lo que hace es sustituirse a s misma por el contenido del fichero especificado. A diferencia de include, la etiqueta require lee y escribe en el documento a partir del que es invocada el archivo referenciado completo y no acepta condicionales que s son aceptados por include.

Evitar errores por duplicidad de llamadas


Tanto en el caso de usar la instruccin include como con require, si se intenta incluir dos o ms veces un fichero que contenga funciones, se producir un error (PHP no permite que dos funciones tengan el mismo nombre) y se interrumpir la ejecucin del script. Los errores de ese tipo pueden evitarse usando las funciones: include_once("fichero") y require_once("fichero")

que a diferencia de include y requiere van a impedir que un mismo fichero pueda incluirse dos veces. En los ejemplos vas a poder comprobar que no aparece el mensaje de error cuando se utiliza esta funcin y que el texto que anteriormente era incluido dos veces ahora solo aparece una vez.

<!-- Repetimos la inclusin de ambos ficheros pero veremos que no aparece mensaje de error por duplicidad de funciones y adems pese a hacer una doble insercin de ejemplo1 solo se visualiza una vez por efecto del filtro establecido por include_onde //--> <?php include_once("ejemplo2.inc.php") ?> <?php Encabezado() ?> Aqu ira el contenido de la pgina<br> ....................<br> ...........................<br><br><br> <?php include_once("ejemplo1.inc.php") ?> ....................<br> no aparecer nada aqu debajo<br><br><br> <?php include_once("ejemplo1.inc.php") ?> <?php include_once("ejemplo2.inc.php") ?>
Ver ejemplo163.php

El resultado de este otro ejemplo es idntico al anterior. Slo hemos sustituido include_once por require_once, que tiene una funcionalidad similar a la anterior.

<?php require_once("ejemplo2.inc.php") ?> <?php Encabezado() ?> Aqu ira el contenido de la pgina<br> ....................<br> ...........................<br><br><br> <?php require_once("ejemplo1.inc.php") ?> ....................<br> ....nada de aqu en adelante ...<br><br><br> <?php require_once("ejemplo2.inc.php") ?> <?php require_once("ejemplo1.inc.php") ?>
Ver ejemplo164.php

Comprobando los ficheros incluidos


PHP dispone de dos funciones que permiten recoger en un array la lista de ficheros que se han insertado en el documento por medio de alguna de las instrucciones: require_once, require, include_once e include. Tales funciones son estas: $v=get_included_files()

Recoge en un array escalar (contenido en la variable $v) los nombres de los ficheros incluidos en el archivo en uso por include_once. $v=get_required_files()

Igual que la funcin anterior recoge en un array escalar (contenido en la variable $v) los nombres de los ficheros incluidos en el archivo en uso mediante require_once.

<?php <?php <?php <?php

include_once("ejemplo2.inc.php") ?> Encabezado() ?> include_once("ejemplo1.inc.php") ?> Pie() ?>

Lista de fichero utilizados por include <?php $z= get_included_files(); foreach($z as $clave=>$valor) { echo "Clave: ",$clave," Valor: ",$valor,"<br>"; }; ?>
Ver ejemplo165.php

Mejorando la seguridad
Hemos hablado de la funcin show_source, que permita visualizar el cdigo fuente de los scripts no solo locales sino de cualquier URL- si esta funcin no estaba desactivada en el php.ini. Esa posibilidad de ver no slo permite el espionaje industrial (ver la tcnica de construccin de los scripts, etctera) sino que permite ver tambin las claves y contraseas de acceso a las bases de datos que pudieran contener los scripts. Aparte de simplificar el trabajo la opcin de incluir ficheros externos permite guardar la informacin confidencial fuera del root del servidor y usarla mediante estas llamadas. De ese modo show_source permitira visualizar el nombre de ese fichero externo pero no su contenido. Si creramos un directorio por ejemplo como subdirectorio de c:\Apache (fuera del root del servidor) y le ponemos como nombre sg, podramos guardar all los ficheros ejemplo2 y ejemplo1, con lo cual sus contenidos no seran visibles con show_source. En este caso la instruccin include ha de contener el path y sera la siguiente: include("C:\Apache\sg\fichero").

Cuidado! La manera de escribir los path difiere de un sistema operativo a otro. Bajo Windows debemos usar \ como separador, mientras que otros S.O. (Unix, Linux, etctera) requieren utilizar /. Para publicar tus pginas en un hosting no Windows tendras que modificar tus scripts. Tenlo en cuenta

Utilizando include para gestin de fechas


Las funciones que incluye PHP para el manejo de fechas solo contemplan periodos posteriores a 1970. Para el caso de fechas anteriores a esta, existen funciones que pueden descargarse desde: http://phplens.com/lens/dl/adodb-time.zip. El archivo comprimido contiene un fichero -adodb-time.inc.php- con funciones PHP que se comportan de forma idntica a las nativas de PHP y que, adems, permiten utilizar fechas anteriores a 1970 y valores negativos del tiempo Unix. Para utilizar estas funciones bastara con poner en el script include("adodb_time.inc.php"); y sustituir las funciones de fecha de acuerdo con lo que se indica en esta tabla:
Funcin PHP Funcin Adodb-time

getdate() date() gmdate() mktime()

adodb_getdate() adodb_date() adodb_gmdate() adodb_mktime()

En este enlace puedes comprobar los resultados de la aplicacin de estas funciones que, como vers, son idnticos a los que

hemos visto en el tema Funciones de fecha con la salvedad de que en este caso se admiten fechas anteriores a 1970 y tiempos Unix negativos.

Manejo de ficheros externos Utilizacin de ficheros externos


PHP dispone de funciones mediante las cuales se pueden crear, modificar, borrar y leer ficheros de cualquier tipo as como extraer informacin sobre ellos y sus contenidos.

Abrir o crear ficheros


Para crear o modificar ficheros se utiliza la instruccin: $f1=fopen(fichero,modo)

dnde $f1 es una variable que recoge el identificador del recurso, un valor importante (ser utilizado para referirnos a este fichero en instrucciones posteriores), fichero es el nombre (con extensin) del fichero a abrir o crear y deber escribirse entre comillas, y modo, que es una cadena que debemos poner entre comillas, el indicador del modo de apertura elegido. En la tabla hemos enumerado las opciones de ese parmetro. Valores del parmetro modo de la funcin fopen
Valor Funcionalidad

r r+ w w+ a a+

Abre el fichero en modo lectura y coloca el puntero al comienzo del fichero Abre el fichero en modo lectura y escritura y coloca el puntero al comienzo del fichero Abre el fichero en modo escritura y coloca el puntero al comienzo del fichero, reduce su tamao a cero y si el fichero no existe intenta crearlo Abre el fichero en modo lectura y escritura y coloca el puntero al comienzo del fichero, reduce su tamao a cero y si el fichero no existe intenta crearlo Abre el fichero en modo escritura y coloca el puntero al final del fichero y si no existe intenta crearlo Abre el fichero en modo lectura y escritura y coloca el puntero al final del fichero y si no existe intenta crearlo

Si el fichero que pretendemos abrir est en un directorio distinto al del script, debe incluirse el path completo delante del nombre del fichero y la cadena resultante debe ir entre comillas.

Cuidado! Si incluimos, junto con el nombre del fichero, un path hay que tener muy presente que bajo Windows hemos de utilizar siempre el separador anti-slash (\).

Cerrar ficheros
Una vez finalizado el uso de un fichero es necesario cerrarlo. Para ello PHP dispone de la siguiente intruccin: fclose($f1)

Esta funcin -que devuelve un valor booleano- permite cerrar el fichero especificado en $f1 que, como recordars, es el valor delidentificador de recurso que le fue asignado automaticamente por PHP en el momento de la apertura.

Punteros internos

PHP dispone de funciones para situar sus punteros internos y tambin para determinar la posicin a la que apuntan en un momento determinado. Se trata de las siguientes: feof($f1)

Es un operador booleano que devuelve CIERTO (1) si el puntero seala el final del fichero y FALSO si no lo hace. rewind($f1)

Coloca el puntero interno al comienzo del fichero indicado por el identificador del recurso $f1. fseek($f1, posicin)

Sita el apuntador del fichero sealado por el identificador del recurso $f1 en la posicin (expresada en bytes) sealada por posicin. ftell($f1)

Devuelve (expresada en bytes) la posicin actual del puntero interno del fichero.

Cuidado! Antes de utilizar funciones es necesario que el fichero que seala el identificador de recursos haya sido abierto.

Lectura de ficheros
La lectura de los contenidos de un fichero puede hacerse de dos maneras: sin apertura previa o con apertura previa del mismo.

Lectura de ficheros sin apertura previa


Las funciones que permiten la lectura de ficheros sin haber sido abiertos previamente son las siguientes: $t=file_get_contents(fichero)

Recoge en la variable $t el contenido del fichero cuyo nombre y eventual ruta se especifican en el parmetro fichero. readfile(fichero)

Escribe directamente en el punto de insercin del script el contenido completo del fichero.

Cuidado! La funcin readfile escribe el contenido del fichero sin necesidad de ir precedido por echo ni print. Si se pone echo o se recoge en una variable, adems de su contenido aadir un nmero que indica el tamao del fichero expresado en bytes.
$var=file(fichero)

Crea $var un array escalar cuyos elementos tienen como valores los contenidos de cada una de las lneas del fichero. Una lnea termina all donde se haya insertado un salto de lnea en el fichero original.

Lectura de ficheros con apertura previa


Para la utilizacin de estas funciones los ficheros han de ser abiertos en un modo que permita la lectura. fpassthru($f1)

Hace la lectura completa del fichero. Esta funcin presenta algunas peculiaridades importantes: Cierra el fichero de forma automtica despus de la lectura. Por esa razn, si se escribe la funcin fclose a continuacin defpassthru, se produce un error. Si el resultado se recoge en una variable, o si va precedido de echo, adems de escribir el contenido del mismo, aadir el nmero de bytes que indican su tamao. fgets($f1,long)

Extrae del fichero sealado por el $f1 una cadena que comienza en la posicin actual del puntero y cuya longitud est limitada por el menor de estos tres valores: El valor (en bytes) indicado en long. La distancia (tambin en bytes) desde la posicin actual del puntero hasta el final del fichero. La distancia que hay entre la posicin actual del puntero y el primer salto de lnea. fgetc($f1)

Extrae el caracter siguiente al sealado por la posicin actual del puntero.

Escribir en un fichero
Una vez abierto un fichero -en modo que permita escritura- la funcin PHP que nos permite escribir en el es la siguiente: fwrite($f1,"texto",long)

donde: $f1 sigue siendo el identificador de recurso, texto la cadena de texto a insertar en el fichero y long el nmero mximo de caracteres que han de insertarse. Si la cadena de texto tiene menor o igual longitud que el parmetro long la escribir en su totalidad, en caso contrario slo escribir el nmero de caracteres indicados. fputs($f1,"texto",long)

Es un alias de la funcin anterior. file_put_contents(nombre_fichero,$cadena)

Crea un fichero cuya ruta, nombre y extensin se definen mediante la cadena nombre_fichero e incluye en l el contenido de la variable$cadena. Esta funcin es idntica a llamar a fopen(), fwrite() y fclose() sucesivamente para escribir informacin en un archivo.

Cuidado! Estas funciones realizan la insercin de la cadena a partir de la posicin a la que apunte el puntero en el momento de ser invocadas. Si el fichero ya existiera y contuviera datos los nuevos datos se sobrescribiran sobre el contenido anterior. Para poder aadir contenidos a un fichero el puntero deber apuntar el final del fichero preexistente y estar abierto en un modo que permita aadir contenidos.

Borrado de ficheros
Para borrar ficheros se utiliza la siguiente instruccin: unlink(fichero)

Dnde fichero ha de ser una cadena que contenga el nombre y la extensin del fichero y, en su caso, tambin el path.

Duplicado de ficheros
La funcin: copy(fichero1, fichero2)

Copia el fichero fichero1 (debe indicarse nombre y extensin) en otro fichero cuyo nombre y extensin se establecen en la cadenafichero2. Esta funcin devuelve un valor booleano indicando si la copia se ha realizado con xito TRUE (1) o FALSE (nul) si por alguna razn no ha podido realizarse la copia.

Renombrar ficheros
La funcin: rename(fichero1, fichero2)

cambia el nombre del fichero fichero1 (hay que poner nombre y extensin) por el indicado en la cadena fichero2. Igual que la anterior, devuelve TRUE o FALSE. Si intentamos cambiar el nombre a un fichero inexistente nos dar error.

Funciones informativas
PHP dispone de funciones que nos facilitan informacin sobre ficheros. Algunas de ellas son las siguientes: file_exists(fichero)

Esta funcin devuelve TRUE si el fichero existe, en caso contrario devuelve FALSE. filesize(fichero)

Devuelve el tamao del fichero expresndolo en bytes. En caso de que el fichero no existiera nos dar un error. filetype(fichero)

Devuelve una cadena en la que se indica el tipo del fichero. En caso de que el fichero no existiera nos dar un error. filemtime(fichero)

Devuelve en tiempo Unix la fecha de la ltima modificacin del fichero. stat(fichero)

Devuelve un array que contiene informacin sobre el fichero. Hemos creado un fichero llamado domingo.txt para poder utilizarlo en los ejemplos. Su contenido es exactamente el siguiente (incluidos los saltos de lnea):

Esto es un ejemplo para comprobar si funcionan o no los saltos de lnea en un documento de texto que ser ledo desde php
En la tabla puedes ver los contenidos asociados a cada uno los ndices del array que contiene resultado de aplicar la funcin stat al fichero domingo.txt.
Indice Significado Dispositivo I node Modo de proteccin de I node Nmero de enlaces Id de usuario del propietario Id de grupo del propietario tipo de dispositivo si es un inode device Tamao en bytes Fecha del ltimo acceso Fecha de la ltima modificacin Fecha del ltimo cambio Tamao del bloque para el sistema I/O Nmero de bloques ocupados *
* * *

Sintaxis <? echo $d[0] ?> <? echo $d[1] ?> <? echo $d[2] ?> <? echo $d[3] ?> <? echo $d[4] ?> <? echo $d[5] ?> <? echo $d[6] ?> <? echo $d[7] ?> <? echo $d[8] ?> <? echo $d[9] ?> <? echo $d[10] ?> <? echo $d[11] ?> <? echo $d[12] ?>

Resultado

0 1 2 3 4 5 6 7 8 9 10 11 12

2056 28607187 33279 1 32031 32033 0 126 1338948639 1312376374 1312526279 4096 8

Los valores sealados con

devuelven -1 en algunos sistemas operativos, entre ellos Windows>

Otras funciones
Existen otras muchas funciones relacionadas con el manejo de ficheros y directorios, as como con los permisos de acceso, etctera. Hemos resumido nicamente las de mayor inters. Si quieres profundizar en este tema a travs de este enlace podrs acceder al captulo del Manual de Referencia oficial de PHP, en el que se describen las funciones relacionadas con el manejo de ficheros.

Ejemplos del uso de algunas funciones sobre ficheros


<?php /* abrimos con w+ con lo cual borramos el contenido y creamos el fichero en el caso de que no existiera */ $f1=fopen("sabado.txt","w+"); # escribimos en el fichero vaco fwrite($f1,"Esta es la primera linea que escribimos en el fichero<br>"); #cerramos el fichero fclose($f1); echo "<H2>Este es el resultado despus del primer fwrite</H2><br>"; include("sabado.txt"); # abrimos con r+ con lo cual sobreescribiremos # en el fichero preexistente $f1=fopen("sabado.txt","r+"); # escribimos en al principio del fichero preexistente # ya que al abrir un fichero en este modo el puntero # se sita al comienzo del fichero

fputs($f1,"Esto se sobreescribe"); #cerramos el fichero fclose($f1); echo "<H2>Este es el resultado despus del segundo fwrite</H2><br>"; include("sabado.txt"); # abrimos con a+ con lo cual AADIREMOS # al fichero preexistente ya que el modo de apertura # sita el puntero al final del fichero $f1=fopen("sabado.txt","a+"); # escribimos al final del fichero preexistente fputs($f1," Esto se aadir al final<br>"); #cerramos el fichero fclose($f1); echo "<H2>Este es el resultado despus del tercer fwrite</H2><br>"; include("sabado.txt"); echo "<h2>Leyendo con fgetc</h2><br>"; # abrimos con r+ con lo cual podemos LEER y AADIR # al fichero preexistente $f1=fopen("sabado.txt","r+"); # leemos el primer carcter del fichero # ya que el apuntador esta el principio $z=fgetc($f1); # imprimimos el primer carcter echo "He leido el primer carcter: ",$z,"<br>"; /* leemos el segundo caracter del fichero ya que el apuntador se ha movido a esa posicin al leer anteriormente el primer carcter. OBSERVA que NO HEMOS CERRADO AUN EL FICHERO */ $z=fgetc($f1); # este es el nuevo valor de la variable $z echo "He leido el segundo carcter: ",$z,"<br>"; /* leemos el siguiente caracter del fichero ya que el apuntador se ha movido a una nueva posicin Recuerda que NO HEMOS CERRADO AUN EL FICHERO */ $z=fgetc($f1); # este es ahora el valor de la variable $z echo "He leido el tercer carcter: ",$z,"<br>"; echo "<h2>Ahora el puntero est en el tercer caracter<br>"; echo "fgets empezar a leer a partir de el</H2>";; $z=fgets($f1,200); echo "Con fgets he leido esto: ",$z,"<br>"; #Ahora cerramos el fichero fclose($f1); echo "<br><H2>Al abrir el fichero de nuevo fgets comienza desde el principio</h2><br>"; #Abrimos de nuevo el fichero $f1=fopen("sabado.txt","r"); #Leemos su contenido $za=fgets($f1,5000); #Presentamos el contenido echo $za; #Ahora cerramos el fichero fclose($f1); echo "--------------------------------------------------------------<br>"; ?> <h2>Aqui veremos el contenido (sin etiquetas HTML)de una pagina web</H2> <?php # Escribimos la direccin completa de la pgina que puede ser # el resultado de unir el valor de la variable $_SERVER['DOCUMENT_ROOT'] # (ruta completa del directorio raz de servidor) # con el nombre del directorio que la contiene y nombre del fichero # la abrimos en modo solo lectura

$f1=fopen($_SERVER['DOCUMENT_ROOT']."/php/php24.php","r"); # Escribimos un bucle para que vaya leyendo # cada una de las lneas hasta llegar al final del fichero while (!feof($f1)) { $z = fgetss($f1, 1024); echo $z,"<br>"; } #Cerramos el fichero fclose($f1); #Borramos el fichero antes de salir unlink("sabado.txt"); ?>
Ver ejemplo166.php

Otro ejemplo completando el anterior


<?php # Abrimos el fichero en modo lectura $f1=fopen("domingo.txt","r"); # Al anteponer echo a fpassthru # NOS APARECER AL FINAL EL TAMAO DEL FICHERO echo fpassthru($f1),"<br>"; /* Abrimos de nuevo el fichero RECUERDA QUE FPASSHRU LO CIERRA AUTOMTICAMENTE DESPUS DE EJECUTAR LA INSTRUCCIN */ $f1=fopen("domingo.txt","r"); # Este bucle nos escribir cada una de las #lneas del fichero while(!feof($f1)){ $z=fgets($f1,4000); echo $z,"<br>"; } # Situamos el puntero #al comienzo del fichero rewind($f1); # Reescribimos el fichero while(!feof($f1)){ $z=fgets($f1,4000); echo $z,"<br>"; } # Situamos de nuevo el puntero #al comienzo del fichero rewind($f1); # Situamos el puntero #sealando el byte nmero 15 del fichero fseek($f1,15); # Releemos el fichero #ahora la primera lnea estar incompleta #LE FALTARN LOS 15 PRIMEROS CARACTERES while(!feof($f1)){ $z=fgets($f1,4000); echo $z,"<br>"; } # volvemos el puntero al comienzo del fichero rewind($f1); #leemos la primera lnea $z=fgets($f1,4000); echo $z,"<br>"; # Determinamos LA POSICIN ACTUAL DEL PUNTERO echo ftell($f1),"<br>";

# Cerramos el fichero fclose($f1); echo "_________________________________________<br>"; # leemos el fichero y lo presentamos # en diferentes modalidades $pepe=readfile("domingo.txt"); readfile("domingo.txt"); echo $pepe, "<br>"; #leemos el fichero y lo recogemos #en un array $z=file("domingo.txt"); #Al presentar la variable solo #nos aparecer la palabra array echo $z,"<br>"; # presentamos el contenido del array foreach($z as $linea=>$texto) { echo "Linea: ",$linea," Texto: ",$texto,"<br>"; }; # copiamos el fichero con mensaje de resultado if (!copy("domingo.txt", "otrodomingo.txt")) { print("Error en el proceso de copia<br>\n"); }else{ print "<br>Fichero copiado con exito"; } # renombramos un fichero con mensaje de resultado if (!rename("otrodomingo.txt", "otrolunes.txt")) { print("Error en el proceso de renombrado<br>"); }else{ print "<br>Fichero renombrado con exito"; } unlink("otrolunes.txt"); echo "Ultima modificacin a las: ",date("h:i:s A", filemtime ("domingo.txt"))," del da ", date("j-n-Y", filemtime ("domingo.txt")); echo "<br>El tamao del fichero es: ", filesize("domingo.txt")," bytes<br>"; echo "<br>El fichero es tipo: ", filetype("domingo.txt")," <br>"; echo "<br>Saldr un 1 si el fichero existe: ",file_exists("domingo.txt"); ?>
Ver ejemplo167.php

Ejemplo de un contador de visitas


<?php /* comprobamos si existe el fichero contador. Si existe leemos las visitas registradas e incrementamos su valor en una unidad Si no existe, registramos 1 como valor de nmero de visitas*/ if(file_exists("contador.txt")){ /* abrimos el fichero en modo lectura y escritura (r+) con lo que el puntero se colocar al comienzo del fichero */ $f1=fopen("contador.txt","r+"); # leemos el contenido del fichero $visitas=(int)(fgets($f1,10)); # lo aumentamos en una unidad $visitas++; # colocamos el puntero al comienzo del fichero para que # al guardar en nuevo valor sobreescriba el anterior rewind($f1); }else{ /*abrimos el fichero en modo lectura y escritura con (w+)

de modo que se cree automaticamente al no existir*/ $f1=fopen("contador.txt","w+"); #asignamos uno como valor a nmero de visitas $visitas=1; } /* escribimos el nmero de visitas en el fichero. En cualquiera de los casos el puntero estar al comienzo del fichero, por tanto cuando existan valores sern sobreescritos */ fwrite($f1,$visitas,10); print("Esta pgina ha sido visitada ".$visitas." veces"); fclose($f1); ?>
Ver contador

Guardar y leer datos transferidos mediante un formulario


Aunque el modo ms habitual de guardar informacin suele ser los servidores de bases de datos (MySQL, por ejemplo) la utilizacin de ficheros ofrece interesantes posibilidades de almacenamiento de informacin. Este es un ejemplo muy sencillo, en el que mediante un formulario tal como el que aparece en el recuadro puede transferirse y almacenarse la informacin en un fichero.

<form name="fichero" method="post" action="escribe.php"> <input type="text" name="nombre"> <input type="text" name="apellido"> <input type="edad" name="edad"> <input type="submit" value="enviar"> </form>
Los datos transferidos mediante un formulario como el anterior podran ser registrados y visualizados mediante un script como este:

<?php /*abrimos el fichero en modo a+ para permitir que se cree en caso de no existir, que permita los modos lectura y escritura y que escriba al final del fichero */ $f1=fopen("escribiente.txt","a+"); # hacemos un bucle para leer los valores transferidos # desde el formulario y recogidos en el array $_POST foreach($_POST as $v){ /* aadimos "\r\n" a cada valor para que se inserte un salto de lnea y que cada valor sea recogido en una lnea distinta en el fichero Limitamos las entradas a 150 caracteres*/ fwrite($f1,$v."\r\n",150); } /* para comprobar que los nuevos datos han sido agregados y visualizar el contenido ntegro del fichero situamos el puntero interno al comienzo del mismo */ rewind($f1); /* creamos un bucle que vaya leyendo todas las lneas hasta encontrar el final del fichero */ while (!feof($f1)) { /* vamos leyendo el contenido de cada lnea del fichero y aunque establecemos en 250 el nmero de carcteres dado que los saltos del lnea aparecern antes sern ellos los puntos de interrupcin de cada lectura*/ $z = fgets($f1,250); #presentamos el resultado de las lecturas echo $z,"<br>";

} # cerramos el fichero fclose($f1); ?>

Transferencia de ficheros Comprobacin de la configuracin


Antes de empezar con este tema debemos comprobar cul es la configuracin de nuestro php.ini. Si por alguna circunstancia los valores no coincidieran con los que tenemos aqu debajo, tendramos que abrir php.ini y modificar aquellas directivas. Cuando publicamos en un hosting no tenemos acceso al fichero de configuracin php.ini pero s podemos conocer su configuracin mediante el script info.php. Recordemos que ese fue nuestro primer script lo hemos creado y utilizado para comprobar nuestra instalacin y lo hemos guardado con ese nombre en el root de nuestro servidor /home/rinconas/public_html as que podremos acceder a l escribiendo como direccin http://localhost/info.php. La abundante lista que nos muestra info.php contiene las siguientes lneas (las podemos localizar fcilmente porque estn ordenadas alfabticamente), que en nuestro caso configuracin por defecto tendrn los valores que vemos en la imagen.

Es imprescindible que file_uploads=On (tal como aparece en la imagen) y resulta muy til tambin conocer el valor deupload_max_filesize que por defecto tal como ves en la imagen es de 2Mb. La primera directiva nos dice que PHP s permite subir ficheros al servidor y la segunda nos indica el tamao mximo (en Mbytes) de los ficheros que pueden ser objeto de esa transferencia. Si te apetece, y como simple experimento, podemos cambiar el lmite del tamao mximo de transferencia poniendo un valor ms reducido: upload_max_filesize=500K que nos servir para hacer alguna prueba sencilla.

Transferencia de ficheros
La transferencia de un fichero requiere dos documentos: un formulario que la inicie y un script que la recoja.

El formulario
Se diferencia del que hemos visto en pginas anteriores en tres aspectos. Dos de ellos se refieren a cambios dentro de la etiqueta<form> y el tercero es un nuevo tipo de input del que an no hemos hablado. En la etiqueta <form> hemos de incluir obligatoriamentemethod='POST' y ENCTYPE = "multipart/form-data" ya que no soporta ni otro mtodo ni otra forma de codificacin. El cuerpo del formulario ha de contener un nuevo tipo de input que utiliza la siguiente sintaxis: <input type='file' name='nombre'> Observa que en el formulario hemos insertado una variable oculta (hidden) con el fin de limitar el tamao mximo e impedir la transferencia de ficheros que excedan ese tamao.

<html> <body> <form enctype="multipart/form-data" action="ejemplo169.php" method="post"> # con este input "oculto" establecemos el lmite mximo

# del tamao del fichero a transferir. En este ejemplo 1.000.000 bytes <INPUT type="hidden" name="lim_tamano" value="1000000"> <p><b>Archivo a transferir<b><br> <input type="file" name="archivo"></p> <p><input type="submit" name="enviar" value="Aceptar"></p> </form> </body> </html>

La tranferencia
Una vez enviado el formulario, el fichero transferido se guarda en un directorio temporal del servidor salvo que php.ini especifique una cosa distinta con un nombre que le es asignado de forma automtica, y, adems, se recogern todos los datos relativos al contenido del fichero y a los resultados de la transferencia en la variable predefinida $_FILES. El la variable $_FILES tiene formato de array bidimensional. El primero de sus ndices es el nombre de variable usado para la transferencia (el especificado como name='nombre' en el input type='file'). Los segundos ndices se trata de un array asociativo tiene como valores: name, type, tmp_name, error y size. En ellos se recogen: el nombre original del fichero transferido, su formato, el nombre con el que ha sido guardado en el directorio temporal, el tipo de error de transferencia y el tamao del archivo. El error puede ser CERO o UNO. Si es CERO indica que la transferencia se ha realizado con xito. En caso contrario, el valor de ese error es UNO. Este script, al que hemos llamado ejemplo169.php es el que recoge la action de formulario que hemos incluido unas lneas ms arriba.

<?php /* Mediante el bucle foreach leemos el array $_FILES. Observa la sintaxis. Escribimos como nombre del array $_['archivo'] con lo cual foreach leer los elementos del array que tienen 'archivo" como primer ndice (coincide con el name que hemos puesto en la etiqueta input=file del formulario) */ foreach ($_FILES['archivo'] as $indice=>$valor){ print $indice."--->".$valor."<br>"; } /*Dependiendo del navegador que ests utilizando puede ocurrir que varan los valores del ndice type sean distintos. Cuando se trata de un fichero jpg, con IE devolver image/pjpeg, mientras que con Mozilla, Firefox, Opera y Netscape devolver image/jpeg.*/ ?>
ejemplo168.php

Enva un fichero cualquiera de menos de 2Mb y vers que el error es 0. Repite el envo, ahora con un fichero que sobrepase ese tamao, y comprobars que el error toma valor 1 dado que la directiva upload_max_filesize=2M del fichero php.ini habr bloqueado la transferencia. Puedes modificar la configuracin de php.ini y modificar esos lmites de transferencia. Al hacerlo incrementars o reducirs el lmite mximo de transferencia.

Copia del fichero


Tal como hemos visto, el fichero transferido an no est en el servidor. Por el momento se encuentra en un directorio temporal y ser preciso hacer una copia en nuestro espacio de servidor. Para este proceso puede utilizarse una funcin que ya hemos visto en pginas anteriores:

copy(fichero1, fichero2)

donde fichero1 sera el fichero temporal y fichero2 el del nuevo fichero. El primero de los nombres es el valor contenido en:$_FILES['nm']['tmp_name'] donde nm es el valor incluido como name en el formulario usado para la transferencia y tmp_name es unapalabra reservada que debe escribirse exactamente con esa sintaxis. El valor fichero2 podra ser un nombre cualquiera asignado en el propio script podemos verlo en el ejemplo o el nombre original del fichero transferido. En este caso habra que recogerlo del elemento del array anterior cuyo segundo ndice es name. En la cadena fichero2 podra incluirse recuerda que debes ponerlo entre comillas un path sealando el directorio o subdirectorio donde queremos que guarde la copia. De no incluirlo, el fichero se copiara en el directorio desde el que se est ejecutando el script.

Sintaxis alternativa
La opcin anterior tiene una alternativa, igual de eficiente y mucho ms segura. Se trata de: move_uploaded_file(fich1, fich2)

que tiene la misma utilidad que copy y aade algunas ventajas tales como: Comprobar que el fichero ha sido transferido mediante el mtodo POST e impedir que se copie en el servidor en caso de no cumplirse esa condicin. Si la opcin safe mode=on (configuracin de php.ini en modo seguro) por defecto est Off comprueba, adems, que la transferencia del fichero ha sido realizada por el mismo usuario que hace la peticin de ejecucin del script, evitando que alguien,maliciosamente, pueda mover ficheros desde el directorio temporal hasta el espacio de servidor. A diferencia de la anterior esta funcin mueve el fichero y por lo tanto no queda copia del mismo en el fichero temporal

Cuidado! Al usar esta funcin bajo Windows conviene indicar en el parmetro fichero2 la ruta absoluta completa junto con el nombre del fichero ya que de no hacerlo as en algunas ocasiones la imagen no ser transferida al directorio desde el que se ejecuta el script.

Mejorando las trasnferencias


Cuando est habilitada la opcin de transferencias de ficheros es conveniente en previsin de sorpresas desagradables tomar algunas cautelas. Una de ellas sera limitar la posibilidad de transferencia a determinados tipos de archivos imgenes, por ejemplo impidiendo con ello que pudieran transferirse al servidor ficheros de riesgo, tales como: ejecutables, virus, etctera. Cuando se establece este tipo de limitaciones, PHP comprueba los contenidos de los ficheros sin tomar en consideracin la extensin de los mismos. Con ello se evita el riesgo de que puedan esconderse cambiando la extensin ficheros distintos de los permitidos. Aqu tienes un ejemplo de script que impide la transferencia de ficheros con extensin distinta a .jpg o .gif.

<?php /* filtramos el tipo de archivos recibidos de forma que solo se permitan imagenes en formato jpg gif. Si el fichero transferido tuviera formato distinto, la funcin exit() acabara la ejecucin del script */ if(!($_FILES['archivo']['type']=="image/pjpeg" OR $_FILES['archivo']['type']=="image/jpeg" OR $_FILES['archivo']['type']=="image/gif")){ print "El formato ".$FILES['archivo']['type'].

" no est permitido"; exit(); }else{ # anidamos este segundo condicional # para guardar en una variable # la extensin real del fichero # mas adelante la utilizaremos if ($_FILES['archivo']['type']=="image/pjpeg" OR $_FILES['archivo']['type']=="image/jpeg" ){ $extension=".jpg"; }else{ $extension=".gif"; } } /* filtremos ahora el tamao de modo que no supere el mximo establecido en el hidden del formulario (lgicamente ese valor no puede superar el valor mximo de la configuracin de php, pero si puede ser menor) y tambin evitaremos archivos sin contenido, es decir con tamao CERO */ if($_FILES['archivo']['size']>$_POST['lim_tamano'] OR $_FILES['archivo']['size']==0){ print "El tamao ".$FILES['archivo']['size']." excede el lmite"; exit(); } # # # # # # asignemos un nombre a la imagen transferida de modo que se guarde en el servidor con un nombre distinto, asignado por nosotros con ello, podemos evitar duplicidades de nombres ya que si existiera un fichero con el mismo nombre que el enviado por el cliente, se sobreescribira

$nuevo_nombre="foto_abuelita"; # aadmosle la extensin real de fichero que tenamos # recogida en la variable nuevo_nombre $nuevo_nombre .=$extension; # aceptemos la transferencia siempre que el archivo tenga nombre if ($_FILES['archivo']['tmp_name'] != "none" ){ /* con la funcin copy pasaremos el archivo que est en el directorio temporal al subdirectorio que contiene el script que estamos ejecutando. Podramos incluir un path y copiarlo a otro directorio */ if (copy($_FILES['archivo']['tmp_name'], $nuevo_nombre)) { echo "<h2>Se ha transferido el archivo</h2>"; } }else{ echo "<h2>No ha podido transferirse el fichero</h2>"; } ?>

Funciones de compresin Herramientas de compresin


Existen varias herramientas para compresin de ficheros. Las ms populares son las funciones de la biblioteca bzip2 de Julian Seward que generan ficheros comprimidos que se reconocen por su extensin (bz2) y la funcin de zlib de Jean-loup Gailly y Mark Adler para leer y grabar archivos comprimidos con extensin gz. En esta pgina veremos el uso

de la segunda de las opciones. Empezaremos comprobando en info.php que la opcin est activada. Deberemos ver algo como esto:

En la versin de PHP que estamos utilizando esta opcin se activa por defecto y no es necesario modificar ningn parmetro enphp.ini.

Funciones zlib para compresin de ficheros


Algunas de esas funciones son estas: $f=gzopen(fichero,modo, ruta)

Abre el fichero identificado por el parmetro fichero y lo hace en el modo especificado en el parmetro modo (r o w segn se trate de modo lectura o escritura). Cuando se trata del modo de escritura el parmetro w debe ir seguido de un nmero comprendido entre cero ynueve que especifica el grado de compresin pretendido. El parmetro ruta es opcional y puede contener un valor lgico (cero uno). Cuando el valor de este parmetro es 1 permite incluir en el parmetro fichero la ruta del directorio o subdirectorio que alberga el fichero que tratamos de abrir. Si se incluye un path sin especificar el valor 1 en el parmetro ruta aparecer un error. gzclose($f)

Cierra el fichero asociado al identificador de recurso $f. Esta funcin devuelve TRUE en caso de xito o FALSE si se produjera un error. gzeof($f)

Esta funcin devuelve 1 (TRUE) en el caso de que el puntero apunte al final del fichero abierto e identificado mediante $f. Tambin devuelve TRUE en caso de error. Si el fichero estuviera abierto y el puntero apunta a una posicin distinta del final del fichero devolver FALSE. gzseek($f,desplaza)

Desplaza dentro del fichero identificado por $f el puntero a partir de su posicin actual la cantidad de bytes indicados en el parmetro desplaza. gztell($f)

Devuelve la posicin actual del puntero.

gzrewind($f)

Coloca el puntero al comienzo del fichero gzread($f, longitud)

Devuelve una cadena -despus de descomprimida- de longitud igual a la indicada en el parmetro longitud. La lectura comienza en laposicin actual del puntero y acaba cuando la longitud de la cadena leda y descomprimida sea igual al valor del parmetro longitud o cuando se haya alcanzado el final del fichero. gzpassthru ($f)

Esta funcin escribe en la salida (no necesita la funcin echo) el contenido del fichero desde la posicin actual del puntero hasta el final del fichero. Como es lgico, si estuviera precedida de gzrewind escribira el fichero completo.

Cuidado! La funcin gzpassthru cierra automticamente el fichero despus de escribir su contenido. Si pones gzclose despus de esta funcin te dar error y si quieres seguir utilizando el fichero tendrs que volver a abrirlo con la funcin gzopen.
gzwrite($f, cadena, long)

Esta funcin escribe en el fichero comprimido que se identifica por $f la cadena contenida en el parmetro cadena. Opcionalmente puede llevar el tercer parmetro (longitud) en cuyo caso solo escribir los primeros longitud bytes de la cadena. Si el parmetro longitudexiste y es mayor que la longitud de la cadena, insertar la cadena completa. gzputs($f, cadena, longitud)

Esta funcin es idntica a gzwrite. readgzfile($fichero,path)

Esta funcin abre de forma automtica el fichero indicado como parmetro fichero, adems lo lee y lo escribe de forma automticasin necesidad de usar echo ni ninguna otra funcin de salida. Si el fichero no est en el mismo directorio que el script -adems de incluir la ruta en la cadena fichero- es necesario aadir el segundo parmetro -path- con valor 1.

Ejemplo de compresin y lectura de un fichero


En este ejemplo trataremos de utilizar las funciones de compresin comentadas al margen. Si observas las formas de apertura de los ficheros vers que son similares a las utilizadas para la gestin de ficheros. Los modos de apertura para escritura son: "w0" a "w9" siendo los valores de cero a nueve los indicadores de los niveles de compresin. Para lectura debe usarse el modo "r" sin indicar ningn nivel de compresin.

<?php # asignamos un nombre al fichero con extensin "gz" $fichero ='prueba.gz'; # abrimos el fichero en modo escritura (w) # con el nivel mximo de compresin (9) $f=gzopen($fichero,"w9",0); $cadena="Este es el primer bloque de texto que hemos introducido en el fichero comprimido. "; $cadena .="Aadimos este segundo bloque"; echo "<i>Esta es la cadena inicial:</i> ".$cadena."<br>";

# escribimos (comprimida) la cadena en el fichero gzwrite($f,$cadena); # cerramos el fichero gzclose($f); #abrimos el fichero en modo lectura $f=gzopen($fichero,"r"); echo "<i>Estos son los tres primeros caracteres de la cadena:</i> "; # escribimos los tres primeros caracteres, el puntero (por defecto) # apunta al comienzo de la cadena echo gzread($f, 3)."<br>"; # desplazamos el puntero hasta el carcter n 8 gzseek($f,8); echo "<i>Estos son los seis caracteres siguientes al octavo:</i> "; # escribimos seis caracteres a partir del octavo echo gzread($f, 6)."<br>"; echo "<i>Ahora el puntero est en:</i> "; # buscamos la posicin actual de puntero echo gztell($f)."<br>"; # movemos el puntero hasta el comienzo del fichero gzrewind($f); echo "<i>Estos son los diez primeros caracteres de la cadena:</i> "; # escribimos los diez primeros caracteres del fichero echo gzread($f, 10)."<br>"; # volvemos el puntero al comienzo del fichero gzrewind($f); echo "<i>Escribimos el fichero completo:</i> "; # con gzpasthru escribimos el fichero completo # el puntero est al principio porque all lo ha situado gzrewind # no necesitamos utilizar "echo" ni "print" ya que gzpassthru # escribe directamente el contenido del fichero gzpassthru($f); # tenemos que volver a abrir el fichero ya que gzpassthru # se encarg de cerrarlo despus de leerlo $f=gzopen($fichero,"r"); echo "<br><i>Aqu estar todo el fichero:</i> "; gzpassthru ($f); # la funcin readgzfile abre el fichero, imprime su contenido y lo cierra echo "<br><i>Aqui se imprime la cadena completa usando readgzfile</i>: <br>"; readgzfile($fichero); /* con gzfile tambin se abre el fichero, pero ahora el contenido no se presenta directamente. Es recogido en un array. Para visualizarlo debemos imprimir el primer elemento del array. */ $z=gzfile($fichero); echo "<br><i>Este es el primer elemento (0) del array generado por gzfile</i>: ".$z[0]; # gzfile cierra el fichero. # No podemos poner gzclose porque nos dara error ?>
ejemplo174.php

Utilizando un directorio distinto


El ejemplo anterior est desarrollado para el supuesto que el script y el fichero comprimido estn en el mismo directorio. Si quieres utilizar estas funciones utilizando ficheros alojados en un directorio distinto, solo tendrs que recordar que algunas funciones deben incluir el parmetro complementario 1.- Estos son las modificaciones que deberas efectuar: La variable que recoge el nombre del fichero debe incluir el path, por ejemplo: $fichero ='/subdirectorio/prueba.gz'

La funcin gzopen debe incluir el tercer parmetro (path) con valor 1, por ejemplo: $f=gzopen($fichero,"r",1); Tambin las funciones gzfile y readgzfile -que abren automticamente el fichero- debern incluir ese valor 1 como parmetro aadido. Por ejemplo: readgzfile($fichero,1) $z=gzfile($fichero,1)

Eleccin del grado ptimo de compresin


Puede parecer que la condicin ptima de compresin sera elegir el nivel 9 y eso es cierto si tomamos nicamente en consideracin el tamao final del fichero comprimido. Sin embargo no existe una relacin lineal entre reduccin de tamao/nivel de compresin. Sin que pueda considerarse ninguna referencia exacta la compresin alcanzable depende del contenido del fichero y en consecuencia no puede establecerse una relacin funcional puede comprobarse experimentalmente que -aparentemente- a partir del grado 2 la reduccin de tamao del fichero es mnima y que cuando se aumenta el grado de compresin a niveles mximos (tratndose de ficheros de un cierto tamao) el tiempo de ejecucin aumenta sustancialmente como consecuencia de la reiteracin de la ejecucin de los algoritmos de compresin.

Comprimiendo cadenas
Las funciones anteriores permiten la creacin, lectura y modificacin de ficheros comprimidos. Sin embargo, existen otras funciones PHP que permiten comprimir cadenas. Aqu tienes algunas de ellas. gzcompress(cadena, nivel)

Esta funcin devuelve una cadena comprimida a partir de una original especificada en el parmetro cadena. El nivel de compresin (valores entre 0 y 9) se especifica en el parmetro nivel. Las cadenas resultantes de esta funcin pueden descomprimirse aplicando la funcin gzuncompress que referimos ms abajo. gzdeflate(cadena, nivel)

Se comporta de forma idntica a la funcin anterior. La nica salvedad parece ser que utiliza un algoritmo de compresin distinto. Las cadenas resultantes de esta funcin tambin pueden descomprimirse aplicando la funcin gzdeflate. gzencode(cadena, nivel, opciones)

Esta funcin devuelve la cadena cadena comprimida con el nivel especificado en nivel y permite dos opciones de compresin:FORCE_GZIP FORCE_DEFLATE que se pueden especificarse como tercer parmetro (opciones) sin encerrar entre comillas. El valor por defecto (cuando no se especifica el parmetro opcin) es FORCE_GZIP.

Descomprimiendo cadenas
gzuncompress(cadena)

Con esta funcin se obtiene la cadena original a partir de la cadena comprimida indicada en el parmetro cadena siempre que esta hubiera sido comprimida usando la funcin gzcompress. gzinflate(cadena)

Funciona igual que la anterior. La nica diferencia es que esta descomprime las cadenas que han sido comprimidas con gzdeflate.

Ejemplo de compresin y descompresin de cadenas


En este ejemplo utilizamos las tres funciones de compresin de cadenas as como las opciones de descompresin y lectura de cada una de ellas.

<?php # creamos una cadena de ejemplo $cadena="Esta es la cadena a comprimir. Intentaremos que sea larga porque parece que si la hacemos muy corta en vez de reducirse su tamao parece que aumenta. Y como sigue siendo enormemente grande la cadena comprimida intentaremos hacerla aun mayor a ver que pasa "; # comprimimos con la funcin gzcompress $c=gzcompress($cadena,9); echo "<br>".$c; # descomprimimos con la funcin gzcompress $dc=gzuncompress($c); echo "<br>".$dc."<br>"; # ahora utilizamos la funcin gzencode $c1=gzencode($cadena,9,FORCE_GZIP); echo "<br>".$c1."<br>"; /* el resultado lo guardamos en un fichero con extensin gz pero abierto en modo "normal", es decir escribiendo dentro del fichero la cadena "tal cual" fue devuelta por gzencode*/ $f=fopen("pepe.gz","w"); fwrite($f,$c1); fclose($f); # abrimos el fichero anterior utilizando las funciones # de lectura de fichero comprimidos $f=gzopen("pepe.gz","r"); readgzfile("pepe.gz"); gzclose($f); # borramos el fichero una vez ledo unlink("pepe.gz"); # otra opcin de compresin de cadenas utilizando la funcin # gzdeflate $c2= gzdeflate($cadena,9); echo "<br><BR>".$c2; # con la funcin gzinflate podemos descomprimir la cadena # comprimida generada por gzdeflate $dc2=gzinflate($c2); echo "<br>".$dc2; ?>
ejemplo175.php

Funciones para buferizacin de salidas


ob_start()

Esta funcin activa la buferizacin de las salidas generadas por el script de PHP a partir de su activacin. Dicho de otra forma, impide que las salidas generadas por el script se enven al cliente impidiendo que sean visualizadas en el navegador. A partir del momento de activar esa buferizacin, todas las salidas generadas se almacenan en una variable especfica llamada: ob_get_contents() ob_end_clean()

Esta funcin desactiva la buferizacin iniciada por ob_start y borra los contenidos de la variable ob_get_contents() ob_clean()

Esta funcin vaca el buffer de salida pero sin desactivar la bufferizacin. Las salidas posteriores a esta funcin seguiran siendo recogidas en el buffer.

Cabeceras para transferir informacin comprimida


Cuando un servidor recibe una peticin de una pgina web el navegador del cliente siempre enva informacin sobre su disposicin a aceptar diferentes tipos de contenidos. Una de las informaciones que suelen recibirse con la peticin del navegador se refiere a su capacidad para aceptar contenidos codificados y esto suelen hacerlo mediante el envio de una cabecera que dira algo similar a esto: Accept-Encoding:gzip,deflate o Accept-Encoding: gzip. Esta posibilidad es una caracterstica comn a todas las versiones modernas de los navegadores (es posible que algunas versiones antiguas no acepten esta codificacin) y bastar con que se incluya en la respuesta (el documento transferido por el servidor al cliente) la cabecera: Header('Content-Encoding: gzip') para que el navegador sepa que la informacin llegar codificada y que debe activar -de forma automtica- sus mecanismos de traduccin de ese tipo de contenidos.

Algunas limitaciones
En todos estos ejemplos hemos dado por supuesto que los navegadores de los clientes aceptan la codificacin gzip, pero es evidente que si eso no ocurriera la pgina se visualizara errneamente.

Economizando espacio en el servidor


Las opciones de compresin pueden permitirnos un cierto ahorro de espacio de servidor. Las pginas HTML podran almacenarse comprimidas y ser llamadas a travs de un script de descompresin que permita visualizarlas. En este ejemplo se efecta la compresin de una pgina web (una de las pginas de estos materiales guardada en formato HTML) cuyo tamao original es de 57.105 bytes. El fichero comprimido resultante ocupa 12.371 bytes. Como vers, el fichero se reduce a poco ms del 20% del original.

<? # Creamos una variable "vacia" $cadena=""; # Abrimos el fichero en modo lectura (r) $f1=fopen("prueba.html","r"); /* hacemos un bucle para leer el fichero hasta encontrar el final (feof) y vamos recogiendo el contenido en la variable */ while (!feof($f1)) { $cadena .= fgets($f1, 1024); } /*comprimimos la cadena con gzencode con lo cual la propia funcin aade los "encabezados" de formato gzip*/ $c1=gzencode($cadena,3,FORCE_GZIP); /* abrimos un nuevo fichero modo escritura (w) con "fopen", es decir como un fichero normal con extensin GZ */ $f=fopen("prueba.html.gz","w"); /* escribimos la cadena "tal cual" en este fichero */ fwrite($f,$c1); # cerramos el fichero comprimido fclose($f); echo "La compresin ha terminado"; ?>
ejemplo176.php

El fichero comprimido mediante el script anterior no puede ser visualizado directamente. Requiere ser descomprimido antes de ser enviado al navegador. Y eso podra hacerse mediante un script como este:

<?php #abrimos el fichero comprimido con "gzopen" $f=gzopen("prueba.html.gz","r"); /* leemos el contenido completo en forma transparente ya que readgzfile descomprime la salida*/ readgzfile("prueba.html.gz"); # cerramos el fichero gzclose($f); ?>
Visualizar fichero comprimido

Economizando tiempo de transferencia


No solo se puede economizar espacio en el servidor. Tambin es posible enviar comprimidas -desde el servidor hasta el cliente- las pginas web. En ese caso, ser el propio navegador el que interprete la informacin comprimida y la presente de una manera transparente. Lo que habremos ahorrado habr sido tiempo de transferencia pero, igual que ocurra en el comentario anterior, esa reduccin del volumen de informacin a transferir afecta nicamente al contenido de la pgina y no a otros elementos que puede incluir, tales como imgenes, etctera. Este es un ejemplo de un script que comprime una pgina web y la enva comprimida al cliente.

<?php /* activamos la bufferizacin de la salida para que no se presenten los resultados del script directamente en la pgina Cuidado con no dejar lneas en blanco delante del script ya que vamos a insertar luego Headers!! */ ob_start(); # abrimos y leemos el fichero html $f1=fopen("prueba.html","r"); fpassthru($f1); # recogemos el contenido del buffer en la variable $cadena $cadena = ob_get_contents(); # comprimimos la cadea con gzencode # para que incluya los encabezados "gzip" $cd=gzencode($cadena,3,FORCE_GZIP); # desactivamos la "buferizacin" # y borramos el contenido del buffer ob_end_clean(); # insertamos la cabeceras # indicando el tipo de contenido y el tamao Header('Content-Encoding: gzip'); Header('Content-Length: ' . strlen($cd));; # presentamos el contenido (cadena comprimida) que ser # "traducido" automticamente por el navegador echo $cd; ?>
Ejecutar script

El ejemplo anterior comprima el contenido del fichero antes de enviarlo. En este que incluimos a continuacin partimos del supuesto de que la pgina ya est comprimida en el servidor. Por tanto, tendremos que leer el fichero comprimido y enviarlo, de igual forma, al cliente.

<?php ob_start(); /* En este caso abrimos el fichero con "gzopen" ya que se trata de un fichero comprimido # todo lo dems es idntico al ejemplo anterior*/ $f1=gzopen("prueba.html.gz","r"); gzpassthru($f1); $cadena = ob_get_contents(); $cd=gzencode($cadena,3,FORCE_GZIP); ob_end_clean(); Header('Content-Encoding: gzip'); Header('Content-Length: ' . strlen($cd)); echo $cd; ?>
Ejecutar script

Funciones FTP Requisitos del sistema


El uso de estas funciones requiere que PHP tenga activada la opcin FTP (enabled), que en nuestro caso est activada en la configuracin por defecto, tal como puedes ver a travs de tu info.php, que tendr un apartado idntico al que observamos en la siguiente imagen.

Esto en cuanto a PHP. Pero adems de esta configuracin ser imprescindible disponer de un servidor FTP accesible y activo. En este tipo de transferencias intervienen dos servidores: el servidor HTTP (nuestro Apache) y el servidor FTP, cuyo procedimiento de instalacin y configuracin hemos descrito en el apartado Servidor de FTP. Antes de poder utilizar las funciones que aqu describimos debers tener instalado y activo el servidor FTP que all se describe. Nos conviene tener muy presente que esta versin de PHP parece no admitir localhost como nombre de servidor (en la versin 4 esto no ocurra) y que por esa razn hemos de referirnos al servidor FTP mediante su direccin IP (127.0.0.1, valor por defecto para nuestro servidor de pruebas en modo local) y que hemos creado diferentes usuarios (con privilegios distintos) entre ellos admin.

Transferencias FTP
En la pgina anterior hemos hablado de la manera de transferir informacin entre el ordenador de un usuario y un servidor web. Aqu trataremos algo similar a primera vista un poco distinto. Es el caso de las transferencias en los dos sentidos entre servidores (un servidor HTTP y un servidor FTP). En la configuracin descrita en la instalacin del servidor FTP hemos establecido que ambos servidores tengan sus root en el mismo equipo, pero esa no es la nica opcin posible. Es totalmente factible que uno de los servidores est alojado en un equipo situado fsicamente en Londres y el otro lo est en Sydney, por poner un ejemplo de lugares distantes. Imaginemos que todo esto es cierto. Los dos primeros pasos para poder utilizar las funciones FTP han de ser: abrir la conexin y pasar el login. El ltimo sera cerrar la conexin.

Abrir la conexin

$identificador=ftp_connect (host,puerto)

Esta funcin en la que host es una cadena con el nombre del servidor FTP (no te olvides de ponerlo entre comillas) y puerto es el nmero del puerto a travs del cual se efecta la conexin FTP abre una conexin con el servidor FTP. Si se omite puerto se asigna por defecto el valor 21 que es el habitual para este tipo de servidores. La variable $identificador recoger un identificador de conexin que ser utilizado por las dems funciones.

Loguearse
Utilizaremos este trmino del argot informtico horrible, verdad? para referirnos al hecho de que el usuario se acredite comoautorizado en el servidor FTP. ftp_login($identificador,usuario,contrasea)

Una vez abierta la conexin es preciso comenzar la sesin utilizando la funcin ftp_login con los siguientes parmetros: $identificador, que es la variable en la que se recoga el resultado de ftp_connect. usuario, que es el nombre de usuario. contrasea, que es la contrasea de acceso del usuario. Esta funcin devuelve un valor booleano que ser 1 en el caso en que se inicie la sesin correctamente o NUL si no lo hace.

Cerrar la conexin
Mediante la funcin: ftp_quit($x)

se cierra la conexin abierta con el identificador indicado en la variable $identificador.

<?php # conexin con el servidor FTP if($x=@ftp_connect ("127.0.0.1",21)){ echo "Conexin FTP activada<br>"; }else{ echo "No se activo lo conexin FTP<br>"; } # registro de usuario if(@ftp_login($x,"super","superi")){ echo "El login y la password han sido aceptados"; }else{ echo "Error en login o password"; } #desconexin ftp_quit($x); ?>
ejemplo180.php

Gestin de directorios en el servidor FTP


Una vez logueados y con la conexin activa, ya podremos utilizar funciones FTP tales como:

ftp_cdup($identificador)

Nos sita en el directorio raz del servidor FTP. ftp_pwd($identificador)

Devuelve una cadena con el nombre del directorio actual. ftp_chdir($identificador, otro_directorio)

Cambia el acceso del directorio actual al especificado por la cadena otro_directorio, en caso de que exista. ftp_pwd($identificador)

Devuelve una cadena que contiene el nombre del directorio actual. ftp_mkdir($identificador, nuevo_directorio)

Crea un subdirectorio en el directorio actual cuyo nombre es el nombre indicado en la cadena nuevo_directorio. ftp_rmdir($identificador, nombre_directorio)

Borra el directorio especificado en la cadena nombre_directorio. Para que un directorio pueda ser borrado se requiere que est vacoy que sea un subdirectorio del directorio actual.

Informacin sobre los contenidos de los directorios del servidor FTP


ftp_nlist($identificador, nombre_directorio)

Devuelve una array escalar con los nombres de los ficheros y subdirectorios contenidos en el directorio que se indica ennombre_directorio. Si se trata del directorio actual, el parmetro nombre_directorio puede especificarse como una cadena vaca (""). Si la informacin se refiere a un subdirectorio del actual bastar con poner su nombre como valor del parmetro nombre_directorio. En cualquier otro caso nombre_directorio contendr la ruta completa. ftp_rawlist($identificador, nombre_directorio)

Igual que la funcin anterior, ftp_rawlist tambin devuelve un array escalar, pero en este caso con informacin ampliada. Este array detalla, adems del nombre del fichero, el tamao, el tipo, la fecha de la ltima modificacin y los permisos de lectura y/o escritura.

<?php if($x=@ftp_connect ("127.0.0.1",21)){ echo "Conexin FTP activada<br>"; }else{ echo "No se activo lo conexin FTP"; } if(@ftp_login($x,"webmaster","webmaster")){ echo "El login y la password han sido aceptados<BR><BR>"; }else{ echo "Error en login o password";

} $lista=ftp_nlist($x,"/php/images"); foreach($lista as $c=>$v){ print "Indice: ".$c." Valor: ".$v."<br>"; } print "<H1>Lista completa</H1>"; $listacompleta=ftp_rawlist($x,"/php/images"); foreach($listacompleta as $c=>$v){ print "Indice: ".$c." Valor:".$v."</br>"; } ftp_quit($x); ?>
ejemplo181.php

El resultado de la ejecucin del script anterior podra producir una salida similar a esta:

Tal como puedes ver en la imagen, la cadena devuelta por la funcin ftp_rawlist tiene dos resultados distintos. La primera de las cadenas comienza por lo cual indica que se trata de un archivo y documento. En el segundo de los casos, se primer carcter es d e indica que se trata de un directorio. Los nueve caracteres siguientes especifican los permisos de acceso a los ficheros y/o directorios. Se subdividen en tres bloques de igual tamao que corresponden a los tres niveles de usuarios habituales en sistemas Unix/Linux (propietario, grupo y resto de usuarios). Para nuestros propsitos bastar con que consideremos los privilegios del primer bloque, es decir los del propietario. El primero carcter de cada bloque slo puede ser r . Si se trata de un fichero y est marcado con r indica que se permite el acceso a l en modo lectura y si se trata de un directorio indica que est permitida la visualizacin de su contenido. El segundo de los caracteres (puede ser w ) indica, si se trata de un fichero, que est permitida la modificacin del fichero. Cuando se trata de un directorio significa que se pueden aadir o suprimir ficheros. El tercero de los caracteres indicara (x ) que el fichero -si se trata de un ejecutable- tiene permisos para ser ejecutado. Cuando se trata de un directorio, indica que pueden conocerse los atributos de los ficheros que contiene y que est permitido el acceso a l y a sus subdirectorios. El signo significa la negacin del atributo en todas las opciones. El siguiente carcter, el nmero 1, est asociado con sistemas Linux/Unix e indicara el nmero de vnculos duros contra el archivo, que es otra cosa que una forma de asignar nombres distintos a un mismo fichero.

Los dos grupos siguientes -parece que no demasiado relevantes para nuestros propsitos- son los nombres del usuario y grupo al que pertenece. A continuacin aparece el tamao del archivo (cero si se trata de un directorio), la fecha y hora de su creacin y el nombre del archivo o directorio.

Transferencia de ficheros
Las transferencias de ficheros pueden realizarse en ambos sentidos.

Desde el servidor FTP hasta el servidor HTTP


Mediante la funcin: ftp_get( $identificador, nombre_en_servidor_web, nombre_en_servidor_ftp, modo)

se transfiere un fichero desde un servidor FTP hasta un directorio del servidor HTTP en el que se est ejecutando PHP. La cadenanombre_en_servidor_web contiene el nombre con el que el fichero ser copiado en el directorio actual del servidor web y la cadenanombre_en_servidor_ftp contiene el nombre (incluyendo el path) que tiene (en el servidor FTP) el fichero que debe ser trasferido. El parmetromodo puede contener uno de estos valores: FTP_ASCII o FTP_BINARY

Desde el servidor HTTP hasta el servidor FTP


Para realizar transferencias en sentido opuesto al anterior se utiliza la siguiente sintaxis: ftp_put($identificador, nombre_en_servidor_ftp, nombre_en_servidor_web, modo)

Se comporta de forma idntica a la funcin anterior. La cadena nombre_en_servidor_ftp sigue siendo el nombre y el path del servidor FTP (donde vamos a copiar el fichero) y nombre_en_servidor_web contiene el nombre del fichero en el servidor web (origen de la transferencia).

Modificacin de ficheros en el servidor FTP


ftp_rename($identificador,nombre_actual,nuevo_nombre)

Cambia el nombre del fichero nombre_actual por el indicado en la cadena nuevo_nombre. ftp_delete($identificador,nombre_fichero)

Elimina -en el servidor FTP- el fichero indicado en la cadena nombre_fichero.

Informacin sobre ficheros del en el servidor FTP


ftp_size($identificador,nombre_fichero)

Devuelve el tamao (en bytes) del fichero que se indica en la cadena nombre_fichero. ftp_mdtm($identificador,nombre_fichero)

Esta funcin devuelve la fecha de la ltima modificacin del fichero indicado en la cadena nombre_fichero. Esta fecha se indica entiempo Unix.

Un ejemplo de uso de las funciones FTP

<?php # Conexin con el el servidor ftp utilizando su direccin IP if(!$x=@ftp_connect ("127.0.0.1",21)){ echo "No se activo lo conexin FTP"; exit(); } # Identificacin de usuario webmaster (manejaremos ficheros en Apache) if(!@ftp_login($x,"webmaster","webmaster")){ echo "Error en login o password"; exit(); } /* comprobamos el nombre del directorio actual del servidor FTP que ser el root correspondiente al usuario registrado (aparecr /) */ echo "El directorio actual es: ",ftp_pwd($x),"<br>"; /* intentamos cambiar a un subdirectorio indicando la ruta absoluta partiendo del directorio root del usuario actual. En caso de error (ruta incorrecta o falta de permisos de accesos nos dara un mensaje de error. Si el cambio tiene xito nos indicara el nombre del nuevo directorio */ if(!@ftp_chdir($x,"/miphp/pdf")){ print "No tienes permisos de acceso a este directorio<br>"; print "o la ruta es incorrecta.Comprueba los datos!<br>"; }else{ echo "Hemos cambiado al directorio: ",ftp_pwd($x),"<br>"; } # comprobamos el nombre del sistema operativo del servidor de FTP echo "El S.O: del servidor FTP es: ",ftp_systype ($x),"<br>"; /* obtenemos una matriz conteniendo la lista de ficheros y directorios del subdirectorio "miphp/fuentes" del del directorio actual*/ $lista=ftp_nlist($x,"/miphp/fuentes"); # escribimos la lista de ficheros contenidos en ese directorio echo "Lista de ficheros del subdirectorio miphp/fuentes<br>"; foreach ($lista as $valor){ echo $valor,"<br>"; } # obtenemos una lista completa de los contenidos de ese subdirectorio $lista=ftp_rawlist($x,"/miphp/fuentes"); # ordenamos el array que contiene la lista anterior sort($lista); echo "Contenidos del subdirectorio miphp/fuentes<br>"; /* extrae los elementos del array eliminando los espacios repetidos mediante la funcion preg_replace en la que \s+ indica uno o ms espacios que sern sustituidos por uno solo (' ') */ foreach($lista as $v){ $v=preg_replace('/\s+/', ' ', $v); # imprimimos la cadena completa print "<br><br><br>".$v."<br>"; # convertimos la cadena en un array # utilizando los espacios como separadores $extrae=explode(" ",$v); # leemos los elementos del array y comentamos sus valores foreach($extrae as $indice=>$cont){ switch($indice){ case 0: print "El elemento de indice".$indice." es: ".$cont."<br>"; if (substr($cont,0,1)=="d"){ print "Es un directorio<br>"; }elseif(substr($cont,0,1)=="-"){ print "Es un fichero<br>"; } if (substr($cont,1,1)=="r"){ print "Tiene permisos de LECTURA<br>";

}elseif(substr($cont,1,1)=="-"){ print "No tiene permisos de LECTURA<br>"; } if (substr($cont,2,1)=="w"){ print "Tiene permisos de ESCRITURA<br>"; }elseif(substr($cont,2,1)=="-"){ print "No tiene permisos de ESCRITURA<br>"; } break; case 4: print "El tamao de este fichero es: ".$cont." bytes<br>"; break; case 8: print "El nombre del fichero o directorio es: ".$cont."<br>"; break; } } } # regresamos al directorio miphp ftp_chdir($x,"/miphp/"); /* creamos un subdirectorio (del directorio actual que es miphp) con nombre experimento anteponiendo @# para evitar mensajes de error en caso de que ya existiera */ @ftp_mkdir($x,"experimento"); /* copiamos el fichero enol.jpg desde el directorio que se indica en el tercer parmetro (miphp) al directorio del servidor FTP que se indica en el segundo parmetro. Le ponemos por nombre lago_enol.jpg */ ftp_put($x, "../miphp/experimento/lago_enol.jpg", "../miphp/enol.jpg",FTP_BINARY); # obtenemos el tamao del fichero transferido echo "El tamao de fichero tranferidos es: ", ftp_size($x,"../miphp/experimento/lago_enol.jpg")," bytes<br>"; /* escribimos la fecha de la ltima modificacin del fichero transferido que coincidir con la fecha y hora en la que se realiz la transferencia. Convertimos a formato de fecha convencional el tiempo UNIX que devuelve la funcin ftp_mdtm */ print "La fecha de modificacion del fichero es:"; print date("d-m-Y H:i:s",ftp_mdtm($x,"./experimento/lago_enol.jpg")); # cambiamos el nombre del fichero lago_enol.jpg por lago_covadonga.jpg # en el servidor FTP @ftp_rename($x,"./experimento/lago_enol.jpg", "./experimento/lago_covadonga.jpg"); /* creamos un enlace de descarga directa del fichero haciendo una llamada mediante el protocolo ftp:// utilizando la sintaxis: ftp://usuario:contrasea@nombre del servidor seguidos de la ruta (en el servidor FTP) y el nombre del fichero */ print "<BR><a href='ftp://webmaster:webmaster@localhost"; print "/miphp/experimento/lago_covadonga.jpg'> Descargar</a>"; /* transferimos al directorio miphp con nombre liborio.jpg un fichero procedente del directorio experimento cuyo nombre es lago_covadonga.jpg*/ ftp_get($x,"../miphp/liborio.jpg", "./experimento/lago_covadonga.jpg",FTP_ASCII); /* comprimimos un fichero alojado en miphp para transferirlo comprimido al servidor FTP */ #empezamos leyendo el fichero y guardndolo en una cadena $cadena=""; // inicializamos la variable con una cadena vaca $f1=fopen("cabina.jpg","r"); while (!feof($f1)) { $cadena .= fgets($f1,1024); }

fclose($f1); # comprimimos la cadena obtenida del fichero anterior $c1=gzencode($cadena,3,FORCE_GZIP); # guardamos la cadena comprimida en un fichero $f=fopen("cabina.jpg.gz","w"); fwrite($f,$c1); fclose($f); /* al servidor el fichero comprimido. No es necesario indicar la ruta actual ya que ha sido creado en el mismo directorio en el que se est ejecutando el script */ ftp_put($x, "./experimento/cabina.jpg.gz", "cabina.jpg.gz",FTP_BINARY); #eliminamos el fichero comprimido del directorio miphp unlink("cabina.jpg.gz"); # cerramos la conexin con el servidor ftp ftp_quit($x); # establecemos un enlace de descarga para el fichero comprimido print "<BR><a href='ftp://webmaster:webmaster@localhost"; print "/miphp/experimento/cabina.jpg.gz'>Descarga comprimido</a>"; ?> Cuidado! Observa los path de los ejemplos. Al anteponer ../ estaremos indicando una ruta absoluta desde al root de servidor FTP y con ./ aludimos a un subdirectorio del actual. Si vas a utilizar el ejemplo anterior presta mucha atencin a los nombres de los directorios y adecalos a la configuracin de tu servidor. Al ejecutar el script del ejemplo anterior por segunda vez (sobre Linux Ubuntu) puede aparecerte un mensaje de error del tipo overwrite permission denied. Este problema puede ser causado por un defecto de configuracin del sevidor FTP. Hemos podido comprobar que, algunas veces, por una extraa razn, aparecen en el fichero de configuracin dos lneas segudas dicendoAllowOverwrite Off y AllowOverwrite On. La configuracin correcta es AllowOverwrite On (para permitir sobreescribir). Bastara con eliminar la lnea marcada con Off (o reemplazar el Off por On) para solventar el problema.

Mensajes de correo Correo electrnico


PHP dispone de una funcin que permite el envo de todo tipo de mensajes de correo electrnico desde una pgina web. Son escasos los hosting que tienen activada esta funcin. El motivo aducido por muchos de ellos para establecer esta restriccin es el riesgo de abusosmediante los mensajes conocidos como spam. Como siempre, si tu inters es publicar y tienes necesidad de este servicio, procura consultar sobre la disponibilidad de este servicio.

Requisitos del sistema


La utilizacin de las funciones de correo electrnico requiere disponer de un servidor de correo electrnico instalado y activo y la modificacin de la configuracin inicial del fichero php.ini. Si no tienes instalado este servidor puedes hacerlo ahora. En la pgina Servidor de correo tienes detallados ambos procesos (instalacin y modificacin de php.ini).

Sintaxis
La forma ms simple de la funcin de correo es esta:

mail(destinatario,asunto,mensaje)

Dnde destinatario es la direccin del destinatario, asunto es el texto que aparecer como Asunto en el encabezado que recibir el destinatario y mensaje el texto que aparecer en el cuerpo del mensaje. No te olvides de escribir entre comillas esos tres parmetros de la funcin.

<? # insertamos la funcin mail (rojo) dentro de un condicional # para tener una confirmacin de envio y/o aviso de error # es algo muy habitual para conocer el exito de la ejecucin # de funciones if(mail("juan@mispruebas.as", "Mi primer mensaje","Este es el texto")){ print "mensaje enviado"; }else{ print "el mensaje no ha podido enviarse"; } ?>

Mensaje con cabeceras MIME


Una forma ms completa es la siguiente: mail(destario,asunto,mensaje,cabecera)

Como puedes ver, en este caso aadimos un nuevo parmetro a la funcin (cabez) que debe estar entre comillas y que puede contener, separando con comas, lo siguiente: From: Nombre <e-mail> El texto que escribas en el parmetro Nombre (cuidado, no lleva comillas!) ser el nombre del remitente, que aparecer en el campo De: cuando el destinatario reciba el mensaje. Donde dice e-mail es obligado escribir una direccin de correo que debe ir contenida entre < y >, tal como puedes ver en el ejemplo. Reply-To: correo En una nueva lnea, y sin cerrar las comillas de la cadena iniciada en el encabezado anterior, podemos indicar la direccin de respuesta del mensaje. La direccin que escribamos donde dice correo (fjate que no va entre comillas) ser la direccin a la que se enviar la respuesta si el destinatario una vez recibido tu correo desea responder mediante la opcin Responder de su programa de correo electrnico. Cc: correo1,correo2,... De igual forma que en el caso anterior en una nueva lnea y sin cerrar comillas podemos incluir en correo1, correo2, etctera, las direcciones de correo de las personas a las que deseamos enviar copia del mensaje. No te olvides de separar con comas cada una de las direcciones que, como puedes ver en los ejemplos, no van entre comillas. Bcc: correo1,correo2,... Esta opcin es idntica a la anterior en cuanto a su funcionamiento, con la nica diferencia de que esas direcciones no sern visibles por los destinatarios de los mensajes. X-Mailer:PHP/".phpversion() Es una frivolidad que se puede incluir en el encabezado del mensaje y que indica que versin de PHP con que ha sido creado.

Cuidado! Debemos insistir en sugerirte una especial atencin a la sintaxis de este tipo de scripts. Los contenidos generados por la funcin mail deben ser interpretados por el servidor de correo y tanto en este caso como en los que veremos a continuacin los requisitos de formato de estos servidores son muy estrictos. De no adaptarse exactamente a sus especificaciones pueden producirse efectos extraos tales como: envos incorrectos y/o apariencias indeseadas en los mensajes. <?

mail("juan@mispruebas.as","Varios destinatarios","Cuerpo del mensaje", "From: php <juan@mispruebas.as> Reply-To: andres@mispruebas.as Cc: perico@mispruebas.as,andres@mispruebas.as Bcc:andres@mispruebas.as,perico@mispruebas.as X-Mailer: PHP/" . phpversion()); ?>

En el ejemplo anterior insertaremos los nuevos elementos. Observa con mucha atencin la estructura del cdigo. Fjate que hemos insertado en lneas diferentes cada uno de los conceptos: From, Reply-To, etctera y que no hemos dejado ningn espacio al comienzo de esas lneas. No es por capricho ni por afn esttico. Si insertramos algn carcter delante de esas lneas se plantearan problemas en la estructura del mensaje y si no incluyramos un salto de lnea para cada uno de los conceptos tambin tendramos ese mismo problema. La sintaxis MIME es muy estricta en este sentido. Tengamos mucho cuidado en esto! Hay otra posibilidad sintctica como alternativa a los saltos de lnea ya conocida. Podramos escribir todo en una sola lnea sustituyendo los saltos de lnea que ves aqu por \n, de forma que el script tuviera un aspecto similar al siguiente: mail("juan@localhost","Asunto","Contenido","\nReply-To: ...\nCc:.....\nBcc: ...") donde, como ves, los \n sustituyen a los saltos de lnea.

El mismo ejemplo, utilizando variables


Aqu tenemos un ejemplo donde los parmetros de envo proceden de variables PHP. Recordemos que esas variables pueden transferirse mediante un formulario a un script que se encargue de su envo. Como puedes observar, hemos puesto las direcciones de los destinatarios de las copias visibles y ocultas en sendos arrays y hemos aadido una funcin que: lee los array, los une en una cadena separndolos con comas y, por ltimo, quita la ltima coma aadidautilizando la funcin substr.

<? #variables destinatario, asunto, texto, etc. $destino="andres@mispruebas.as"; $envia="Andrs PHP"; $remite="andres@mispruebas.as"; $asunto="Mensaje experimental"; $texto="Esto es una prueba. No es spam"; #array de destinatarios de copias visibles $c[0]="perico@mispruebas.as"; $c[1]="juan@mispruebas.as"; #crear la cadena con las direcciones # y aadir las comas de separacin $cco=""; //creamos la variable (vacia) foreach($c as $pegar) { $cco .=$pegar; $cco.=","; }; #quitamos la coma del final de la cadena $l=strlen($cco);

$cco=substr($cco,0,$l-1); #array de destinatarios de copias OCULTAS $b[0]="perico@mispruebas.as"; $b[1]="andres@mispruebas.as"; #crear la cadena con las direcciones # y aadir las comas de separacin $bco=""; //creamos la variable (vacia) foreach($b as $pegar) { $bco .=$pegar; $bco.=","; }; #quitamos la coma del final de la cadena $l=strlen($bco); $cco=substr($bco,0,$l-1); mail($destino, $asunto, $texto, "From: $envia <$remite> Reply-To: $remite Cc: $cco Bcc:$bco X-Mailer: PHP/" . phpversion()); ?>

Formatos MIME Funciones PHP requeridas para el envo de mensajes


Podrs ver a lo largo de los ejemplos de envo de mensajes de correo electrnico algunas funciones raras que vamos a comentar seguidamente: uniqid(prefijo,booleano)

Genera un identificador nico basado en la hora actual del sistema, expresada en microsegundos y con una longitud de 13 caracteres. El parmetro prefijo permite establecer una cadena o nmero (puede ser una cadena vaca) que se antepone al identificador generado por la funcin. Opcionalmente permite el segundo parmetro booleano que debe ser un valor booleano (TRUE FALSE) o tambin 0 1. Cuando este parmetro es TRUE aade al final de la cadena generada anteriormente otra subcadena numrica -generada aleatoriamente- de nueve dgitos, que refuerza la unicidad del identificador. preg_replace(busca, reemplaza, cadena)

Busca en la cadena especificada en el parmetro cadena (que puede ser una cadena o una variable que contenga una cadena) las subcadenas especificadas en busca (recuerda que debe llevar delante y detrs un carcter delimitador tal como puedes ver en lasexpresiones regulares) y sustituye esas subcadenas por el contenido del parmetro reemplaza. Devuelve la cadena modificada. strip_tags(cadena, excepciones)

Suprime todas las etiquetas HTML contenidas en cadena salvo las que se indiquen en excepciones. Por ejemplo: strip_tags($cadena, '<i><u><b>') eliminara todas las etiquetas HTML, salvo las indicadas aqu y sus correspondientes cierres. Si no se especifican excepcioneselimina todas las etiquetas.

base64_encode(cadena)

Devuelve una cadena codificada en base64. Esta codificacin se hace para permitir que las informaciones binarias puedan ser correctamente manipuladas por sistemas que no generan correctamente los 8 bits, tal como ocurre frecuentemente en los cuerpos de los mensajes de correo electrnico. base64_decode(cadena)

Realiza el proceso inverso a la anterior. Decodifica una cadena previamente codificada en base64. chunk_split(cadena, longitud, separador)

Devuelve una cadena obtenida al insertar en la cadena especificada -a intervalos del nmero de caracteres especificados en el parmetro numrico longitud- el contenido de una subcadena indicada en el parmetro separador. Por defecto -cuando no se especifican los parmetros- longitud es igual a 76 caracteres y el separador es la cadena \r\n (retorno y salto de lnea). Esta funcin se utiliza para convertir al formato especificado en la RFC 2045 (especificacin para MIME) las cadenas obtenidas porbase64_encode. Es el formato habitual de los ficheros adjuntos de los e-mail.

Formato de los mensajes de correo electrnico


En la pgina anterior hemos hablado acerca de la manera de enviar un e-mail y veamos la forma de insertar el cuarto parmetro de la funcin mail para incluir algunos elementos de los encabezados MIME. El formato de los mensajes est especificado en una serie de normas conocidas como el MIME (Multipurpose Internet Mail Extensions) en las que se establecen los contenidos y la sintaxis de las diferentes partes de un mensaje. Recordemos que la funcin mail(destinatario, asunto, mensaje, cabecera)

tiene cuatro parmetros y que las especificaciones del MIME aluden a los dos ltimos, es decir a mensaje (el cuerpo del mensaje) ycabecera que es el encabezado del mismo. Respecto a destinatario y asunto no se requieren ms comentarios que reiterar la necesidad de incluir esos valores (e-mail del destinatario y asunto) bien directamente, como parmetro en la funcin, o a travs de una variable tal como hemos comentado en la pgina anterior.

Cabeceras de los mensajes


Los diferentes elementos de la cabecera de un mensaje deben insertarse siempre separados por saltos de lnea bien pulsandoEnter o incluyendo la secuencia \n dentro de la misma de lnea. No pueden incluirse espacios, ni al comiezo de las nuevas lneas ni despus de \n, y las comillas que han de contener todo el encabezado se abren delante del primero de ellos y no se cierran hasta despus de haber escrito el ltimo. Pueden contener lo siguiente: Date: xxxxx

Date: debe escribirse con esta sintaxis exactamente. El parmetro xxxxx es una cadena que contendr la fecha de envo del mensaje y que puede obtenerse a travs de una de las funciones de fecha de PHP tal como puedes ver en el ejemplo. MIME-Version: 1.0

Este elemento de la cabecera especificar la versin MIME que ha de utilizar el cliente de correo para poder interpretar adecuadamente el contenido de los mensajes. From: remitente<e-mail>

Este elemento de la cabecera permite indicar el nombre del remitente (remitente) y su direccin e-mail siguiendo la sintaxis que se especifica. El nombre, como un elemento independiente y la direccin e-mail dentro de < >. Cuidado!

No debemos poner comillas ni en el nombre del remitente, ni en la direccin e-mail, ni en la fecha, etctera. Respecto a Cc: y Bcc: ; Reply-To: y X-Mailer: son vlidos los comentarios que hemos hecho en la pgina anterior. Si no se especifica lo contrario, los mensajes se envan como texto sin formato, pero existen opciones que permiten especificar el formato que ha de tener un mensaje. La especificacin de un formato obliga a incluir otro elemento en cabecera del mensaje: Content-Type:

Este elemento debe ir seguido de la especificacin en la que se indique el tipo de contenido. Tiene la sintaxis: tipo/subtipo. El MIME establece un gran variedad de opciones para este propsito. Hablaremos de dos de ellas: text/plain El text/plain es la opcin por defecto y seala que el contenido del mensaje es de tipo texto (text) y del subtipo sin formato (plain) text/html Como la opcin anterior, es tipo texto, pero en este caso, el subtipo es html con lo cual el mensaje se visualizar en formato htmlsiempre que el cliente de correo permita esa posibilidad. Los tipos anteriores permiten enviar mensajes simples (sin ficheros adjuntos) en uno u otro formato, pero el MIME nos da opciones para insertar dentro de un mismo mensaje elementos de diferentes tipos y subtipos. Las opciones de mayor inters son las siguientes: multipart/alternative Es la forma de especificar que el mensaje tiene varias partes (multipart) de las que el destinatario ha de ver una sola (alternative). Se podra utilizar en casos en los que sea necesario prever la posibilidad de que un mensaje con formato HTML pueda ser visualizado como texto plano cuando el cliente de correo no soporte HTML. Podemos hacer un mensaje a medida que se presentar de una forma u otra segn el cliente utilizado para leerlo. multipart/mixed Cuando en el Content-Type se establece el tipo multiparte y el subtipo mezclado (mixed) ser cuando tengamos la posibilidad deadjuntar ficheros al mensaje. Las diferentes partes de un mensaje deben ir separadas tanto en modo alternativo como mezclado y para ello hay que incluir un nuevo elemento en el encabezado. Se trata de un separador al que se llama boundary. boundary=cadena

Dentro del encabezado y siempre en lnea aparte (fjate que en los ejemplos o est en lnea aparte o aparece el \n) debemos incluir el elemento boundary= (sin smbolo de $ delante) y detrs del signo igual una cadena (en este caso entre comillas) que en principio puede ser una cadena cualquiera que no contenga espacios, aunque lo habitual es incluirla con el formato que podemos ver en los ejemplos.

El cuerpo del mensaje


En su formato ms simple el cuerpo del mensaje contiene nicamente texto, pero cuando se trata de multipartes deber contener necesariamente: los separadores de las diferentes partes, los encabezados de cada una de las partes y sus respectivos contenidos. La secuencia habra de ser de este tipo: Separador Content-type Los tipos y subtipos ms habituales son los siguientes. Para incluir textos: los ya mencionados text/plain y text/html. Para imgenes y segn el tipo de imagen: image/jpeg, image/gif. Para sonidos: audio/basic. Para vdeo: video/mpeg. Para ejecutables,

comprimidos y otros ficheros adjuntos: application/octet-stream. En cualquier caso, si quieres utilizar algn otro tipo de archivo puedes consultar en la web las especificaciones del MIME. Aparte de tipo/subtipo puede aadirse a Content-type -en el caso de texto- separado por punto y coma, la especificacin del tipo de alfabeto (charset=) seguida del tipo de codificacin (te sugerimos el "ISO-8859-1" que hace alusin al alfabeto latino). Cuando se trata de ficheros adjuntos deberemos poner, despus del punto y coma, name= seguido del nombre y extensin del fichero que se adjunta. Content-Transfer-Encoding Este apartado del encabezado puede especificar una de los siguientes codificaciones: 7BIT, 8BIT, BASE64, BINARY,QUOTEDPRINTABLE La transferencia codificada en 7bit representa la codificacin habitual en el formato ASCII de 7 bits. No permite caracteres ASCII con un cdigo mayor que 127. Quoted-printable constituye una de las alternativas al formato ASCII de 7 bits. Esta codificacin suele usarse cuando la mayora de los caracteres del mensaje puede escribirse con formato US ASCII de 7 bits. Prev que los caracteres con cdigos ASCII superiores a 127 se expresen mediante un mecanismo especial evitando, entre otras cosas, que las letras con tilde y algunos otros caracteres especiales se visualicen incorrectamente. Es la forma de codificacin ms recomendable para textos. La codificacin en base64 convierte cadenas binarias en cadenas de texto, con lo cual pueden ser enviadas de forma ms segura. Es la forma de codificacin habitual de las imgenes y los ficheros exe, zip, etctera. Content-Disposition Se utiliza nicamente cuando se insertan ficheros adjuntos. Permite dos opciones: inline o attachment. La primera permite que los contenidos se visualicen junto con el cuerpo del mensaje mientras que bajo la segunda apareceran como ficheros adjuntos. Este elemento del encabezado lleva separada por punto y coma una segunda parte. El filename=, donde se puede especificar entre comillas un nombre y una extensin (igual o distinta de la original) con la que se denominar al fichero en el mensaje recibido. Lectura del fichero Cuando se trata de insertar un fichero el proceso es el tpico de lectura de ficheros, es decir: Hay que crear el identificador de recurso del fichero en modo lectura. Recoger en una variable el buffer de lectura. Cerrar el fichero. Codificacin Una vez recogido en el fichero a transmitir en una variable, el paso siguiente es codificar esa variable.Utilizaremos la codificacin ms habitual y flexible base64 que requerir el uso de las funciones base64_encode y chunk_split. Cuerpo del mensaje La fase final del proceso es la de agrupar los diferentes trozos en una sola variable, que ser la que se insertar como parmetro texto en la funcin e-mail. Separador ..... otra parte ... Separador final

Cuidado! La insercin de ficheros adjuntos requiere que stos estn disponibles en el servidor por lo que, antes de enviarlos, habr que subirlos al servidor utilizando un proceso como el que hemos analizado cuando hablbamos deTransferencia de ficheros.

Las cabeceras MIME de un mensaje

Aqu tienes un ejemplo con los diferentes elementos del encabezado de un mensaje. Como ves, hemos incluido todos los elementos dentro de la funcin mail.

<? mail("juan@mispruebas.as", "Cabeceras", "Prueba de cabeceras", "Date: 24 de Junio de 2001 MIME-Version: 1.0 From: Estudiante Perico<perico@mispruebas.as> Cc:perico@mispruebas.as Bcc:andres@mispruebas.as Reply-To: perico@mispruebas.as X-Mailer: PHP/".phpversion()); ?>

Una forma un poco ms depurada del script anterior podra ser esta que incluimos aqu debajo. Sus particularidades son las siguientes: Recogemos los datos en variables e insertamos en la funcin mail esas variables La variable $cabecera tiene algunas singularidades: La vamos construyendo aadiendo subcadenas: date, from, etc. etc. En cada subcadena dejamos pegado el contenido a las comillas iniciales Al final de cada subcadena (cada una contiene un elemento del encabezado) insertamos \n para el carcter especial que indica a PHP un salto de lnea imprescindible

<? # datos del mensaje $destinatario="juan@mispruebas.as"; $titulo="Cabeceras en variables"; $mensaje="Nueva prueba de cabeceras"; $responder="andres@mispruebas.as"; $remite="andres@mispruebas.as"; $remitente="Otra vez Andres"; //sin tilde para evitar errores de servidor # cabeceras $cabecera ="Date: ".date("l j F Y, G:i")."\n"; $cabecera .="MIME-Version: 1.0\n"; $cabecera .="From: ".$remitente."<".$remite.">\n"; $cabecera .="Return-path: ". $remite."\n"; $cabecera .="X-Mailer: PHP/". phpversion()."\n"; if( mail($destinatario, $titulo, $mensaje,$cabecera)){ echo "mensaje enviado";}else{print "el mensaje no ha podido enviarse"; } ?>

Mensaje con contenido alternativo


<? # creamos la variables "salto" para "mayor comodidad # un salto es la secuencia retorno de carro-nueva lnea # dos saltos es algo similar pero duplicado $UN_SALTO="\r\n"; $DOS_SALTOS="\r\n\r\n"; # creamos el remitente, etc. y tambin la que parte que

# contiene el cdigo HTML del mensaje $destinatario="juan@mispruebas.as"; $titulo="Mensaje alternativo Texto Plano - HTML "; $mensaje="<html><head></head><body bgcolor='#ff0000'>"; $mensaje .="<font face='Arial' size=6>Prueba HTML. </font>"; $mensaje .="aqu pueden ir tildes: , , , , , </body></html>"; $responder="andres@mispruebas.as"; $remite="andres@mispruebas.as"; $remitente="Andres Perez y Perez"; // omitimos las tildes en encabezados para evitar errores de servidor # # # # creamos el separador de bloques del mensaje anteponiento "_separador" aunque podramos haber puesto "tiburcio" generamos un identificador unico utilizando un numero aleatorio como "semilla" y luego lo codificamos con la funcin md5

$separador ="_separador".md5 (uniqid (rand())); # creamos la variable cabecera con los elementos # ya utilizados en los ejemplos anteriores y ponemos al final # de cada elemento UN SALTO DE LINEA $cabecera $cabecera $cabecera $cabecera $cabecera $cabecera $cabecera = "Date: ".date("l j F Y, G:i").$UN_SALTO; .="MIME-Version: 1.0\n"; .="From: ".$remitente."<".$remite.">".$UN_SALTO; .= "Return-path: ". $remite.$UN_SALTO; .="Cc:perico@mispruebas.as".$UN_SALTO; .="Reply-To: ".$remite.$UN_SALTO; .="X-Mailer: PHP/". phpversion().$UN_SALTO;

# AQU DEFINIMOS EL CONTENIDO MULTIPART, fjate que lo acabamos con ";" $cabecera .="Content-Type: multipart/alternative;".$UN_SALTO; # insertamos BOUNDARY (fjate que dejo un espacio # en BLANCO DELANTE y ponemos al FINAL los DOS SALTOS DE LINEA $cabecera .=" boundary=$separador".$DOS_SALTOS; # # # # colocamos el primer separador(con los dos guiones delante) antes de insertar la primera parte del mensaje que es el texto plano para el caso de que el cliente de correo no soporte HTML

$texto_plano ="--$separador".$UN_SALTO; # especificamos el tipo de contenido y la codificacin # e inserto DOS SALTOS AL FINAL ya que ahi acaba la cabecera de esta parte $texto_plano .="Content-Type:text/plain; charset=\"ISO-8859-1\"".$UN_SALTO; $texto_plano .="Content-Transfer-Encoding: 7bit".$DOS_SALTOS; # cambiamos las etiquetas "<br>" por saltos de lnea # y luego quitamos todas las etiquetas HTML del cuerpo del mensaje # ya que el texto plano no debe llevar ese tipo de etiquetas $extractor= strip_tags(preg_replace("/<br>/", $UN_SALTO, $mensaje)); $texto_plano .=$extractor; # insertamos un nuevo separador para sealar el final # de la primera parte del mensaje y el comienzo de la segunda

# en este caso ponemos UN SALTO delante del separador ya que de lo contrario # al componer el mensaje se unira con la cadena texto_plano anterior # que no tiene SALTO DE LINEA AL FINAL $texto_html =$UN_SALTO."--$separador".$UN_SALTO; # especificamos el encabezado HTML para el siguiente bloque # y ponemos en la ultima lnea los DOS SALTOS DE LINEA $texto_html .="Content-Type:text/html; charset=\"ISO-8859-1\"".$UN_SALTO; $texto_html .="Content-Transfer-Encoding: 7bit".$DOS_SALTOS; #aado la cadena que contiene el mensaje $texto_html .= $mensaje; # insertamos SOLAMENTE un SALTO DE LINEA # estamos al funal del mensaje $texto_html .=$UN_SALTO; # unimos ambas cadenas para crear el cuerpo del mensaje $mensaje=$texto_plano.$texto_html; # enviamos el mensaje utilizando if( mail($destinatario, $titulo, $mensaje,$cabecera)){ echo "mensaje enviado ";}else{print "ha habido errores en el envio"; } ?>

Mensaje con ficheros adjuntos


<? # definimos estas variables igual que en el ejemplo anterior $UN_SALTO="\r\n"; $DOS_SALTOS="\r\n\r\n"; #incluimos en varias, asunto, un texto en HTML # remitente, etc. etc. $destinatario="perico@mispruebas.as"; $titulo="Mensaje con dos fichero adjuntos"; $mensaje="<html><head></head><body bgcolor=\"#ff0000\">"; $mensaje .="<font face=\"Arial\" size=6>Prueba HTML </font>"; $mensaje .="</body></html>"; $responder="andres@mispruebas.as"; $remite="andres@mispruebas.as"; $remitente="Andres otra vez"; # definimos el separador de parte # con el mismo procedimiento del ejemplo anterior $separador = "_separador_de_trozos_".md5 (uniqid (rand())); # insertamos los datos de la cabecera del mensaje $cabecera = "Date: ".date("l j F Y, G:i").$UN_SALTO;

$cabecera $cabecera $cabecera $cabecera $cabecera

.= "MIME-Version: 1.0".$UN_SALTO; .= "From: ".$remitente."<".$remite.">".$UN_SALTO; .= "Return-path: ". $remite.$UN_SALTO; .= "Reply-To: ".$remite.$UN_SALTO; .="X-Mailer: PHP/". phpversion().$UN_SALTO;

# especificamos el tipo de contenido mutipart/mixed # ya que ahora insertaremos ficheros de distinto tipo $cabecera .= "Content-Type: multipart/mixed;".$UN_SALTO; # insertamos el valor de boundary hacindola igual a $separador # y acabamos con DOS SALTOS porque es el FINAL DE LA CABECERA $cabecera .= " boundary=$separador".$DOS_SALTOS; /* Parte primera del envio -Mensaje en formato HTML ================================================ Separador inicial ------------------------------- */ $texto ="--$separador".$UN_SALTO; /* Encabezado parcial ------------------ */ /* especificamos que este primer elemento ser texto y que ir codificado en formato 7 bits */ $texto .="Content-Type: text/html; charset=\"ISO-8859-1\"".$UN_SALTO; $texto .="Content-Transfer-Encoding: 7bit".$DOS_SALTOS; /* Contenido de esta parte del mensaje -----------------------------------*/ # ya teniamos escrito el texto del mensaje ms arriba # simplemente lo aadimos a la cadena de texto $texto .= $mensaje; #la variable $texto recoge esta parte del documento # la uniremos al final con las siguientes /* Separador de partes -------------------- */

$adj1 = $UN_SALTO."--$separador".$UN_SALTO; /* Parte segunda de mensaje -Fichero adjunto n 1 ==================================================== */ /* Encabezado parcial ------------------ */ # especificamos el tipo de contenido image/jpeg # ya que ese ser el documento que vamos a enviar # ponemos el nombre del fichero (debemos tenerlo en el servidor # con ese mismo nombre) # establecemos in line como disposicin para que pueda ser visualizado # directamente en el cuerpo del mensajes # en filename le asignamos el nombre con el que queremos que sea # recibido por el destinatario # por ultimo especificamos la codificacion como base64 $adj1 .="Content-Type: image/jpeg;";

$adj1 $adj1 $adj1 $adj1

.=" name=\"casa08.jpg\"".$UN_SALTO; .="Content-Disposition: inline; "; .="filename=\"leoncio.jpg\"".$UN_SALTO; .="Content-Transfer-Encoding: base64".$DOS_SALTOS;

/* Lectura previa del fichero a adjuntar ------------------------------------------ */ # abrimos el fichero en modo lectura (r) # y leemos todo su contenido midiendo previamente # su longitud con filesize # recogemos en $buff el contenido del fichero # y cerramos despus $fp = fopen("casa08.jpg", "r"); $buff = fread($fp, filesize("casa08.jpg")); fclose($fp); /* Codificacin del fichero a adjuntar ------------------------------------------ */ # codificamos en base 64 y troceamos en lineas de 76 caracteres # y aadimos el resultado a la variable adj1 $adj1 .=chunk_split(base64_encode($buff)); /* Separador de partes -------------------- */

$adj2 = $UN_SALTO."--$separador".$UN_SALTO; /* Tercera parte de mensaje -Fichero adjunto n 2 ==================================================== */ /* Encabezado parcial ------------------ */ # los contenidos del encabezado son similares al caso anterior # con la salvedad de que el contenido es ahora # application/octet-stream ya que contiene un fichero ejecutable # y la disposicion es attachment, no tiene sentido tratar # de visualizar un fichero zip $adj2 .="Content-Type: application/octet-stream;"; $adj2 .=" name=\"apachito.zip\"".$UN_SALTO; $adj2 .="Content-Disposition: attachment; filename=\"apachito.zip\"".$UN_SALTO; $adj2 .="Content-Transfer-Encoding: base64".$DOS_SALTOS; /* Lectura previa del fichero a adjuntar ------------------------------------------ */ # abrimos el fichero en modo lectura (r) # y leemos todo su contenido midiendo previamente # su longitud con filesize # recogemos en $buff el contenido del fichero # y cerramos despus $fp = fopen("apachito.zip", "r"); $buff = fread($fp, filesize("apachito.zip")); fclose($fp); /* Codificacin del fichero a adjuntar -----------------------------------------$adj2 .=chunk_split(base64_encode($buff)); */

/*

Separador final YA NO HAY MAS PARTES ---------------------------------------- */

$adj2 .=$UN_SALTO."--$separador".$UN_SALTO; Unin de todas las PARTES ---------------------------------------- */ # unimos en la variable mensaje todos los elementos # y lo hacemos por el orden en el que fueron creados /* $mensaje=$texto.$adj1.$adj2; /* Envio del mensaje ---------------------------------------- */

if(mail($destinatario, $titulo, $mensaje,$cabecera)){ echo "mensaje enviado";}else{print "ha habido problemas"; } ?>

Imgenes dinmicas
Imgenes dinmicas
PHP permite la creacin dinmica de imgenes. Quiere esto decir que una imagen puede ser presentada en la pgina web sin necesidad de ser almacenada previamente en el servidor y, adems, con un contenido que puede ser modificado en cada instante. Esta posibilidad que ofrece PHP puede resultar muy til a la hora de presentar grficos estadsticos ya que permitira utilizar valores actualesobtenidos, por ejemplo, de una base de datos.

Requisitos del sistema


El manejo de imgenes dinmicas requiere que est instalada la librera de PHP llamada php_gd2.dll. En la versin de PHP que estamos manejando se instala por defecto, pero requiere que la configuracin de fichero php.ini tenga activada esta extensin. La hemos activado durante el proceso de configuracin de PHP (para usuarios de Windows) y en instalacin de Apache + PHP (para usuarios de Ubuntu). Podemos probar a abrir este enlace, info.php en el que habremos de encontrar algo similar a lo que ves en esta imagen:

Si eso ocurre habremos comprobado nuestra configuracin es la adecuada para utilizar las funciones PHP de este mbito y estaremos en disposicin de poder generar imgenes dinmicas.

Formatos GIF Aunque son abundantes los materiales que aluden a este formato grfico -incluso en las pginas oficiales PHP- los formatos GIF slo funcionan en modo lectura. Parece ser que existe un conflicto sobre los derechos de propiedad del algoritmo de compresin que se utiliza en los ficheros .gif y eso est obligando a los desarrolladores de PHP a abandonar este tipo de formato. Formatos PNG El formato de imgenes PNG (Portable Network Graphic) nos permite seguir disponiendo de un formato grfico de difusin gratuitacon una funcionalidad similar al GIF en lo que se refiere a transparencias y que junto con la posibilidad de usar tambin el formato JPG va a cubrir las necesidades grficas de esta utilidad de PHP.

Scripts para grficos estadsticos


Si en algn momento tienes inters en insertar en tus pginas grficos estadsticos, en esta direccinhttp://www.aditus.nu/jpgraph/index.php podrs encontrar una interesante coleccin de scripts listos para usar, con licencia gratuita para usos no comerciales.

Formatos soportados Formatos de imgenes


Aunque podemos obtener desde info.php informacin sobre los tipos de imgenes soportados por la versin en uso de PHP, existe una funcin que permite determinarlos. imagetypes()

Devuelve un campo de bits correspondiente a los formatos soportados por la versin de GD que estamos utilizando. Los formatos de imagen que PHP soporta actualmente son: GIF, JPG, PNG y WBMP. El conocimiento de estas posibilidades grficas puede sernos muy til a la hora de elegir entre los diferentes formatos grficos disponibles. Aqu tienes el cdigo fuente de un fichero que permite obtener informacin sobre los formatos soportados por tu versin de PHP.

Formatos soportados
<?php if (imagetypes() & IMG_GIF) { echo "El tipo GIF es soportado<br>"; }else{ echo "El tipo GIF NO ES SOPORTADO<BR>"; } if (imagetypes() & IMG_PNG) { echo "El tipo PNG es soportado<br>"; }else{ echo "El tipo PNG NO ES SOPORTADO<BR>"; } if (imagetypes() & IMG_JPG) { echo "El tipo JPG es soportado<br>"; }else{ echo "El tipo JPG NO ES SOPORTADO<BR>"; } if (imagetypes() & IMG_WBMP) { echo "El tipo WBMP es soportado<br>"; }else{ echo "El tipo WBMP NO ES SOPORTADO<BR>"; } ?>
ejemplo191.php

Creando imgenes Creacin de imgenes dinmicas


Una imagen dinmica es tan slo un script que contiene las instrucciones para la creacin de esa imagen. Para visualizar una imagen dinmica desde una pgina web basta con invocar el fichero que contiene el script desde la etiqueta clsica de insercin de imgenes de HTML <img src="imgxx.php"> donde imgxx.php ser el nombre del script que genera la imagen.

Primera etiqueta
Una vez conocidos los formatos que soporta nuestra versin, ya podemos generar imgenes utilizando cualquiera de esos formatos. Trabajaremos con dos de ellos: JPG y PNG. La primera instruccin que ha de contener cualquier script que deba generar imgenes ha de ser la siguiente: Header("Content-type: image/jpeg") si se trata de crear una imagen JPG o: Header("Content-type: image/png") si pretendemos que la imagen tenga formato PNG.

Cuidado! Cualquier etiqueta header (cabecera) ha de incluirse obligatoriamente al comienzo del script antes que ninguna otra instruccin y sin ninguna lnea en blanco que la preceda. Pondremos siempre estas instrucciones inmediatamente debajo de <? sin que las separe ninguna lnea en blanco.

Creacin de imgenes
Definida la etiqueta anterior tenemos que: crear la imagen, dibujarla y luego enviarla al navegador para que pueda ser visualizada y, por ltimo, (no es imprescindible pero si muy conveniente) borrarla, con el fin de liberar la memoria del servidor ocupada durante el proceso de generacin de la misma. Estas son las funciones PHP para esos procesos: $nombre = imagecreate(ancho, alto)

Con esta funcin se crea una imagen del tamao indicado en los parmetros ancho y alto (en pixels) que ser recogida en la variable$nombre. Esta funcin es idntica para cualquier formato de imagen.

Envo de imgenes al navegador


Para enviar imgenes al navegador (visualizacin) se usan funciones diferentes segn el tipo de imagen definida en Header. Si pretendemos que la imagen tenga formato JPG habremos puesto en Header la indicacin jpeg (cuidado! observa la sintaxis... jpeg). En este caso la funcin de visualizacin ser: Imagejpeg($nombre)

Si se tratara de una imagen en formato PNG (recuerda que debe estar definido en Header) la sintaxis sera: Imagepng($nombre)

Eliminando imgenes de la memoria


Para borrar imgenes de la memoria del servidor (que no del navegador) se utiliza la siguiente sintaxis: Imagedestroy($nombre)

El primer ejemplo
<?php /* insertamos la cabecera sin ninguna contenido (ni siquiera lnea en blanco) qantes <php */ Header("Content-type: image/jpeg"); /* establecemos las dimensiones de la imagne y la creamos */ $im = imagecreate(200,200); /* mostramos las imagen */ Imagejpeg($im); /* la eliminamos de la memoria */ Imagedestroy($im); ?>
Ver ejemplo192.php

Colores
Creacin de colores
PHP permite crear una paleta de colores. Para ello se pueden crear variables de color (con independencia del formato utilizado) mediante la siguiente funcin: $color=imagecolorallocate ($nombre, rojo, verde, azul)

donde la variable $color recoge el color resultante de mezclar los colores primarios indicados en rojo, verde y azul que sern nmeros enteros comprendidos entre 0 y 255 y que especifican la intensidad de las luces roja, verde y azul utilizadas para la obtencin del color y donde $nombre es la variable utilizada para la creacin de la imagen por imagecreate Se pueden definir tantos colores como se deseen tan slo con utilizar nombres de variables distintos para cada uno de ellos.

Aplicar colores de fondo


Para aplicar un color de fondo a una imagen (no importa el tipo del formato) se utiliza la siguiente funcin: Imagefill($nombre,x,y,$color)

donde $nombre es la variable que contiene la imagen, x e y son las coordenadas del punto de la imagen a partir del cual se aplica el relleno y $color el color (previamente definido) que se pretende aplicar a la imagen. Mediante esta funcin todos los puntos colindantes con el de coordenadas x,y que tengan su mismo color sern rellenados con el color especificado en la variable $color. Aqu tienes dos ejemplos de creacin de una imagen con un color de fondo. Se diferencian nicamente en el formato. La primera ser una imagen JPG y la segunda ser PNG.

<?php Header("Content-type: image/jpeg"); $im = imagecreate(200,200); /* creamos un color de fondo con nombre $fondo */ $fondo=imagecolorallocate ($im, 0, 0, 200); /* aplicamos el clor al fondo */

Imagefill ($im, 0, 0, $fondo); Imagejpeg($im); Imagedestroy($im); ?>


Ver ejemplo193.php

<?php Header("Content-type: image/png"); $im = imagecreate(200,200); /* creamos un color de fondo con nombre $fondo */ $fondo=imagecolorallocate ($im, 0, 0, 200); /* aplicamos el clor al fondo */ Imagefill ($im, 0, 0, $fondo); Imagepng($im); Imagedestroy($im); ?>
Ver ejemplo194.php

Figuras
Rectngulos sin relleno
Para dibujar un rectngulo sin relleno (solo las lneas) se utiliza la siguiente funcin: imagerectangle($nombre, x0, y0, x1, y1, $color)

Dnde $nombre es el nombre de la imagen, x0, y0 son las coordenadas del vrtice superior izquierdo y x1, y1 las coordenadas delvrtice inferior derecho y $color el color que pretendemos asignar a los lados del rectngulo. El punto (0,0) siempre es la esquina superior izquierda de la imagen y recuerda que las lneas no tienen un color distinto al del fondo no se visualizar el rectngulo.

<?php Header("Content-type: image/jpeg"); $im = imagecreate(200,200); $fondo=imagecolorallocate ($im, 0, 0, 200); $linea=imagecolorallocate ($im, 255, 255, 255); Imagefill ($im, 0, 0, $fondo); imagerectangle ($im, 10, 10, 190, 190, $linea); Imagejpeg($im); Imagedestroy($im); ?>
Ver ejemplo195.php

<?php Header("Content-type: image/png"); $im = imagecreate(200,200); $fondo=imagecolorallocate ($im, 0, 0, 200); $linea=imagecolorallocate ($im, 255, 255, 255); Imagefill ($im, 0, 0, $fondo); imagerectangle ($im, 10, 10, 190, 190, $linea); Imagepng($im); Imagedestroy($im); ?>

Ver ejemplo196.php

Rectngulos con relleno


Para dibujar un rectngulo con relleno se utiliza la siguiente funcin: imagefilledrectangle($nombre, x0, y0, x1, y1, $color)

Los parmetros son idnticos a los del caso anterior con la nica diferencia de que en este caso el rectngulo aparecer relleno con el color elegido.

<?php Header("Content-type: image/jpeg"); $im = imagecreate(200,200); $fondo=imagecolorallocate ($im, 0, 0, 200); $blanco=imagecolorallocate ($im, 255, 255, 255); $amarillo=imagecolorallocate ($im, 255, 255,0); /*aplicamos un color al fondo de la imagen */ Imagefill ($im, 0, 0, $fondo); /* trazamos un rectangulo en blanco */ imagerectangle ($im, 10, 10, 190, 190, $blanco); /* dentro del rectngulo anterior insertamos otro coloreado */ imagefilledrectangle ($im, 20, 20, 180, 180, $amarillo); Imagejpeg($im); Imagedestroy($im); ?>
Ver ejemplo197.php

<?php Header("Content-type: image/png"); $im = imagecreate(200,200); $fondo=imagecolorallocate ($im, 0, 0, 200); $blanco=imagecolorallocate ($im, 255, 255, 255); $amarillo=imagecolorallocate ($im, 255, 255,0); /*aplicamos un color al fondo de la imagen */ Imagefill ($im, 0, 0, $fondo); /* trazamos un rectangulo en blanco */ imagerectangle ($im, 10, 10, 190, 190, $blanco); /* dentro del rectngulo anterior insertamos otro coloreado */ imagefilledrectangle ($im, 20, 20, 180, 180, $amarillo); Imagepng($im); Imagedestroy($im); ?>
Ver ejemplo198.php

Polgonos con relleno


Para trazar un polgono con un color de fondo son necesarias dos operaciones: Crear un array con las coordenadas de cada uno de sus vrtices. Aplicar la funcin que dibuja polgonos de este tipo. La creacin del array podra hacerse as: $vertices=(x0, y0, x1, y1,... xn, yn )

dnde se iran introduciendo las coordenadas de los sucesivos vrtices del polgono (x e y de cada vrtice). Una vez creados los vrtices aplicaranos la siguiente funcin: imagefilledpolygon($nombre, $vertices, n vertices , $color)

donde $nombre es el nombre de la imagen, $vertices es el array que contiene las coordenadas de los vrtices, n vertices es el nmero de vrtices del polgono y $color es el color de relleno.

<?php Header("Content-type: image/jpeg"); $esquinas=array(20,100,100,180,180,100,100,20); $im = imagecreate(200,200); $fondo=imagecolorallocate ($im, 0, 0, 200); $blanco=imagecolorallocate ($im, 255, 255, 255); $amarillo=imagecolorallocate ($im, 255, 255,0); Imagefill ($im, 0, 0, $fondo); imagerectangle ($im, 10, 10, 190, 190, $blanco); imagefilledrectangle ($im, 20, 20, 180, 180, $amarillo); imagefilledpolygon ($im, $esquinas, 4, $blanco); Imagejpeg($im); Imagedestroy($im); ?>
Ver ejemplo199.php

<?php Header("Content-type: image/png"); $esquinas=array(20,100,100,180,180,100,100,20); $im = imagecreate(200,200); $fondo=imagecolorallocate ($im, 0, 0, 200); $blanco=imagecolorallocate ($im, 255, 255, 255); $amarillo=imagecolorallocate ($im, 255, 255,0); Imagefill ($im, 0, 0, $fondo); imagerectangle ($im, 10, 10, 190, 190, $blanco); imagefilledrectangle ($im, 20, 20, 180, 180, $amarillo); imagefilledpolygon ($im, $esquinas, 4, $blanco); Imagepng($im); Imagedestroy($im); ?>
Ver ejemplo200.php

Polgonos sin relleno


Su funcionamiento es idntico al anterior en tanto requiere que se defina el array de coordenadas de los vrtices y los parmetros de la funcin son los mismos indicados en el caso anterior. Slo se modifica el nombre de la funcin que en este caso es: imagepolygon($nombre, $vertices, n vertices , $color)

<?php Header("Content-type: image/jpeg"); $esquinas=array(20,100,100,180,180,100,100,20); $im = imagecreate(200,200); $fondo=imagecolorallocate ($im, 0, 0, 200); $blanco=imagecolorallocate ($im, 255, 255, 255); $rojo=imagecolorallocate ($im, 255,0, 0); $amarillo=imagecolorallocate ($im, 255, 255,0); Imagefill ($im, 0, 0, $fondo);

imagerectangle ($im, 10, 10, 190, 190, $blanco); imagefilledrectangle ($im, 20, 20, 180, 180, $amarillo); imagepolygon ($im, $esquinas, 4, $rojo); Imagejpeg($im); Imagedestroy($im); ?>
Ver ejemplo201.php

<?php Header("Content-type: image/png"); $esquinas=array(20,100,100,180,180,100,100,20); $im = imagecreate(200,200); $fondo=imagecolorallocate ($im, 0, 0, 200); $blanco=imagecolorallocate ($im, 255, 255, 255); $rojo=imagecolorallocate ($im, 255,0, 0); $amarillo=imagecolorallocate ($im, 255, 255,0); Imagefill ($im, 0, 0, $fondo); imagerectangle ($im, 10, 10, 190, 190, $blanco); imagefilledrectangle ($im, 20, 20, 180, 180, $amarillo); imagepolygon ($im, $esquinas, 4, $rojo); Imagepng($im); Imagedestroy($im); ?>
Ver ejemplo202.php

Elipses, circunferencias y arcos


Mediante una nica funcin podremos dibujar elipses, circunferencias y arcos. Es la siguiente: imagearc($nom, Xcentro, Ycentro , a, b, anguloinicial, angulofinal, $color)

Los parmetros de esta funcin son los siguientes: $nombre es el nombre de la imagen. Xcentro e Ycentro las coordenadas del centro de la elipse o circunferencia. a es la longitud del semieje horizontal de la elipse. b es la longitud del semieje vertical de la elipse. anguloinicial es la posicin angular del radio inicial del arco y se expresa en grados sexagesimales. angulofinal es la posicin angular del radio final del arco tambin en grados sexagesimales. $color es el color con el que se dibujar la lnea. Respecto a los ngulos, CERO GRADOS coincide con el cero trigonomtrico pero el sentido es contrario, es decir, el de las agujas del reloj. Obviamente, para dibujar una circunferencia basta con hacer iguales los valores de a y de b y fijar los puntos inicial y final en 0 y 360 respectivamente.

<?php Header("Content-type: image/jpeg"); $esquinas=array(20,100,100,180,180,100,100,20); $im = imagecreate(200,200); $fondo=imagecolorallocate ($im, 0, 0, 200); $blanco=imagecolorallocate ($im, 255, 255, 255); $amarillo=imagecolorallocate ($im, 255, 255,0);

$rojo=imagecolorallocate ($im, 255, 0,0); Imagefill ($im, 0, 0, $fondo); imagerectangle ($im, 10, 10, 190, 190, $blanco); imagefilledrectangle ($im, 20, 20, 180, 180, $amarillo); imagepolygon ($im, $esquinas, 4, $blanco); imagearc ($im, 100, 100, 160, 160, 0, 360, $fondo); imagearc ($im, 100, 100, 160, 100, 0, 360, $rojo); imagearc ($im, 100, 100, 100, 160, 0, 360, $rojo); Imagejpeg($im); Imagedestroy($im); ?>
Ver ejemplo203.php

<?php Header("Content-type: image/png"); $esquinas=array(20,100,100,180,180,100,100,20); $im = imagecreate(200,200); $fondo=imagecolorallocate ($im, 0, 0, 200); $blanco=imagecolorallocate ($im, 255, 255, 255); $amarillo=imagecolorallocate ($im, 255, 255,0); $rojo=imagecolorallocate ($im, 255, 0,0); Imagefill ($im, 0, 0, $fondo); imagerectangle ($im, 10, 10, 190, 190, $blanco); imagefilledrectangle ($im, 20, 20, 180, 180, $amarillo); imagepolygon ($im, $esquinas, 4, $blanco); imagearc ($im, 100, 100, 160, 160, 0, 360, $fondo); imagearc ($im, 100, 100, 160, 100, 0, 360, $rojo); imagearc ($im, 100, 100, 100, 160, 0, 360, $rojo); Imagepng($im); Imagedestroy($im); ?>
Ver ejemplo204.php

Dibujando sobre una imagen de fondo


PHP permite crear imgenes utilizando como fondo una prEexistente. Para ello es necesario cambiar la instruccin $nom = imagecreate(x,y) por $nom= imagecreatefrompng (nombre_de_la_imagen_de_fondo) si se trata de utilizar una imagen con formato PNG o$nom= imagecreatefromjpeg (nombre_de_la_imagen_de_fondo) cuando se trata de usar una imagen JPG. La imagen resultante puede tener formato JPG o PNG dependiendo de lo que se especifique en Header y como formato de salida independientemente del formato que pudiera tener la imagen utilizada como fondo de la composicin

<?php Header("Content-type: image/jpeg"); $esquinas=array(20,100,100,180,180,100,100,20); $im = imagecreatefrompng('./images/cruz.png'); $fondo=imagecolorallocate ($im, 0, 0, 200); $blanco=imagecolorallocate ($im, 255, 255, 255); $amarillo=imagecolorallocate ($im, 255, 255,0); $rojo=imagecolorallocate ($im, 255, 0,0); Imagefill ($im, 0, 0, $fondo); imagerectangle ($im, 10, 10, 190, 190, $blanco); imagefilledrectangle ($im, 20, 20, 180, 180, $amarillo); imagepolygon ($im, $esquinas, 4, $blanco); imagearc ($im, 100, 100, 160, 160, 0, 360, $fondo); imagearc ($im, 100, 100, 160, 100, 0, 360, $rojo); imagearc ($im, 100, 100, 100, 160, 0, 360, $rojo); Imagejpeg($im); Imagedestroy($im); ?>

Ver ejemplo204a.php Imagen original PNG Imagen resultante JPG

Como puedes comprobar en los ejemplos, el tamao de la imagen es el mismo de la utilizada como fondo.

Guardando imgenes
Las imgenes que son creadas mediante la sintaxis anterior no se guardan en el servidor. Si se pretendiera guardarlas, hay que modificar la sintaxis de las etiquetas: Imagepng($nombre) o Imagejpeg($nombre) aadiendo un segundo parmetro con el nombre y la extensin del fichero que vamos de guardar. As por ejemplo: Imagepng($nombre, "mi_imagen.png") o Imagejpeg($nombre, "mi_imagen.jpg") guardaran en el servidor las imgenes creadas con los nombres mi_imagen.png o mi_imagen.jpg en el directorio actual del servidor.>

Cuidado! No dejes NUNCA lneas en blanco entre la etiqueta <? de comienzo del script y la lnea que contiene Header Si escribiramos el script anterior sustituyendo image/jpeg por image/png e Imagejpeg($im) por Imagepng($im)no visualizaramos nada. El formato jpg a falta de especificaciones considera la imagen con negro como color de fondo, pero png requiere que ese color sea especificado.

Utilizacin de imgenes dinmicas


En todos los ejemplos anteriores hemos podido visualizar las imgenes con slo llamarlas desde el navegador, de la misma forma que podramos visualizar cualquier otra imagen. Pero las imgenes dinmicas pueden ser insertadas en una pgina web de la misma forma que cualquier otra imagen. Aqu tienes un ejemplo donde se recogen en una pgina web todas las imgenes dinmicas creadas anteriormente.
ejemplo205.php Ver cdigo fuente

Si observas el cdigo fuente vers que es exactamente el mismo que se utiliza para insertar una imagen normal, con la nica diferencia de que aqu el nombre de la imagen ser el mismo que el del script PHP que la genera.

Imgenes con lneas y textos Trazando segmentos


La funcin PHP que permite dibujar segmentos rectilneos es la siguiente: imageline($nombre, x0, y0, x1,y1,$color)

donde: $nombre es el nombre de la variable definida mediante imagecreate, x0 e y0 son las coordenadas de uno de los extremos; x1e y1 son las coordenadas del otro extremo y $color es la variable de color con el que ser dibujada la lnea. Tal como puedes observar en los primeros ejemplos de esta pgina, PHP utiliza como fondo de la imagen el primer color definido por la funcin: ImageColorAllocate. Esta opcin de PHP nos obliga a definir dos colores distintos para conseguir la visibilidad de las lneas.

Aunque presentaremos nicamente el cdigo fuente de una de las imgenes, para hacer la comprobacin de las funciones y las diferencias de visualizacin insertaremos dos ejemplos, uno en formato PGN y otro en JPG. Recuerda que las nicas diferencias entre ambos radican en utilizar: Header("Content-type: image/png") o Header("Contenttype: image/jpeg") y en las funciones Imagepng Imagejpeg.

<?php Header("Content-type: image/png"); $im = imagecreate(200,200); $fondo=ImageColorAllocate ($im,0,0,255); $linea=ImageColorAllocate ($im,255,255,255); imageline($im,0,0,200,200,$linea); Imagepng($im); Imagedestroy($im); ?>
Ver ejemplo211.php Formato PNG Ver ejemplo212.php Formato JPG

Crear transparencias
Si deseamos que un color determinado se comporte como si fuera transparente debemos utilizar la funcin: imagecolortransparent ($nombre ,$color).

donde: $nombre es el nombre de la variable definida mediante imagecreate, y $color es el color que pretendemos hacer transparente. No olvides estos dos pequeos detalles: Si pretendes lograr un fondo transparente debes hacer transparente el primero de los colores definidos. Esta funcin slo tiene sentido en imgenes PNG que son las nicas que permiten zonas transparentes. Recuerda que JPG no las permite.

<?php Header("Content-type: image/png"); $im = imagecreate(200,200); $fondo=ImageColorAllocate ($im,0,0,255); $linea=ImageColorAllocate ($im,255,0,0); imagecolortransparent ($im ,$fondo); imageline($im,0,0,200,200,$linea); Imagepng($im); Imagedestroy($im); ?>
Ver ejemplo213.php Formato PNG Ver ejemplo214.php Formato JPG

Insertando textos
Para insertar textos dentro de una imagen hemos de recurrir a una de estas funciones: imagechar ($imagen, tamao, x, y, $texto, $color)

Requiere que la variable $texto contenga una cadena definida con anterioridad. Mediante esta funcin se inserta el primer carcter de la cadena con orientacin horizontal. Los parmetros de la funcin son los siguientes: $nombre el nombre de la variable con la que fue definida por imagecreate tamao es un nmero comprendido entre UNO y CINCO que asigna el tamao de la letra de menor a mayor. x e y son las coordenadas del punto donde se colocar la esquina superior izquierda del carcter a representar. $texto es la cadena de texto de la que se extraer el primer carcter, el nico que se ver en la imagen. $color es el color del carcter a representar.

<?php Header("Content-type: image/png"); $im = imagecreate(150,150); $t1="Tamao 1"; $t2="Tamao 2"; $t3="Tamao 3"; $t4="Tamao 4"; $t5="Tamao 5"; $fondo=imagecolorallocate ($im, 0, 0, 200); $amarillo=imagecolorallocate ($im, 255, 255,0); imagechar ($im, 1, 0, 0, $t1, $amarillo); imagechar ($im, 2, 20, 20, $t2, $amarillo); imagechar ($im, 3, 40, 40, $t2, $amarillo); imagechar ($im, 4, 60, 60, $t2, $amarillo); imagechar ($im, 5, 80, 80, $t2, $amarillo); Imagepng($im); imagedestroy($im); ?>
Ver ejemplo216.php Formato PNG Ver ejemplo217.php Formato JPG

imagecharup ($imagen, tamao, x, y, $texto, $color)

Su funcionamiento es similar al de la funcin anterior, con la nica diferencia de que inserta el carcter con orientacin vertical. Lascoordenadas de insercin tambin se corresponden con las de la esquina superior izquierda del carcter pero, recuerda que ahora estar girado y que, por lo tanto, ese punto coincidir con parte inferior izquierda de la imagen del carcter.

<?php Header("Content-type: image/png"); $im = imagecreate(150,150); $t1="Tamao 1"; $t2="Tamao 2"; $t3="Tamao 3"; $t4="Tamao 4"; $t5="Tamao 5"; $fondo=imagecolorallocate ($im, 0, 0, 200); $amarillo=imagecolorallocate ($im, 255, 255,0); imagecharup ($im, 1, 10, 10, $t1, $amarillo); imagecharup ($im, 2, 20, 20, $t2, $amarillo); imagecharup ($im, 3, 40, 40, $t2, $amarillo); imagecharup ($im, 4, 60, 60, $t2, $amarillo); imagecharup ($im, 5, 80, 80, $t2, $amarillo); Imagepng($im); imagedestroy($im); ?>
Ver ejemplo218.php Formato PNG Ver ejemplo219.php Formato JPG

imagestring ($imagen, tamao, x, y, $texto, $color)

Esta funcin se comporta de forma similar a imagechar. La nica diferencia entre ambas es que mientras imagechar inserta slo el primer carcter, en el caso de imagestring se inserta la cadena completa. Los parmetros de ambas funciones son los mismos. Si la cadena desborda los lmites de la imagen slo se visualizar la parte de la misma contenida dentro de stos.

<?php Header("Content-type: image/png"); $im = imagecreate(150,150); $t1="Tamao 1"; $t2="Tamao 2"; $t3="Tamao 3"; $t4="Tamao 4"; $t5="Tamao 5"; $fondo=imagecolorallocate ($im, 0, 0, 200); $amarillo=imagecolorallocate ($im, 255, 255,0); imagestring ($im, 1, 10, 20, $t1, $amarillo); imagestring ($im, 2, 10, 40, $t2, $amarillo); imagestring ($im, 3, 10, 60, $t3, $amarillo); imagestring ($im, 4, 10, 80, $t4, $amarillo); imagestring ($im, 5, 10, 100, $t5, $amarillo); Imagepng($im); imagedestroy($im); ?>
Ver ejemplo220.php Formato PNG Ver ejemplo221.php Formato JPG

imagestringup ($imagen, tamao, x, y, $texto, $color)

Inserta una cadena completa con orientacin vertical y sus parmetros son idnticos a los comentados cuando nos hemos referido aimagecharup.

<?php Header("Content-type: image/png"); $im = imagecreate(150,150); $t1="Tamao 1"; $t2="Tamao 2"; $t3="Tamao 3"; $t4="Tamao 4"; $t5="Tamao 5"; $fondo=imagecolorallocate ($im, 0, 0, 200); $amarillo=imagecolorallocate ($im, 255, 255,0); imagestringup ($im, 1, 10, 100, $t1, $amarillo); imagestringup ($im, 2, 20, 100, $t2, $amarillo); imagestringup ($im, 3, 40, 100, $t3, $amarillo); imagestringup ($im, 4, 60, 100, $t4, $amarillo); imagestringup ($im, 5, 80, 100, $t5, $amarillo); Imagepng($im); imagedestroy($im); ?>
Ver ejemplo222.php Formato PNG Ver ejemplo223.php Formato JPG

Tipos de letra
Todas las funciones anteriores utilizan siempre la fuente predefinida por PHP y slo permiten los cinco tamaos que hemos podido ver en los ejemplos. Afortunadamente lo veremos en la pgina siguiente PHP tambin permite usar fuentes TrueType y aplicarlas en la creacin de imgenes.

Manejando fuentes Utilizando fuentes TrueType


Si has ledo los comentarios de la pgina anterior recordars que para usar estas funciones es preciso que estn instaladas las libreras FreeType y que, adems, conozcamos el path de directorio que contiene las fuentes TrueType. Hemos creado un subdirectorio llamado fuentes y lo hemos incluido en directorio donde estn alojadas estas pginas. En ese subdirectorio hemos incluido dos fuentes TrueType manteniendo en una de ellas el nombre original (arial.ttf) y renombrado la otra comofuente2.ttf. Como podrs comprobar en los ejemplos, no hay problema alguno por el hecho de renombrar las fuentes.

Escribiendo con fuentes TrueType


La funcin PHP que nos permite insertar este tipo de textos en imgenes dinmicas es la siguiente: Imagettftext($nombre, tamao, angulo, x, y, $color, $fuente, $texto)

donde: $nombre es, como siempre, el nombre de la imagen. tamao es un nmero entero que indica el el tamao de la fuente. angulo es el giro expresado en grados sexagesimales que pretendemos que tenga la cadena de texto. Si ang=0 el texto aparecer escrito en horizontal. x e y son las coordenadas del punto de inicio de la insercin del texto. Ese punto coincide con la esquina inferior izquierda del rectngulo imaginario que contiene el texto. $color es el color a utilizar en el texto. fuente es una cadena de texto que contiene el path y el nombre de la fuente. Observa los ejemplos. $texto es el nombre de la variable que contiene el texto a insertar.

Texto True Type horizontal


<?php Header("Content-type: image/png"); $im = imagecreate(400,300); $fondo=imagecolorallocate ($im, 255, 255, 210); $rojo=imagecolorallocate ($im, 255, 0, 0); $texto="PHP"; Imagettftext($im, 40, 0, 100, 270, $rojo,"./fuentes/fuente2.ttf", $texto); Imagepng($im); imagedestroy($im); ?>
Ver ejemplo224.php Formato PNG Ver ejemplo225.php Formato JPG

Texto True Type girado


<?php Header("Content-type: image/png"); $im = imagecreate(400,300); $fondo=imagecolorallocate ($im, 255, 255, 210); $rojo=imagecolorallocate ($im, 255, 0, 0); $texto="Me gusta PHP"; Imagettftext($im, 40, 30, 100, 270, $rojo, "./fuentes/fuente2.ttf", $texto); Imagepng($im); imagedestroy($im); ?>
Ver ejemplo226.php Formato PNG Ver ejemplo227.php Formato JPG

Cuidado! Las rutas (path) de la las fuentes utilizadas por Imagettftext pueden darte un montn de quebraderos de cabeza. Las rutas relativas que ves en estos ejemplos no parecen dar problema alguno. Sin embargo si hiciramos algo como crear una variable previa del tipo: $ruta="fuentes"; y luego sustituir "./fuentes/fuente2.ttf" por: "./". $ruta."/fuente2.ttf" que aparentemente da el mismo resultado ./fuentes/fuente2.ttf se nos genera un error de fuente no encontrada. La solucin que parece ser ms efectiva es huir como alma que lleva el diablo del uso de variables en la asignacin de rutas de las fuentes. Vamos, escribir la ruta completa a pico y pala!

Colocando los textos


PHP dispone de una funcin que permite determinar las dimensiones de una caja de texto (el rectngulo imaginario que rodea el texto). $rect= ImageTTFBBox (tamao, angulo, fuente, $texto) donde tamao es el tamao de la fuente a utilizar, angulo es el ngulo de rotacin del texto que tendra valor cero en el caso de orientacin horizontal, fuente es el path y nombre de la fuente a a utilizar, $texto es el nombre de la variable que contiene el texto a incluir.

La variable $rect recoge un array escalar cuyos valores son las coordenadas de las cuatro esquinas de la caja de texto. Los ndices correspondientes a cada uno de los elementos de ese array son los siguientes: Inferior izquierdo. Sus coordenadas son: $rect[0] y $rect[1] Inferior derecho. Sus coordenadas son: $rect[2] y $rect[3] Superior derecho. Sus coordenadas son: $rect[4] y $rect[5] Superior izquierdo. Sus coordenadas son: $rect[6] y $rect[7] Respecto a estas coordenadas, habremos de tener en cuenta lo siguiente: Las correspondientes al vrtice inferior izquierdo son siempre (0,0). Los puntos situados por encima del (0,0) tienen ordenada negativa. Las abscisas de los puntos situados a la izquierda del (0,0) son negativas.

Centrando textos
Aqu tienes un ejemplo donde utilizando ImageTTFBox e ImageTTFText se puede centrar un texto -tanto si es horizontal como si est girado- con relacin a un punto. En este ejemplo, el punto de referencia para el centrado es (200,150) que es el centro de la imagen. Las coordenadas de ImageTTFText, como puedes ver, estn calculadas usando las coordenadas de ese punto de referencia y los valores del array generado por ImageTTFBox. Si la variable que contiene el array generado por ImageTTFBox se llama $pepa, las coordenadas del centro del rectngulo imaginarioson $pepa[4]/2 y $pepa[5]/2. Partiendo de esos valores, si queremos centrar el texto sobre un punto de la imagen cuyas coordenadas son (X,Y) nos basta con escribir como parmetros de la funcin ImageTTFText los siguientes: Abscisa= X - $pepa[4]/2 Ordenada= Y - $pepa[5]/2 Este procedimiento es vlido tanto para textos horizontales como para textos girados.

<?php Header("Content-type: image/png"); $im = imagecreate(400,300); $fondo=imagecolorallocate ($im, 255, 255, 210); $gris=imagecolorallocate ($im, 160, 160,160); $rojo=imagecolorallocate ($im, 255, 0, 0); $texto="El mundo del PHP"; $texto1="lleno de posibilidades"; $marco= ImageTTFBBox (40, 0, "./fuentes/arial.ttf", $texto); Imagettftext($im,40,0,200-$marco[4]/2,150-$marco[5]/2, $gris,"./fuentes/arial.ttf",$texto); $marco1= ImageTTFBBox (30, 30, "./fuentes/fuente2.ttf", $texto1); Imagettftext($im,30,30,200-$marco1[4]/2,150-$marco1[5]/2,$rojo,"./fuentes/fuente2.ttf", $texto1); Imagepng($im); imagedestroy($im); ?>
Ver ejemplo228.php Formato PNG Ver ejemplo229.php Formato JPG

Un ejemplo resumen

Aqu tienes un ejemplo bastante completo de generacin de imgenes dinmicas.


Ver ejemplo230.php Ver cdigo fuente

Diagramas de sectores Diagramas de sectores


Esta posibilidad grfica de tratamiento de informacin estadstica la proporciona la funcin

imagefilledarc( Xc, Yc, a, b,anguloi, angulof , $color, tipo )

dnde los parmetros son: Xc y Yc que son las coordenadas del centro de la elipse cuyo arco (o porcin) tratamos de representar. Los nmeros a y b son las longitudes (expresadas en pixels) de los semiejes horizontal y vertical de la elipse. Si ambos fueran iguales el resultado sera circular. Los parmetros anguloi y angulof son las posiciones (en grados sexagesimales) de los radios (inicial y final) que delimitan el sector que se trata de representar. Los cero grados coinciden con el semieje horizontal positivo y el sentido del recorrido angular es el de las agujas del reloj. El parmetro $color es la variable ha de ser definida previamente mediante imagecolorallocate que indica el color que ha de utilizarse en el grfico. Por ltimo el parmetro tipo un constante PHP que puede tomar uno de los siguientes valores: IMG_ARC_PIE,IMG_ARC_NOFILL, IMG_ARC_EDGED o IMG_ARC_CHORD Con la primera de las constantes dibuja el sector de elipse delimitado por los radios indicados relleno con el color especificado. Mediante IMG_ARC_NOFILL nicamente dibuja la porcin de arco, pero no incluye la representacin de los radios en el dibujo. La opcionIMG_ARC_EDGED se comporta de forma idntica a IMG_ARC_PIE cuando se utiliza de forma aislada aunque tiene una opcin muy interesante que veremos un poco ms abajo. Con IMG_ARC_CHORD el resultado es un tringulo relleno con el color indicado formado por los dos radios y la cuerda correspondiente al arco que delimitan.

Combinar dos constantes de tipo


Cuando en la funcin imagefilledarc() utilizamos como tipo una expresin tal como: IMG_ARC_NOFILL|IMG_ARC_EDGED (fjate en el signo | que separa ambas constantes) lo que obtenemos es la representacin grfica del contorno del sector (incluye los radios que lo delimitan). Mediante esta opcin -con dos llamadas a la funcin- tenemos la posibilidad de representar el sector con un color de relleno (usando IMG_ARC_PIE) y, luego, superponerle un contorno de distinto color. Puedes verlo en los ejemplos.

Efecto tridimensional
Tal como puedes ver en los ejemplos, resulta fcil lograr un efecto tridimensional en el dibujo de los sectores. Basta con crear un bucle que dibuje arcos sucesivos (separados verticalmente por un pixel) y posteriormente superponer un sector relleno con un color distinto.

Ejemplos de sectores
<?php $im = imagecreate (400, 400); $fondo = imagecolorallocate($im, 226, 226, 226); $col1=imagecolorallocate($im,255,255,0); $col2=imagecolorallocate($im,255,0,0); imagefilledarc($im, 200, 200, 350, 300, 20, 240, $col1, IMG_ARC_PIE); imagefilledarc($im, 200, 200, 350, 300, 10, 150, $col2, IMG_ARC_NOFILL); header('Content-type: image/png'); imagepng($im); imagedestroy($im); ?>
Ver ejemplo .jpg Ver ejemplo .png Ver ejemplo .gif

<?php $im = imagecreate (400, 400); $fondo = imagecolorallocate($im, 226, 226, 226); $col1=imagecolorallocate($im,255,255,0); $col2=imagecolorallocate($im,255,0,0); imagefilledarc($im, 200, 200, 350, 300, 20, 240, $col1, IMG_ARC_EDGED); imagefilledarc($im, 200, 200, 350, 300, 10, 150, $col2, IMG_ARC_NOFILL); header('Content-type: image/png'); imagepng($im); imagedestroy($im); ?>

Ver ejemplo .jpg

Ver ejemplo .png

Ver ejemplo .gif

<?php $im = imagecreate (400, 400); $fondo = imagecolorallocate($im, 226, 226, 226); $color1=imagecolorallocate($im,255,0,0); imagefilledarc ($im, 200, 200, 350, 300, 20, 240, $color1, IMG_ARC_NOFILL|IMG_ARC_EDGED); header('Content-type: image/gif'); imagegif($im); imagedestroy($im); ?>
Ver ejemplo .jpg Ver ejemplo .png Ver ejemplo .gif

<?php $im = imagecreate (400, 400); $fondo = imagecolorallocate($im, 226, 226, 226); $color1=imagecolorallocate($im,255,0,0); imagefilledarc ($im, 200, 200, 350, 300, 50, 200, $color1, IMG_ARC_CHORD); header('Content-type: image/gif'); imagegif($im); imagedestroy($im); ?>
Ver ejemplo .jpg Ver ejemplo .png Ver ejemplo .gif

<? $im = imagecreate (400, 400); $fondo = imagecolorallocate($im, 226, 226, 226); $color1=imagecolorallocate($im,200,0,0); $color2=imagecolorallocate($im,255,0,0); $color3=imagecolorallocate($im,255,255,255); for($i=200;$i<225;$i++){ imagefilledarc($im, 200, $i, 370, 270, 50, 330, $color1, IMG_ARC_NOFILL|IMG_ARC_EDGED); } imagefilledarc($im, 200, 200, 370, 270, 50, 330, $color2, IMG_ARC_EDGED); imagefilledarc($im, 200,200, 370, 270, 50, 330, $color3, IMG_ARC_NOFILL|IMG_ARC_EDGED); header('Content-type: image/gif'); imagegif($im); imagedestroy($im); ?>
Ver ejemplo .jpg Ver ejemplo .png Ver ejemplo .gif

Encuadre y redimensionado de imgenes Lectura de imgenes externas


La visualizacin de imgenes no presenta ningn problema lo hacemos habitualmente mediante etiquetas HTML cuando se encuentran en el espacio del servidor, bien sea propio o ajeno. El problema puede surgir cuando tratemos de almacenar esas imgenes fuera del root del servidor (una forma de impedir la accesibilidad desde otras webs) y eso puede conseguirse mediante las funciones que veremos en este captulo.

Se trata de utilizar PHP para hacer una copia de la imagen original. Para ello debemos conocer la ubicacin de aquella y tambin sufomato. A partir de esos datos ya solo nos quedara utilizar una de las funciones: $copia=imagecreatefromjpeg($original) o $copia=imagecreatefrompng($original) o $copia=imagecreatefromgif($original)

que nos permitira crear una copia de la imagen original utilizando la funcin adecuada al formato de aquella (jpg, png o gif). La visualizacin de la imagen requiere los mismos elementos de ejemplos anteriores: Header puede incluir como Content-type cualquiera de los valores: image/jpeg, image/png o image/gif imagecreate que ahora requerira una de las opciones imagecreatefromjpeg, imagecreatefrompng imagecreatefromgif segn sea el formato de la imagen original. image..($copia) que ahora requerira una de las opciones imagejpeg($copia), imagepng($copia) imagegif($copia) segn sea el formato establecido en Header. En estos ejemplos puedes ver los resultados de la copia de los tres tipos de imagen.

<?php /* ruta completa hasta la imagen original. Aunque aqui usamos DOCUMENT_ROOT para establecer la ruta hasta la imagen ejemplo no sera preciso que estuviera en el root del servidor. Podra estar en cualquier directorio fuera de ese mbito */ $original=$_SERVER['DOCUMENT_ROOT']."/php/images/caballos.jpg"; /* para conocer el formato de la imagen podemos extraer el nombre de la extensin de la imagen original que ser lo que hay a partir del ltimo "punto" de la cadena que contiene la ruta completa */ for($i=strlen($original)-1;$i>0;$i--){ if (substr($original,$i,1)=="."){ $tipo=substr($original,$i+1); break; } } /* insertamos el Header correspondiente al cualquiera de los tipos de imagen utilizables por PHP. Por ejemplo: jpeg */ Header("Content-type:image/jpeg"); /* el uso de switch puede sernos til para elegir la funcin adecuada */ switch($tipo){ case "jpg": $copia=imagecreatefromjpeg($original); break; case "png": $copia=imagecreatefrompng($original); break; case "gif": $copia=imagecreatefromgif($original); break; } /* visualizamos la imagen ateniendonos al formato establecido en Header */ imagejpeg($copia); /* eliminamos la imagen de memoria */ ImageDestroy($copia); ?>

Ver ejemplo .jpg

Ver ejemplo .png

Ver ejemplo .gif

Redimensionar y recortar de imgenes externas


Puede parecer que esta posibilidad carece de utilidad. A fin de cuentas, con etiquetas HTML podemos asignar el ancho y el alto de una imagen. Pero enseguida veremos que esta opcin no es tan trivial como parece. El objetivo es obtener una imagen con unas dimensiones determinadas y unos mrgenes tambin establecidos a partir de una parte (o el todo) de un original.

Copia de la imagen original. Pretendemos recortar la parte marcada

La imagen resultante tiene bordes en blanco y adems contiene el recorte de la anterior ampliado y deformado

Lo que necesitamos es crear una imagen en blanco con las dimensiones elegidas y posteriormente incrustar en ella la copia de una imagen externa despus de haberla deformado para adaptarla a unas nuevas dimensiones. Para lograr este propsito va a ser necesario que utilicemos estas funciones: $dimensiones=getimagesize($original)

dnde $original es la variable que contiene el path y nombre del fichero externo que contiene la imagen y $dimensiones es un array escalar que contiene las dimensiones de la imagen analizada. El elemento del array $dimensiones[0] contiene el ancho y $dimensiones[1] el alto, ambos expresados en pixels. $ampliacion=imagecreatetruecolor(x, y)

dnde $ampliacion es el identificador de una nueva imagen en blanco creada en color verdadero con dimensiones x e y imagecopyresampled($ampliacion, $copia, Xampliacion, Yampliacion, Xcopia, Ycopia, Ax , Ay, Ox , Oy)

$ampliacion que es el identificador de la imagen destino, es decir la imagen en blanco sobre la que pretendemos insertar todo o parte de la original, $copia es el identificador de una copia de la imagen original previamente guardada en memoria, Xampliacion e Yampliacion son las coordenadas de un punto situado en la esquina superior izquierda del papel a partir del que queremos que se impresione la fotografa. Si queremos una foto a sangre pondremos 0,0 y, si quieres dejar mrgenes en blanco, habr que poner los anchos de esos mrgenes (izquierdo y superior) respectivamente. Xcopia e Ycopia nos servirn para reencuadrar la foto original recortando por la izquierda y por arriba, respectivamente, los anchos que se indiquen aqu en pixels. Si no queremos recortar la imagen original ni por la izquierda ni por la derecha pondremos 0,0.

Ax y Ay indican el ancho y el alto (por este orden) que va a tener la mancha de imagen en la imagen resultante. Ten en cuenta que no podemos salirnos del papel as que esos valores sumados con los mrgenes (izquierdo y superior) no podrn ser mayores que las dimensiones de la imagen ampliada. Ox y Oy indican el ancho y el alto de la porcin del original que tratamos de reproducir. Sumados con Xcopia e Ycopia no pueden exceder el tamao de la imagen original. Con estos parmetros la funcin ya se encarga de redimensionar la imagen (incluso distorsionarla, si no hay proporcionalidad entre los anchos y altos del original y del soporte. El proceso es el siguiente: Hacemos un copia en memoria de la imagen original Creamos una nueva imagen en blanco que ser la imagen resultante Insertamos en la nueva imagen el resultado de la transformacin de la copia de la original

Cuidado! Observa que las imgenes en formato png se visualizan con deficiencias en los bordes de las reas transparentes. Con el mtodo que vemos a continuacin ese problema se reduce considerablemente.

Lectura y redimensionado de imgenes externas


<?php /* indicamos la ruta de la imagen original */ $original=$_SERVER['DOCUMENT_ROOT']."/php/images/caballos.jpg"; /* determinamos el formato de esa imagen */ for($i=strlen($original)-1;$i>0;$i--){ if (substr($original,$i,1)=="."){ $tipo=substr($original,$i+1); break; } } /* determinamos las dimesiones de la imagen original */ $tamano=getimagesize($original); $orig_Ancho = $tamano[0]; $orig_Alto =$tamano[1]; /* vamos a tratar de obtener una imagen deformada para ello usaremos factores de ampliacin distintos para para cada uno de los lados. Multiplicaremos por 2 el ancho y por 1.5 el alto */ $ampliacion_X=2; $ampliacion_Y=1.5; /* Pretendemos que la imagen resultante no tenga mrgenes en blanco por tanto sus dimensiones van a ser las del original multiplicado por los factores de ampliacion */ $resultado_Ancho=$orig_Ancho*$ampliacion_X; $resultado_Alto= $orig_Alto*$ampliacion_Y; /* creamos una copia de la imagen original. Debemos elegir la funcion adecuada al tipo de aquella*/ switch($tipo){ case "jpg": $copia=imagecreatefromjpeg($original); break; case "png": $copia=imagecreatefrompng($original); break; case "gif": $copia=imagecreatefromgif($original);

break; } /* insertamos la cabecera de nuestra imagen final ampliada */ Header("Content-type:image/jpeg"); /* creamos una imagen nueva en color verdadero*/ $ampliada=imagecreatetruecolor($resultado_Ancho,$resultado_Alto); /* aplicamos un color de fondo a la nueva imagen para poder visualizar que incluye la transparencia del png y/o del gif */ if($tipo=="png" OR $tipo=="gif"){ $fondo=imagecolorAllocate($ampliada,255,255,200); imagefill($ampliada,0,0,$fondo); } /* incrustamos la imagen importada sobre la que acabamos de crear teniendo en cuenta los parmetros de la funcin. Los cuatro ceros se deben a que vamos a colocar toda la imagen original (sin recortes) sin dejar ningun margen en blanco) y los anchos y altos se mantienen dado que ni recortamos nada la imagen original ni vamos a dejar margen alguno en la resultante */ imagecopyresampled($ampliada,$copia,0,0,0,0, $resultado_Ancho, $resultado_Alto, $orig_Ancho,$orig_Alto); /* visualizamos la imagen resultante */ imagejpeg($ampliada); ImageDestroy(); ?>
Ver ejemplo .jpg Ver ejemplo .png Ver ejemplo .gif

Observa que tanto en el ejemplo anterior como en el siguiente solo hemos utilizado la extensin de la imagen original para elegir la funcin imagecreatefrom.... En el Header hemos puesto image/jpeg y, como es obvio, hemos utilizado la funcin asociada a este formato (imagejpeg). Si sustituimos ambos valores por los correspondientes a otro formato (gif, png) obtendramos resultados similares.

Recortar y encuadrar imgenes externas


<?php /* indicamos la ruta de la imagen original */ $original=$_SERVER['DOCUMENT_ROOT']."/php/images/aviones4.jpg"; /* determinamos el formato de esa imagen */ for($i=strlen($original)-1;$i>0;$i--){ if (substr($original,$i,1)=="."){ $tipo=substr($original,$i+1); break; } } /* determinamos el tamao de la imagen original */ $tamano=getimagesize($original); $orig_Ancho = $tamano[0]; $orig_Alto =$tamano[1]; /* asignamos a una variable el margen en blanco de la imagen igual por los cuatro lados */ $margen=15; /* establecemos los recortes para reencuadrar la imagen original */ $recorte_izq=50; $recorte_sup=80; $recorte_der=40; $recorte_inf=60; /* calculamos las dimensiones para utilizar como parmetros en la funcion imagecopyresampled ancho y alto de la imagen original despus del recorte de encuadre */ $Ancho_recortado=$orig_Ancho-$recorte_izq-$recorte_der; $Alto_recortado=$orig_Alto-$recorte_sup-$recorte_inf; /* establecemos factores de ampliacin iguales para evitar distorsiones */ $ampliacion_X=1.3; $ampliacion_Y=1.3;

/* determinamos las dimensiones de la imagen final teniendo en cuenta los margenes y los factores de ampliacin */ $papel_Ancho=$Ancho_recortado*$ampliacion_X+ 2*$margen; $papel_Alto=$Alto_recortado*$ampliacion_Y+2*$margen; /* dimensiones del area impresa de la imagen resultante Hay que descontar los mrgenes al tamao de la imagen */ $resultado_Ancho=$papel_Ancho -2*$margen; $resultado_Alto=$papel_Alto -2*$margen; switch($tipo){ case "jpg": $copia=imagecreatefromjpeg($original); break; case "png": $copia=imagecreatefrompng($original); break; case "gif": $copia=imagecreatefromgif($original); break; } /* creamos la cabecera de la nueva imagen */ Header("Content-type:image/jpeg"); /* creamos la imagen final asignandole sus dimensiones */ $ampliada=imagecreatetruecolor($papel_Ancho,$papel_Alto); /*ponemos un color de fondo (rojo) que ser con el que se visualizarn los mrgenes*/ $fondo=imagecolorAllocate($ampliada,255,0,0); /* aplicamos el color de fondo */ imagefill($ampliada,0,0,$fondo); /* incrustamos la imagen */ imagecopyresampled($ampliada,$copia,$margen,$margen, $recorte_izq,$recorte_sup, $resultado_Ancho,$resultado_Alto, $Ancho_recortado,$Alto_recortado); /* visualizamos el resultado */ imagejpeg($ampliada); ImageDestroy(); ?>
Ver imgenes original y resultante

Superponer, rotar y dar transparencia a imgenes Colores con transparencia


PHP permite crear colores con transparencia. Para ello se utiliza la funcin: ImageColorAllocateAlpha($imagen, rojo, verde, azul, transparencia)

donde $imagen es el identificador de la imagen que ha sido creada previamente, rojo, verde, azul que son valores numricos (o variables) que contienen en una escala de 0 a 255 la intensidad luminosa de cada uno de los tres colores primarios y transparencia es un valor numrico comprendido entre 0 y 127 que indica el grado de transparencia de la tinta. El valor 0 indica opacidad total, mientras que 127 establece la transparencia total de ese color. En el ejemplhemos incluido dos escalas de transparencias superpuestas a intervalos del 10% (desde 0 hasta 100%) transformados a la escala 0-127.

El orden de superposicin similar a las capas de otros programas grficos se corresponde con el orden de las instrucciones de creacin. Los resultados de las ltimas funciones se superponen siempre a los obtenidos como consecuencia de la ejecucin de las anteriores.

<?php /* Creamos una imagen en color verdadero, le aplicamos un color de fondo (para evitar el negro por defecto) y creamos un nuevo color que utilizaremos para los bordes de rectangulos posteriores*/ Header("Content-type:image/jpeg"); $im_base=imagecreatetruecolor(610,140); $fondo=imagecolorAllocate($im_base,255,255,200); $negro=imagecolorAllocate($im_base,0,0,0); imagefill($im_base,0,0,$fondo); # definimos las componentes de un nuevo color $R=255; $G=00; $B=00; /* vamos a construir una escala de transparencias de 0 a 10 que correspondera con valores de transparencia de 0% al 100%. Crearemos un bucle que dibuje rectangulos rellenos con el color definido en la variable trans que ir aplicando al color bsico los diferentes grados de transparencia y le pondremos un contorno negro para encuadrarlos*/ for($i=0;$i<=10;$i++){ $trans=ImageColorAllocateAlpha($im_base,$R,$G,$B,(int)($i*127/10)); imagefilledrectangle($im_base, 10+55*$i, 20, 50+55*$i, 80, $trans); imagerectangle($im_base, 10+55*$i, 20, 50+55*$i, 80, $negro); } #creamos un nuevo color y repetimos el proceso con nuevos rectangulos #superpuestos a los anteriores y con las transparencias en sentido opuesto # es decir, de 100 a 0% $R=0; $G=0; $B=255; for($i=0;$i<=10;$i++){ $trans=ImageColorAllocateAlpha($im_base,$R,$G,$B,127-(int)($i*127/10)); imagefilledrectangle($im_base, 10+55*$i, 60, 50+55*$i, 120, $trans); imagerectangle($im_base, 10+55*$i, 60, 50+55*$i, 120, $negro); } # visualizamos el resultado imagejpeg($im_base); ImageDestroy(); ?>
Ver ejemplo .jpg Ver ejemplo .png Ver ejemplo .gif

Transparencia en imgenes externas


Tambin resulta posible ajustar el grado de transparencia de una imagen externa. Mediante la funcin imagecopymerge($destino, $origen,Xd, Yd, Xf, Yf, Dx, Dy, opacidad)

dnde $destino es el identificador de la imagen sobre la que se va a colocar la transparencia. Como es lgico, deber haber sido creada antes de incluir la funcin. $origen es el identificador de la imagen que pretendemos incluir con un determinado grado de transparencia, Xd e Yd son las coordenadas de un punto situado en la esquina superior izquierda de la imagen destino a partir del que queremos que se impresione la nueva imagen. Si queremos una imagen a sangre pondremos 0,0 y, si quieres dejar mrgenes, habr que poner los anchos de esos mrgenes (izquierdo y superior) respectivamente. Xf e Yf nos servirn para reencuadrar la foto original recortandopor la izquiera y por arriba, respectivamente, los anchos en pixels que aqu se indiquen. Dx y Dy indican el ancho y el alto (por este orden) que va a tener la mancha de imagen. Ten en cuenta que no puedes salirte del papel as que los valores anteriores sumados con los mrgenes que hayas establecido no podrn ser mayores que las dimensiones que has elegido para la imagen destino. Por ltimo, opacidad es un parmetro al que puede asignarse un valor comprendido entre 0 y 100 y representa el porcentaje de opacidad de la imagen superpuesta. Con un valor cien sera totalmente opaca y si fuera cero la transparencia sera total.

<?php # obtener la imagen $original=$_SERVER['DOCUMENT_ROOT']."/php/images/aviones4.jpg"; # buscar el formato de la imagen mediante su extensin for($i=strlen($original)-1;$i>0;$i--){ if (substr($original,$i,1)=="."){ $tipo=substr($original,$i+1); break; } } # tamao del original extraido del array devuelto por getimagesize $tamano=getimagesize($original); $orig_Ancho = $tamano[0]; $orig_Alto =$tamano[1]; # estableceremos un margen en blanco alrededor de la imagen de 10 pixels # igual por los cuatro lados $borde=10; $Ancho=$orig_Ancho+2*$borde; $Alto=$orig_Alto+2*$borde; # creamos la imagen segun el formato original switch($tipo){ case "jpg": $importada=imagecreatefromjpeg($original); break; case "png": $importada=imagecreatefrompng($original); break; case "gif": $importada=imagecreatefromgif($original); break; } Header("Content-type:image/jpeg"); # creamos una imagen nueva, un color de fondo y la rellenamos con l $im_base=imagecreatetruecolor($Ancho,$Alto); $fondo=imagecolorAllocate($im_base,255,255,200); imagefill($im_base,0,0,$fondo); # superponemos la imagen importada posicionandola y aplicandole # una trasmparencia de 50 imagecopymerge( $im_base, $importada, $borde, $borde, 0, 0, $orig_Ancho, $orig_Alto ,50 ); imagejpeg($im_base); ImageDestroy(); ?>
Ver ejemplo .jpg Ver ejemplo .png Ver ejemplo .gif

Si observas los resultados obtenidos en el ejemplo en el que intentamos dar transparencia a una imagen en formato png podrs observar que deja bastante que desear y produce un efecto indeseado por el recorte de las zonas presuntamente transparentes. Esta situacin nos obliga a replantear la situacin para prever esta circunstancia y recurrir a un truco que parece solventar ese problema. La modificacin del cdigo fuente es la incluimos aqu debajo.

Header("Content-type:image/jpeg"); $im_base=imagecreatetruecolor($Ancho,$Alto); $fondo=imagecolorAllocate($im_base,255,255,200); imagefill($im_base,0,0,$fondo); /* el truco consiste en crear una segunda imagen (im_truco)cuyas dimensiones coincidan con las de la imagen transparente que pretendemos colocar. Le asignamos como color el fondo el mismo

de la imagen destino y hacemos transparente ese color en esa imagen. Despus hacemos una copia de la imagen original sobre la imagen im_truco y sustituimos en la funcin imagecopymerge la imagen original por la obtenida mediante esta chapucilla */ $im_truco=imagecreatetruecolor($orig_Ancho, $orig_Alto); $fondo1=imagecolorAllocate($im_truco,255,0,200); imagefill($im_truco,0,0,$fondo1); imagecolortransparent ($im_truco,$fondo1); imagecopy($im_truco, $importada, 0, 0, 0, 0, $orig_Ancho, $orig_Alto); imagecopymerge( $im_base , $im_truco, $borde , $borde , 0 , 0 ,$orig_Ancho, $orig_Alto ,60 ); imagejpeg($im_base); ImageDestroy();
Ver el nuevo resultado

Montaje de imgenes
Superponer una parte de una imagen
Mediante esta funcin se puede copiar sobre una imagen una parte de otra. Permite extraer porciones de imgenes con su tamao original sin que permita ampliarlas ni reducirlas. Su sintaxis es la siguiente: imagecopy($destino, $original, $x, $y, $X, $Y, $A, $H)

donde: $destino el identificador de la imagen destino, $original el identificador de la imagen original, $x y $y las coordenadas donde se posicionar en la imagen destino la esquina superior izquierda de la porcin copiada, $X y $Y son los anchos de los recortes izquierdo y superior de la imagen a copiar y $A y $H el ancho y el alto del rea de imagen que pretendemos copiar.

<?php /* definimos las imagenes */ $imagen_base=$_SERVER['DOCUMENT_ROOT']."/php/images/aviones1.jpg"; $imagen_superpuesta=$_SERVER['DOCUMENT_ROOT']."/php/images/aviones2.jpg"; Header("Content-type: image/jpeg"); /* creamos en memoria dos imagenes copia de las originales */ $capa_base =imagecreatefromjpeg($imagen_base); $capa_superpuesta =imagecreatefromjpeg($imagen_superpuesta); /* realizamos el montaje de la nueva imagen sobre la base */ imagecopy($capa_base,$capa_superpuesta, 30, 40, 70, 80, 195, 225); /* visualizamos la imagen */ imagejpeg($capa_base); imagedestroy(); ?>
Ver ejemplo

Rotacin de imgenes
Es posible presentar imgenes rotadas por medio de la funcion: imagerotate($imagen,angulo,$fondo)

dnde el parmetro $imagen es el identificador de la imagen a rotar, angulo es el ngulo de rotacin (expresado en grados y tomado en sentido trigonomtrico) y $fondo es un color de fondo asociado a la imagen a rotar que puede ser definido mediante la funcinimagecolorallocate u otra funcin que permita asociar colores a imgenes.

<?php # obtener la imagen $original=$_SERVER['DOCUMENT_ROOT']."/php/images/aviones3.jpg"; for($i=strlen($original)-1;$i>0;$i--){ if (substr($original,$i,1)=="."){ $tipo=substr($original,$i+1); break; } } switch($tipo){ case "jpg": $importada=imagecreatefromjpeg($original); break; case "png": $importada=imagecreatefrompng($original); break; case "gif": $importada=imagecreatefromgif($original); break; } Header("Content-type:image/jpeg"); $fondo=imagecolorallocatealpha($importada,255,255,0,40); $im_base=imagerotate($importada,30,$fondo); imagejpeg($im_base); ImageDestroy(); ?>
Ver ejemplo

Transparencia en capas rotadas


Cuando trabajamos con una imagen truecolor en la que vamos incluyendo en diferentes capas (mediante copy copymerge) otras imgenes recortadas, rotadas, creadas a partir de otra imagen, etc. la transparencia de los colores de los fondos de rotacin no plantea ningn problema. Es suficiente usar la funcin imagecolortransparent, eso s, aplicndola a la imagen correspondiente antes de insertarla mediante la opcin copy en la imagen final.

Cuidado! La funcin imagerotate() no funciona con la versin de la librera GD que se instala con Ubuntu o Debian que es diferente de la que utilizan otras distribuciones de PHP (la de Windows por ejemplo). La forma de resolverlo puedes encontrarla aqu

Ejemplo resumen
Aqu tienes un ejemplo en el que hemos utilizado superposiciones de imgenes, con giros, recortes y diferentes grados de transparencia.
Ver ejemplo resumen Ver codigo fuente

Efectos en imgenes y CAPTCHA Aplicando filtros a imgenes


A partir de PHP 5 se han incluido funciones que permiten aplicar a las imgenes filtros modificadores que producen muchos de los efectos que hasta ahora estaban reservados al software grfico del tipo Gimp o PhotoShop por poner dos ejemplos. Al incluir la funcin: imagefilter ( $imagen , tipo_filtro, param1, param2, ... )

Dnde $imagen es el identificador de imagen, tipo_filtro es un valor numrico entero (o una constante, en cuyo caso no deber su nombre entre comillas) y los parmetros cuyo nmero y valores dependen del tipo de filtro utilizado. Aqu debajo tienes una tabla que contiene los diferentes tipos de filtros disponibles as como los parmetros utilizados por cada uno de ellos.

Imagen original

Imagen transformada

Cdigo fuente

Pulsando en las opciones de la parte inferior podrs visualizar aqu el cdigo fuente de los scripts que transforman la imagen original de acuerdo con los parmetros elegidos para cada opcin

Nombre de la constante

Valor equivalente

Parmetros

Funcin Invierte los colores de la imagen Convertir a escala de grises

Aplicar

IMG_FILTER_NEGATE IMG_FILTER_GRAYSCALE IMG_FILTER_BRIGHTNESS IMG_FILTER_CONTRAST

0 1 2 3
Brillo=60 Contraste=10 Rojo=10 Verde=10

Aplicar Aplicar Aplicar Aplicar

Aumenta o disminuye el brillo en el intervalo 255 a -255 Aumenta o disminuye el contraste en el intervalo 255 a -255

IMG_FILTER_COLORIZE

Azul=10 Alfa=10

Coloriza

Aplicar

IMG_FILTER_EDGEDETECT IMG_FILTER_EMBOSS IMG_FILTER_GAUSSIAN_BLUR IMG_FILTER_SELECTIVE_BLUR IMG_FILTER_MEAN_REMOVAL IMG_FILTER_SMOOTH IMG_FILTER_PIXELATE

5 6 7 8 9 10 11
Suavizado=60 Tamao=5

Detectar y resalta bordes Efecto relieve Desenfoque gaussiano Desenfoque selectivo Aplica efecto boceto a la imagen Aplica suavizado la imagen

Aplicar Aplicar Aplicar Aplicar Aplicar Aplicar Aplicar

Pixelacin avanzada Si

Pixela la imagen (Solo funciona en versiones PHP 5.3 y superiores)

Los filtros requieren incluir los parmetros que aparecen en las respectivas cuadrculas. Su inclusin se realiza agregndolos (nicamente sus valores numricos) a continuacin del nombre o identificador del filtro y separados de este y entre ellos por una coma.

Aplicaciones sucesivas de efectos


Las diferentes opciones de filtrado pueden irse aplicando de forma sucesiva sobre una misma imagen. Un caso tpico puede ser el que puedes verlo en la imagen de la parte superior si pulsas en este enlace. El efecto sepia se logra aplicando primero IMG_FILTER_GRAYSCALE para convertir a escala de grises y colorizando por medio de IMG_FILTER_COLORIZE. En este caso los valora aplicados a las componentes R,G,B han sido 210, 90, 30 respectivamente y el valor del cuarto parmetro (canal alfa) ha sido de 64

Obtencin de valores de las componentes de color


PHP dispone de funcin: $codigo_de_color=imagecolorat($imagen, x, y) por medio de la cual la variable $codigo_de_color recogera un valor decimal resultante de convertir en decimal el color correspondiente (la cadena hexadecimal con el formato clsico RRGGBB) al pixel cuyas coordenadas horizontal y vertical, respecto a la esquina superior izquierda de la imagen son x e y de la imagen cuyo identificador es $imagen Para la manipulacin de imgenes puede resultar muy interesante conocer las componentes R,G y B de esos colores. En caso de la libreria GD cuando se trata de conocer el color de uno de los pixel de una imagen los valores R,G, B de sus componentes puede obtenerse por medio de la funcin: $codigo_de_color=imagecolorat($imagen ,x,y) $array_de_colores=imagecolorsforindex($imagen ,$codigo_de_color)
Ver ejemplo Ver cdigo fuente

Si ejecutas el ejemplo anterior podrs ver que imagecolorsforindex es un array asociativo cuyos indices son: red, green,blue y alfaque corresponden los tres primeros a las componentes de los colores primarios y el cuarto alfa que indicara el grado de transparencia de ese color (en caso de que la imagen la tuviera asignada). Por lo general la informacin de color de un pixel de una imagen estara conformado por 24 bits de los cuales corresponden 8 a cada uno de ellos. Cuando se agrega un canal alfa para incluir una determinada transparencia se agregan otros 8 bits para recoger este valor. En ese caso, como resulta obvio, se requieren 32 bits por cada pixel. El valor cero asignado en el ejemplo anterior al ndice alfa significa que no est asignada ninguna transparencia al pixel estudiado. Cuando se trata de extraer, sin disponer de una imagen de referencia, las componentes de color de un cdigo de color uno los procedimientos para hacerlo requiere el uso de los operadores bit a bit de la forma que hemos tratado de desglosar paso a paso en la tabla que tienes aqu debajo.
Valor hexadecima Valor binario l

Valor inicial

Funcin

Valor decimal

Resultado

$a="#ABCDE $b=str_replace('#','',$a)); F" $b=ABCDEF $c=hexdec($b); 1125937 5

ABCDE F

$c=11259375 decbin($c); $c=11259375 ($c >> 16); $c=11259375 $c=11259375 base_convert(($c>>16),10, 16); base_convert(($c >>16),10,2); 43981 abcd 171 AB

101010111100110111101 111 101010111100110111101 111

Elimina el carcter # de la cadena que contiene el color y determina sus valores hexadecimal, decimal y binario. Observa que el valor binario tiene 24 caracteres. Los 8 primeros son los dos dgitos hexadecimales del color rojo, los siguientes los del verde y los ltimos los del azul. Elimina 16 caracteres por la derecha en la cadena que contiene el valor binario. Transformamos el resultado a las distintas bases. Es la componente rojo del color Elimina 8 caracteres por la derecha en la cadena que contiene el valor binario. Transformamos el resultado a las distintas bases. Son las componente rojo yverde del color

10101011

$c=11259375 $h=($c >> 8); $c=11259375 $c=11259375 base_convert(($c >> 8),10,16); base_convert(($c >> 8),10,2);

1010101111001101 1010101111001101

$c=11259375 ($c >> 8 & 0xFF); $c=11259375 0xFF base_convert(($c>>8 & 0xFF),10,16); base_convert((0xFF),10,2);

205 CD 1111111111111111

$c=11259375

base_convert(($c>>8 & 0xFF),10,2);

1111111111001101

Por medio del operador &extraemos 8 caracteres por la derecha. La razn es que el valor binario de 0xFF (sera lo mismo poner el decimal 255) es 11111111 y operar & con esta cadena dara los 8 carcteres (observa que estos son 8 unos) de la derecha de la otra cadena operada. El resultado ser la componente verde del color. Estos son los valores iniciales. Los repetimos nicamente con el fin de facilitar la visualizacin de las cadenas binarias e ilustrar los procesos bit a bit El operador & compara cadenas de bits (por la derecha). Si ambos bits tienen valor 1 devuelve 1 en caso contrario devuelve cero. Por esa razn al comparar con 0xFF estamos comparando con unos y en consecuencia el resultado coincide con el valor de bit comparado. El resultado de esta comparacin es la componente azul del color.

$c=11259375 $c; $c=11259375 base_convert($c,10,16); $c=11259375 base_convert($c,10,2); $c=11259375 ($c & 0xFF); $c=11259375 0xFF base_convert(($c & 0xFF),10,16); base_convert((0xFF),10,2); base_convert(($c & 0xFF),10,2);

1125937 5 abcdef 101010111100110111101 111 239 EF 11111111

$c=11259375

11101111

El clculo utilizando los operadores bit a bit de la tabla anterior no es el nico posible. Es el ms rpido pero es equivalente a este otro realizado por medio de la aritmtica clsica. En un sistema de numeracin hexadecimal (por su condicin de ordenado y por ser su base igual a 16) siempre puede 5 4 3 2 1 0 convertirse el nmero en una forma polinmica del tipo: A*16 +B*16 +C*16 +D*16 +E*16 +F*16 , o tambin (utilizando nmeros de 4 2 0 4 dos cifras)AB*16 +CD*16 +EF*16 . Si dividimos el polinomio anterior entre 16 obtendremos AB como cociente entero 2 0 y CD*16 +EF*16 como resto. Si el resto anterior, CD*16 +EF*16 lo dividimos entre 16 obtendremos como cociente entero CD y como resto EF (16 =1). Los resultados de estas operaciones resultan ser las componentes de los tres colores. Por tanto, si partimos del valor $c=11259375 del ejemplo de la tabla anterior, tendramos que la componente roja (expresada en valor decimal) del color se obtendra mediante: (int)($c/pow(16,4))=171 sera el valor de la componente roja del color. El valor de (int)($c%pow(16,4)/pow(16,2))=205 nos dara la componente verde y, por ltimo, por medio de (($c%pow(16,4)) % pow(16,2))=239 sera el valor de la componente azul.
2 0 2 0

Filtros personalizados
Cualquiera de los efectos que puedan provocarse en una imagen es el fruto de modificar los valores de color de sus pixels. Este tipo de modificaciones individuales para un solo pixel pueden realizarse por medio de las funciones: $color=imagecolorAllocate($imagen,R,G,B) o $color=imagecolorallocatealpha($imagen,R,G,B,alfa) y imagesetpixel($imagen, $x, $y, $color)

Por medio de la primera de las funciones, ya comentada en pginas anteriores, se crea un ndice de color($color) para la imagen identificada por $imagen al que se asignan como valores de R, G y B valores enteros comprendidos entre 0 y 255. En el segundo de los supuestos, el parmetro alfa es un indicador de transparecia que puede tomar valores entre 0 (opaco) y 127 (transparente). El paso siguiente es aplicar la funcin imagesetpixel para asignar al pixel de la imagen$imagen cuyas coordenadas son x e y el color establecido en el ndice $color. Aqu tienes un ejemplo de como utilizar esas funciones para efectuar la transformacin Umbral que no es otra cosa que transformar a escala de grises y posteriormente modificar el color de los mismos asignando color rojo a aquellos cuyas componentes de color sean superiores a un valor umbral (por ejemplo 110) y color negro a aquellos que lo tengan inferior a ese valor.

<?php Header("Content-type: image/jpeg"); $im = imagecreatefromjpeg('./images/aviones4.jpg'); /* utilizamos imagesx e imagesy para calcular las dimensiones de la imagen actual. Tambin podramos haber utilizado los valores del array obtenido por medio de la funcion getimagesize que nos dara informacin de la imagen original. En este caso ambas son iguales */ $ancho=imagesx($im); $alto=imagesy($im); /* asignamos un valor entre 0 y 255 a la variable umbral dependiendo de este valor aumentarn o se reducirn las zonas blancas de la imagen */ $umbral=110; /* convierto a escala de grise grises */ imagefilter($im,IMG_FILTER_GRAYSCALE); /* creamos dos indices de color. Negro y rojo */ $color[0]=imagecolorAllocate($im,0,0,0); $color[1]=imagecolorAllocate($im,255,0,0); /* este doble bucle nos permite recorrer cada uno de los pixels de la imagen */ for ($i=0;$i<$ancho;$i++){ for ($j=0;$j<$alto;$j++){ /* leemos el color actual. Como se trata de grises las componentes R,G y B de cada uno de los pixels van a ser iguales, nos bastar por tanto conocer uno cualquiera. en este caso extraemos el valor correspondiente al azul */ $color_actual =imagecolorat($im,$i,$j) & 0xFF; /* si la componente gris es mayor que el umbral pinto en negro en caso contrario en blanco */ if($color_actual>$umbral){ imagesetPixel($im,$i,$j,$color[1]); }else{ imagesetPixel($im,$i,$j,$color[0]); } } } /* visualizamos la imagen */ imagejpeg($im); imagedestroy($im); ?>
Ver ejemplo Ver cdigo fuente

Creacin de una imagen CAPTCHA


CAPTCHA es el acrnimo de Completely Automated Public Turing test to tell Computers and Humans Apart que podra ser traducido como Prueba de Turing pblica y automtica para diferenciar a mquinas y humanos. Desde el punto de vista grfico

ha de ser una imagen el la que se visualizarn carcteres alfanumricos con elementos de distorsin y deformacin que impidan (o al menos dificulten) la lectura por dispositivos electrnicos OCR. Para dificultar ese proceso existen multitud de aplicaciones, clases PHP y recursos de toda ndoles. Nosotros vamos a intentar crear una imagen con poca nitidez, con caracteres aleatorios de diferentes tamaos, posiciones, tranparencias y ngulos de rotacin y posteriormente le aadiremos una deformacin vertical desplazando los pixeles en esta direccin por medio de funciones sinusoidales y, posteriormente haremos lo mismo en sentido horizontal. Veamos paso a paso el proceso.

Fondo con ruido aadido

Ver cdigo fuente

Insercin de caracteres aleatorios

Ver cdigo fuente

Deformacin vertical

Ver cdigo fuente

Deformacin horizontal

Ver cdigo fuente

Detectar bordes

Ver cdigo fuente

Filtros de convolucin Filtros de convolucin


Una imagen digital no es otra cosa que una especie de hoja de papel cuadriculado en el que cada una de las cuadrculas tiene asignado un color concreto especificado por medio de su cdigo de color tal como hemos visto en la pgina anterior. Cada uno de esos elementos que hemos llamado cuadrculas es un pixel. Una matriz de convolucin no es otra cosa que una matriz cuadrada formada por nueve cuadrculas (matriz de dimensin 3 x 3) que contiene valores numricos enteros. Aplicar un filtro de convolucin no es otra que superponer simblicamente la matriz de convolucin sobre la cuadrcula que conforma la imagen (El area sombreada de amarillo en la imagen sera delimitara sobre ella la zona de superposicin). El proceso aritmtico de aplicacin del filtro consistira en multiplicar el valor de cada cuadrcula de la matriz de convolucin por el situado debajo suyo en esa superposicin imaginaria. Los resultados de todos esos productos se sumaran obteniendo un valor que sustituira al valor del pixel centraldel area marcada (en rojo en la imagen). El valor anterior puede ser corregido por medio de un factor multiplicador del resultado y tambin por medio un parmetro de desplazamiento (offset) que permitira incrementar (o reducir, ya que admite valores negativos) en un valor entero el resultado anterior. En este esquema tienes el proceso de clculo del nuevo valor para el pixel central que es el marcado con fondo rojo.

La convolucin en PHP
Para aplicar este filtro en PHP es necesario empezar creando una matriz de convolucin. Dado que esa matriz ha de ser obligatoriamente de 3 x 3 la matriz de convolucin puede definirse de alguna de estas formas:

$matriz_de_convolucin = array(array(a11,a12,a13), array(a21,a22,a23), array(a31,a32,a33))

o tambin definiendo independientemente cada fila: $fila1 = array(a11,a12,a13) $fila2 = array(a21,a22,a23) $fila3 = array(a31,a32,a33)

y formando luego la matriz con las tres filas. Es decir: $matriz_de_convolucin = array($fila1, $fila2,$fila3)

Una vez disponemos de la matriz de convolucin podremos utilizar la funcin: imageconvolution ( $imagen , $matriz_de_convolucin, multiplicador, desplazamiento)

o, si preferimos definir la matriz de convolucin en la propia llamada a la funcin, escribiendo: imageconvolution ( $imagen , array(array(a11,a12,a13), array(a21,a22,a23), array(a31,a32,a33)), multiplicador, desplazamiento)

Dnde $imagen es el identificador de imagen, matriz_de_convolucion es el array ya comentado, multiplicador ser el factor multiplicador del resultado de la convolucin y desplazamiento un valor entero que se sumara a los resultados anteriores. El resultado sera la nueva imagen modificada despus de haber aplicado la matriz de convolucin a cada uno de los pixels que la conforman. Dado que los resultados no son facilmente predecibles hemos incluido simulador que te permitir ir modificando valores y observar los efectos producidos por esos cambios.

Imagen original

Imagen transformada

Cdigo fuente de la imagen

Si modificas las opciones de la parte inferior podrs visualizar aqu el cdigo fuente de los scripts que transforman la imagen original de acuerdo con los parmetros elegidos para cada opcin

Matriz de convolucin
0 0 0 0 1 0 0

Divisor:
0 0

1 0

Desplazamiento:

A modo de ejemplo, desde estos enlaces podrs visualizar los efectos indicados y a la vez las matrices de convolucin utilizadas. Sin convolucin Enfocar Desenfocar Repujado

Gestin de directorios Funciones con directorios


PHP dispone de funciones que permiten obtener informacin sobre los contenidos de los directorios del servidor. Algunas de estas funciones son las siguientes:

Pseudo-objeto dir
Mediante la expresin: $objeto = dir (path) dnde path es la ruta absoluta (../dir/subdir/subsubdir) o relativa (./subdir ) hasta el directorio del que vamos a obtener informacin, recogemos en el pseudo objeto $objeto la informacin sobre el directorio en cuestin de una forma un tanto peculiar ya que $objeto se comporta como objeto y, como tal objeto, posee las propiedades y mtodos que indicamos: $objeto->handle Devuelve una cadena con la descripcin del identificador del recurso. $objeto->path Devuelve la ruta del directorio especificado. $objeto->read() Realiza una lectura secuencial de los nombres y extensiones de los ficheros contenidos en el directorio especificado. $objeto->rewind() Posiciona el puntero en la posicin inicial. $objeto->close() Cierra el identificador de directorio. Este es un ejemplo de utilizacin de los mtodos de ste pseudo-objeto. Observa que las propiedades handle y path se invocan sin utilizar () mientras que tanto el mtodo read() como rewind() o close() s requieren esos parntesis.

<?php $directorio = dir("./images"); # en el caso de los objetos la manera de invocar # uno de sus mtodos y/o funciones requiere una sintaxis # especifica con la que vera a lo largo de este ejemplo: # es $objeto->metodo que equivale a la tradicional llamada # a una variable en la forma $variable. echo "Handle: ".$directorio->handle."<br>\n"; echo "Path: ".$directorio->path."<br>\n"; while($fichero=$directorio->read()) { echo $fichero."<br>\n"; } $directorio->rewind(); echo "nuevo listado del directorio despues de rebobinar<br>" ; while($fichero=$directorio->read()) { echo $fichero."<br>"; } $directorio->close(); ?>

ejemplo264.php

Otras funciones sobre directorios


Este nuevo grupo de funciones informativas requiere un sintaxis que recuerda la lectura de ficheros. Hay que comenzar abriendo el directorio y una vez se hayan realizado las consultas hay que cerrarlo segn se indica en las funciones siguientes. $directorio= opendir (path) Recoge en la variable $directorio un identificador que permitir utilizar las restantes funciones. $z= readdir ($directorio) Hace una lectura secuencial del directorio indicado por el identificador $directorio. A medida que efecta la lectura secuencial el puntero de lectura va desplazndose al fichero que sigue al ltimo ledo. rewinddir($directorio1) Rebobina haciendo que el puntero apunte al primer fichero del directorio. closedir($directorio1) Cierra el identificador del directorio.

<?php #abrimos el identificador de directorio $directorio = opendir("./images"); #leemos el primer fichero que ser "." (recuerda la estructura de los directorios de MSDOS) $fichero=readdir($directorio); echo $fichero,"<br>"; #leemos el fichero siguiente que ser ".." (recuerda la estructura de los directorios de MS-DOS) $fichero=readdir($directorio); echo $fichero,"<br>"; #leemos el fichero siguiente (el primer fichero "real") $fichero=readdir($directorio); echo $fichero,"<br>"; #rebobinamos, enviando el puntero al primer fichero rewinddir($directorio); echo "Lista de TODOS los ficheros usando un bucle while<br>"; #leemos todos los ficheros while($fichero=readdir($directorio)) { echo $fichero."<br>"; } closedir($directorio); ?>
ejemplo265.php

Proteccin de directorios Errores y redireccionamiento


Configuracin del servidor Apache
Para poder proteger de directorios mediante un fichero llamado .htaccess es necesario realizar algunas modificaciones en la configuracin de Apache. Abriremos nuestro fichero httpd.conf y buscaremos las lneas en las que aparece: AllowOverride None y reemplazaremos None por All. Guardaremos los cambios en httpd.conf y reiniciaremos el servidor. En caso de que estemos usando como sistema operativo Ubuntu haremos esa modificacin ejecutando desde consola: sudo gedit /etc/apache2/sites-enabled/000-default

El fichero .htaccess
Las misiones ms importantes que puede realizar este fichero son: redireccionar y restringir accesos. Veamos el primero de los casos. Los mensajes de error ms frecuentes al intentar acceder a pginas web y sus causas son los siguientes: Error 401 El subdirectorio est protegido por nmero IP o por password y el intento de acceder a l no ha tenido xito. Error 403 El acceso al documento solicitado est prohibido. Error 404 El documento solicitado no ha sido hallado. Error 500 Error del servidor. Usualmente este error se da cuando se ha intentado ejecutar de forma incorrecta un CGI, o bien debido a problemas en el servidor. Los errores de los tipos 403 y 404 suelen producirse en la mayora de las ocasiones por direcciones incorrectas y aparte de causar un psimo efecto suelen provocar el abandono de la visita. Un fichero .htaccess con este contenido: ErrorDocument 401 pagX ErrorDocument 403 pagY ErrorDocument 404 pagZ donde pagX, pagY y pagZ sean direcciones (completas) de las pginas a las que deseamos redireccionar el navegador, conseguira que esos errores llevaran al visitante a la pgina que nosotros deseramos. Intenta acceder a una direccin inexistente del tipo: http://localhost/noexisto.php y vers que aparece un mensaje de error advirtiendo que no existe ninguna pgina con ese nombre. Algo lgico, porque realmente no existe. Bastar con que abras tu editor no utilices el block de notas porque te dar muchsimos problemas en este caso escribas una lnea como esta ErrorDocument 404 http://www.rinconastur.net y guardes el documento en el raiz de tu servidor con el nombre .htaccess (aunque te parezca extrao, no lleva nada delante del punto). Reinicia el servidor, prueba nuevamente a acceder de nuevo a http://localhost/noexisto.php y observars que ahora no dice pgina no encontrada sino que se abre la pgina principal del este dominio. Edita de nuevo el fichero .htaccess y adele las siguientes lneas: ErrorDocument 401 http://www.rinconastur.net ErrorDocument 403 http://www.rinconastur.net

guarda los cambios, reinicia tu servidor y comprueba que cada vez que intentes acceder a una direccin inexistente te ocurre lo mismo que al pulsar aqu: http://rinconastur.net/noexisto.php. Como es lgico puedes redireccionar cada uno de los errores a una pgina distinta y, desde luego, no necesariamente a la ma. ;-)

Herencias
El archivo .htaccess provoca herencia. Eso significa que las especificaciones incluidas en un directorio sean restricciones o redirecciones son efectivas en todos los subdirectorios que contiene, incluso en el caso de que esos subdirectorios tengan su propio.htaccess y que en l se establezcan condiciones distintas a las anteriores. Al crear un fichero .htaccess las condiciones establecidas afectarn a todos sus subdirectorios. Por esa razn cuando pretendemos que desde subdirectorios distintos se redireccione a pginas distintas tendremos que incluir un .htaccess en cada uno de ellos y no poner ningn .htaccess en el directorio raz que los contenga.

Proteccin de directorios
Son muchas las posibilidades que ofrece .htaccess a la hora de restringir el acceso a un directorio determinado. Entre otras opciones, se puede denegar el acceso a todos los usuarios; denegar el acceso con excepciones, autorizar a todos (equivale a no restringir), autorizar con excepciones o requerir clave y contrasea. Lo que hemos denominado excepciones tambin permite una serie de alternativas tales como: una IP determinada, un rango de IP's, nombres de dominio, etctera. Slo comentaremos la forma de proteccin de directorios mediante claves de usuario y contrasea.

Restriccin de acceso a usuarios no autorizados


Este tipo de proteccin requiere crear un fichero de claves y contraseas y configurar de forma adecuada .htaccess Contraseas sin encriptar Para crear un fichero de claves y contraseas basta con abrir el block de notas y escribir la clave seguida de dos puntos (:) y a continuacin escribir la contrasea. Podemos poner tantas como deseemos sin ms limitaciones que escribir cada bloque clave:contraseaen una lnea distinta. Este puede ser un ejemplo:

pepe:Pepito pepa:Pepita
Podemos guardar este fichero en el sitio que deseemos sin que sea necesario que pertenezca al root del servidor que es la opcin ms aconsejable. Podemos ponerle cualquier nombre sin que importe que tenga extensin o no la tenga. Contraseas encriptadas Apache dispone de una utilidad que permite la creacin de ficheros de claves con contraseas encriptadas. Se trata de un programa llamado htpasswd.exe que est en el subdirectorio bin del servidor. Para crear un nuevo fichero el procedimiento sera el siguiente En la lnea de comandos: Inicio->Ejecutar

debemos escribir: path htpasswd -c nombre y path del fichero de claves usuario si se trata de un sistema operativo Linux Ubuntu habra que escribir en la consola htpasswd -c nombre y path del fichero de claves usuario

En nuestra configuracin y para crear un fichero con la palabra clave pepe escribiramos:
htpasswd -c /home/rinconas/seguridad/misclaves.txt pepe

y aparecera una ventana de MS-DOS en la que deberemos escribir la password para ese usuario.

Aadir usuarios a un fichero de contraseas encriptadas Porcederamos de la misma forma. Volveramos a ejecutar htpasswd con la nueva clave pero sin utilizar -c.

Cuidado! El modificador -c destruira el fichero anterior, si existiera y creara uno nuevo.


El proceso ahora sera:

htpasswd /home/rinconas/seguridad/misclaves.txt luis

Habramos creado as nuestro fichero con claves encriptadas. Si pretendiramos visualizarlo nos aparecera lo siguiente:

pepe:$apr1$EC4.....$7Z3.p2tv2QpzrZbo4bI2j0 luis:$apr1$SU4.....$iU8a.YTo.ZvYyRggDAvTC. Cuidado! Bajo Linux, antes de aadir el usuario luis tendramos que asegurarnos de que el fichero misclaves.txt tenga permisos para poder efectuar modificaciones en su contenido.

Configuracin de .htaccess
Para el caso especfico de nuestro servidor Apache, el fichero .htaccess ha de contener: AuthType Basic No permite modificacin e indica el tipo de autentificacin requerida. AuthName "nuestro texto " El texto que escribamos aqu aparecer como mensaje en la ventana en la que nos pedir la clave AuthUserFile "path" Entre esas comillas debes escribir el nombre del fichero de contraseas especificando su path completo. require valid-user Este texto indica que para acceder se requiere un usuario vlido. Con nuestra configuracin de Apache no es necesario especificar en .htaccess la forma de encriptacin de contraseas. El propio servidor interpreta el contenido del fichero y aplica u omite los criterios de encriptacin. A riesgo de parecerte pesados tenemos que volver a insistir que no todos los hosting tienen habilitada esta opcin, pero adems hemos de hacer mencin a otro detalle muy importante. La configuracin que hemos comentado no es vlida para todos los servidores. Segn como est configurado el servidor, la versin del software que utilice, etctera no sera extrao que se necesitara esta otra sintaxis: AuthType Basic, AuthName "Texto", AuthTextUserFile fichero, required valid-user, AuthTextCrypt On/Off u otras similares que pueden inducirnos al error. Lo mejor, en caso de servidores ajenos, es consultar al administrador del sistema sobre estos aspectos y recabarle detalles sobre la sintaxis especfica de su configuracin.

Un ejemplo de .htaccess
Supongamos que tenemos un directorio llamado protegido en cualquier parte del servidor (por ejemplo dentro de htdocs). La forma de protegerlo sera crear un fichero con nombre .htaccess con un contenido como este:

AuthType Basic AuthName "Pruebas de autentificacin" AuthUserFile "c:/Apache/seguridad/misclaves.txt" require valid-user


y guardarlo en el directorio que hayas especificado en lugar de lo escrito en rojo en el recuadro anterior. Al acceder al directorioprotegido aparecer una ventana como esta:

y si al cabo de tres intentos no escribimos la clave y contrasea adecuadas se producir un Error 401. Una vez que tengamos modificada la configuracin del servidor Apache estaremos en condiciones de poder proteger directorios restringir o limitar el acceso a ellos y tambin podremos redirigir peticiones a pginas predeterminadas en casos concretos. Este control ha de realizarse mediante ficheros que tienen por nombre .htaccess (el primer caracter es el punto), que no pueden llevar ningn tipo de extensin y que pueden ser incluidos en cualquier directorio o subdirectorio del espacio del servidor.

Cuidado! Existen otras opciones de proteccin de acceso a directorios. Algunas guardan la lista de usuarios autorizados en una base de datos y otras requieren que el usuario disponga de un certificado digital. En el epgrafe Servidores seguros tienes informacin al respecto.

Las cookies Las cookies


De igual modo que ocurra con la funcin mail, no todos los hosting tienen habilitada la opcin de envo de cookies. Como sabes, lascookies son pequeos ficheros que se escriben en el ordenador del cliente. Si utilizas Internet Explorer podrs ver que se almacenan como ficheros de texto en un directorio llamado Archivos temporales de Internet y que su nombre es de este tipo: cookie:xxx@nombre[z].txt donde xxx suele ser el nombre que figura en el registro de Windows como nombre del equipo (el que se pone al instalar Windows); nombre suele ser el nombre del directorio de servidor desde el que se envi la cookie y el nmero z suele ser el ordinal del nmeros de accesos a la pgina que enva la cookie. Firefox trata las cookies de forma distinta. Las almacena en un nico fichero llamado cookies.sqlite que suele encontrarse en:C:\Documents and Settings\Usuario\Datos de programa\Mozilla\Firefox\Profiles\xxxx.default. En cuanto a Google Chrome tambin utiliza un nico fichero llamado cookies que suele estar en un directorio como este: C:\Documents and Settings\Usuario\Configuracin local\Datos de programa\Google\Chrome\User Data\Default En el caso de usar Ubuntu como sistema operativo el fichero cookies.sqlite de Firefox puedes encontrarlo en un directorio cuya ruta ser similar a esta: /home/(nombre_de_usuario)/.mozilla/firefox/xxxx.default

Enviar y leer cookies


La instruccin para el envo de cookies debe insertarse al principio de la pgina y antes de cualquier etiqueta HTML o lnea en blanco. Esto es muy importante, no lo olvides. La sintaxis es la siguiente: setcookie(nombre, valor, expira)

donde nombre es una cadena que contiene el nombre de la variable que recoge el valor de la cookie, valor es el valor, numrico o cadena, que se asignar a la variable anterior y expira indica la fecha de caducidad de la cookie que suele expresarse usando el valor devuelto por la funcin time() (hora actual) ms un nmero que representa los segundos que han de transcurrir desde ahora hasta que lacookie expire. Los valores contenidos en las cookies pueden ser ledos por el servidor a partir de variables predefinidas $_COOKIE que, como todas las de este tipo, es un array asociativo. El ndice de este array ser el nombre asignado a la cookie. Veamos este ejemplo:

<?php /* setcookie escribe el contenido de la cookie en el ordenador del cliente */ setcookie("cookie1","Soy la cookie1",time()+3600); # escribe el valor leido en la cookie @print "Esta es la <i>galletita</i>: ".$_COOKIE['cookie1']; ?>
ejemplo266.php

Al ejecutar por primera vez este script (o al hacerlo despus de limpiar o eliminar historial de navegacin en el cliente) solo leeremos el texto Esta es la galletita : sin nada detrs. La explicacin es la siguiente: las instrucciones PHP se ejecutan en el servidor antes de enviar la pgina al cliente. Eso significa que, al ejecutar por primera vez, se inserta la orden de escritura y se comprueba el valor de la variable, que aun no ha sido creada y por ello aparece en blanco. Ser en la actualizacin ya se habra producido un envo al navegador y ya se habra escrito la cookie cuando si se leer el valor anterior Dado el carcter superglobal de $_COOKIE tambin se le puede aplicar la funcin extract tal como hemos comentado en al tratar el tema de los formularios. En este ejemplo podemos ver esa opcin

<?php extract($_COOKIE); @print "Esta es la galletita leida desde extract: ".$cookie1; ?>
ejemplo267.php

Como es lgico los valores de las cookies pueden asignarse tambin por medio de variables tal como puedes comprobar en estos ejemplos:

<?php $variable="Ahora me han incluido desde una variable"; setcookie("cookie2",$variable,time()+3600); @print "Esta es la nueva cookie: ".$_COOKIE['cookie2']; ?>
ejemplo268.php

<?php print "Estoy leyendo la cookie2: ".$_COOKIE['cookie2']; extract($_COOKIE); print "<br>Sigo leyendo lo mismo a travs del resultado de extract: ".$cookie2; ?>
ejemplo269.php

Una cookie definida como array

Una cookie puede contener varios valores agrupados en un array. Para ello basta con incluir en setcookie el nombre y el ndice de un array utilizando un setcookie por cada uno de los elementos del array tal como puedes ver en el ejemplo. Para leer las cookies enviadas de esta forma bastar con leer el array devuelto.

Cuidado! Fjate en la sintaxis de setcookie del ejemplo. Los nombres de los ndices del array no se escriben entre comillas. Observa tambin que al leer los datos de la cookie hemos de tratarla como un array bidimensional. El primer ndice el nombre de la cookie (en nombre del array que contiene la informacin) y el segundo ser el nombre concreto de cada uno de los ndices tal como han sido creados. <?php $valores=Array("Verde","Verano","Rolls-Royce","Millonario"); # a diferencia de lo que ocurre al definir elementos de array asociativos # en este caso los indices asociativos (color, estacin, etc.) no van # entre comillas setcookie("cookie3[color]",$valores[0],time()+3600); setcookie("cookie3[estacion]",$valores[1],time()+3600); setcookie("cookie3[coche]",$valores[2],time()+3600); setcookie("cookie3[finanzas]",$valores[3],time()+3600); # la variable superglobal $_COOKIE['cookie3'] contiene un array, por ello # la lectura de sus valores debe hacers considerando que se trata de un # array bidimensional @print "<br>El color viene en $_COOKIE['cookie3']['color'] y es: ".$_COOKIE['cookie3']['color']; @print "<br>La estacin $_COOKIE['cookie3']['estacion'] y es: ".$_COOKIE['cookie3']['estacion']; @print "<br>La finanzas $_COOKIE['cookie3']['finanzas'] estn: ".$_COOKIE['cookie3']['finanzas']; @print "<br>El coche es $_COOKIE['cookie3']['coche'] y es: ".$_COOKIE['cookie3']['coche']; print "<br> tambin podemos leer la cookie mediante un bucle como este:<br>"; if (isset($_COOKIE['cookie3']) ) { while( list( $indice, $valor) = each($_COOKIE['cookie3']) ) { echo "$indice == $valor\n"; } } ?>
ejemplo270.php

Un contador de visitas como aplicacin prctica


<?php @$numero=$_COOKIE['visitante']; $numero+=1; setcookie("visitante",$numero,time()+86400); if($numero==1){print "Es la $numero vez que visitas esta pgina";} if($numero>1){print "Es la $numero vez que visitas esta pgina";} ?>
ejemplo271.php

Cambio del color de fondo

<?php @$numero=$_COOKIE['color']; $numero+=1; setcookie("color",$numero,time()+86400); extract($_COOKIE); $colores=array('red','blue','yellow','green','black'); /* el fondo de la pgina tendr uno de estos cinco colores de fondo dependiendo del resto de la division entre 5 del nmero de visitas efectuadas hasta el momento */ @print "<body bgcolor='".$colores[$color%5]."'></body>"; ?>
ejemplo272.php

Sesiones Qu son las sesiones?


Suponemos que habrs estado alguna vez en un hotel y que recuerdas que al inscribirnos como huspedes nos facilitan una tarjetita identificativa que tericamente habramos de presentar a la hora de solicitar cualquier servicio del hotel (cafetera, restaurante, etc.). Al registrarnos en ese hotel estaremos iniciando una sesin (estancia) y al recibir la tarjeta identificativa se nos estar facilitando un identificador de sesin, que tiene validez temporal, ya que expirar en la fecha de salida indicada en ella y que recoge una serie de datos (nuestros datos personales, nuestro perodo de estancia, el precio y los servicios contratados, etctera). Imaginemos ahora que vamos al restaurante. Pueden ocurrir dos cosas: que decidamos efectuar el pago directamente, o que pidamos que el importe de la factura se incluya en nuestra cuenta. En el segundo de los casos, se reiniciar la sesin y se registrar una nueva variable de sesin el importe del servicio al firmar la nota de cargo del mismo. El responsable del restaurante deber guardar en algn sitio (probablemente en la oficina de recepcin) esa nota de cargo una variable de sesin de forma temporal ya que una vez abonado su importe o en el momento que abandonemos el hotel expirar la sesin y dejar de tener utilidad. Se requiere de forma imprescindible un directorio temporal en el que almacenar las variables de sesin. En PHP la sesiones funcionan de forma muy similar y de esa similitud surge la necesidad de habilitar un directorio temporal antes de utilizar sesiones. Si visualizamos el fichero info.php y buscamos la directiva session.save_path veremos que, en el caso de Windows tiene el valor C:/ServidoresLocales/tmp como consecuencia de la creacin del directorio tmp y de la modificacin que hicimos en la lnea 1471 dephp.ini cuando detallbamos el proceso de configuracin de php (puedes verlo aqu). En el caso de la instalacin sobre Ubuntu esa configuracin se hace de forma automtica. Al observar info.php podras ver que:session.save_path="/var/lib/php5" La posibilidad de propagacin de las sesiones y con ellas la informacin guardada en las variables de sesin ($_SESSION) son instrumentos de enorme utilidad en la gestin de de pginas web.

Funciones de sesin
Para la gestin de sesiones se utilizan estas funciones: session_start() Crea una sesin o contina con la actual. En el segundo caso el identificador de sesin debe ser tranferido por medio de una variable GET o a travs de una cookie. session_name()

Recoge el nombre de la sesin. Si no se asigna uno de forma explcita utiliza como nombre de sesin el contenido de la directivasession.name del fichero php.ini. Por defecto ese nombre suele ser PHPSESSID, pero no est de ms comprobarlo mirando el valor actual de la directiva session.name en info.php. session_name('nombre') Esta variante de la funcin anterior permite asignar un nuevo nombre a la sesin actual. Debemos tener en cuenta que si cambiamos de pgina y queremos mantener el mismo identificador (conservar la sesin anterior) esta funcin debe ser incluida con el mismo nombreen la nueva pgina y, adems, ha de ser insertada antes de que la funcin session_start() se invocada para iniciar la sesin. session_cache_limiter() El limitador de cach controla las cabeceras HTTP enviadas al cliente. Estas cabeceras determinan las reglas mediante las que se habilita la opcin de que los contenidos de las pginas puedan ser guardados en la cach local del cliente o se impida tal almacenamiento. En este ltimo modo no cach cada peticin de pgina requerira una nueva llamada al servidor, lo cual tiene como todo en la vida ventajas e inconvenientes. Entre las ventajas est la garanta de que en cada acceso estamos viendo la versin actualizada de la pgina, cosa que podra no ocurrir de otro modo. El inconveniente es que requiere una nueva peticin que puede significar un tiempo de espera, mientras el servidor produce la respuesta. Esta opcin viene configurada por defecto en las directivas de configuracin del php.inicomo nocache. Para evitar sea cual fuera la configuracin de php.ini el almacenamiento de las pginas en la cach del cliente hemos de utilizar: session_cache_limiter ('nocache,private') Igual que ocurra con session_name, si utilizamos est funcin debemos escribirla antes que session_name y tambin igual que en aquel caso deberemos repetirla en cada uno de los documentos. Por tanto, el orden de escritura de estas instrucciones sera el siguiente: <?php session_cache_limiter(); session_name('nombre'); session_start(); ..... ?> Es muy importante mantener ese orden y que este bloque de instrucciones sea el primer elemento de la pgina antes de cualquier otra etiqueta y que no haya lneas en blanco ni antes de la etiqueta <?php ni entre ella y las llamadas a estas funciones.

Propagacin de las sesiones


La verdadera utilidad de las sesiones estriba en su propagacin, es decir, la posibilidad que tanto el identificador de sesin como losvalores de las variables de sesin luego hablaremos de estas variables puedan ir pasando de una pgina a otra sin necesidad de recurrir al uso de formularios. Para entendernos, se trata de dar validez y utilizar la misma tarjeta para movernos por las diferentes secciones delhotel que hemos utilizado como ejemplo. La forma habitual de propagar las sesiones es a travs de cookies, pero como quiera que el usuario tiene la posibilidad de desactivar la opcin (no aceptar cookies) PHP dispone una opcin alternativa que permite la propagacin a travs de la URL an en el caso de que lascookies estn desactivadas.

Caso de que el cliente tenga activada la opcin aceptar cookies


Si queremos que las sesiones se propaguen nicamente en el caso de que est activada la opcin aceptar cookies en el navegador bastar con hacer la llamada a la nueva pgina siguiendo el mtodo tradicional, es decir: <A href="pagxx.php"> y que esa nueva pgina contenga sin que lo preceda ninguna lnea en blanco el script siguiente:

<? session_cache_limiter(); session_name('nombre'); session_start(); ..... ?> donde no es imprescindible incluir session_cache_limiter pero cuando se incluye ha de ir como primera lnea del script. Consession_name ocurre algo similar. Si la sesin fue iniciada con un nombre distinto al que le asigna por defecto PHP, debemos escribirsession_name('nombre'), y adems, nombre debe tener el mismo valor que en la pgina precedente. Si no se asigna ningn nombre tomar el valor PHPSESSID nombre por defecto en todas las pginas y no ser necesaria la instruccin session_name.

Caso de cookies deshabilitadas


Para garantizar la propagacin de las sesiones an cuando el navegador est configurado para no aceptar cookies tendremos quepasar el identificador de sesin junto con las llamadas a las pginas siguientes. Para ello se requiere la siguiente sintaxis: <A href="pagxx.php?<?php print echo session_name()."=".session_id():?>" Con esta sintaxis, despus de escribir el ? (recordemos que es la forma de indicar que aadimos variables y valores para que sean transferidos junto con la peticin de la pgina) estaremos pidiendo a PHP que escriba como nombre de variable el nombre de la sesin y como valor de esa variable, despus de insertar el signo igual, el identificador de sesin. Es evidente que la utilizacin de esta opcin nos permite asegurar que las sesiones y sus variables podrn ser usadas sin riesgos de que una configuracin inadecuada por parte del cliente produzca resultados imprevisibles.

Algunos ejemplos
Aqu tenemos un ejemplo de como iniciar una sesin y tambin podremos comprobar como se propaga al llamar a la misma pgina si est activada la opcin aceptar cookies. Si ejecutamos reiteradamente el script pulsando en volver a llamar esta pgina podremos ver que no se modifica el valor del identificador de sesin. Si bloqueamos las cookies (en este enlace est descrito el procedimiento para hacerlo) podremos comprobar que ahora la sesin no se propaga y que cada vez que volvemos a llamar a la pgina nos aparece un nuevo valor en el identificador de sesin, es decir, se crea una nueva sesin.

<?php session_start(); #pedimos que escriba el identificador nico y el nombre de la sesin echo session_id(),"<br>"; echo session_name(),"<br>"; ?> <A Href="ejemplo273.php">Volver a llamar estallamar esta pgina</A>
ejemplo273.php

Ahora haremos una modificacin importante en el script. Al incluir en la llamada a la pgina el nombre y el identificador de sesinestamos transfiriendo mediante el mtodo GET el valor de esa variable. De esta forma, la propagacin de la sesin estar asegurada sea cual fuere la configuracin del navegador del cliente. Podemos comprobar activando/desactivando cookies que en las sucesivas llamadas a la pgina se mantiene el identificador de sesin.

<?php session_start(); #pedimos que escriba el identificador nico y el nombre de la sesin echo session_id(),"<br>"; echo session_name(),"<br>";

?> <A Href="ejemplo275.php?<?php echo session_name()."=".session_id();?>">Volver a pgina</a>


ejemplo275.php

esta

Sesiones con nombre propio En los ejemplos siguientes se crean y propagan sesiones con nombre propio sin que ello altere las condiciones de respuesta con las opciones aceptar /no aceptar cookies. Tambin hemos incluido session_cache_limiter con las restricciones de nocache con lo cual el navegador no guardar las pginas de ejemplo en la cach. Si cambiramos los parmetros (nocache, private por public) podramos comprobar si se almacena en la cach del navegador la pgina web devuelta por el servidor.

<?php session_cache_limiter('nocache,private'); session_name('leocadia'); session_start(); #pedimos que escriba el identificador nico echo session_id(),"<br>"; echo session_name(),"<br>"; ?> <A Href="ejemplo276.php">Volver a llamar esta pgina</A>
ejemplo276.php

<?php session_cache_limiter('nocache,private'); session_name('leocadia'); session_start(); #pedimos que escriba el identificador nico echo session_id(),"<br>"; echo session_name(),"<br>"; ?> <A Href="ejemplo278.php?<?php echo session_name()."=".session_id()?>">Volver a esta pgina</A>
ejemplo278.php

Las cookies de sesin y sus parmetros


Para el caso de que el navegador del cliente tenga activada la opcin de aceptar cookies PHP dispone de una funcin que permiteleer los parmetros de esa cookie. Es la siguiente: session_get_cookie_params() que devuelve un array asociativo con los siguientes ndices: lifetime: Indica el tiempo de duracin de la duracin de la cookie path: Indica la ruta -en el ordenador del cliente- en la que se almacenan los datos de la sesin domain :Indica el dominio de procedencia de la cookie. secure :Indica si la cookie solo puede ser enviada a travs de conexiones seguras (1) o si no considera esa posibilidad (0). Los valores por defecto para estos parmetros se pueden establecer en la configuracin del fichero php.ini. Si visualizamos info.phppodremos ver en las directivas session.cookie_xxx nuestros valor por defecto y observaremos que session.cookie_lifetime tiene valor 0, razn por la cual si con la opcin aceptar cookies activada ejecutamos cualquiera de los script anteriores y miramos el directorio Temporal Internet Files, no encontraremos ninguna de estas cookies, dado que su plazo de expiracin es cero.

<?php session_name('mi_sesion'); session_start();

echo session_id(),"<br>"; echo session_name(),"<br>"; # recogemos en la variable $a el array con los datos de la sesin $a=session_get_cookie_params(); foreach($a as $c=>$v){ echo $c,"--->",$v,"<br>"; } ?> <A Href="ejemplo279.php">Volver a llamar esta pgina</a>
ejemplo279.php

<?php session_name('mi_sesion'); session_start(); echo session_id(),"<br>"; echo session_name(),"<br>"; # recogemos en la variable $a el array con los datos de la sesin $a=session_get_cookie_params(); foreach($a as $c=>$v){ echo $c,"--->",$v,"<br>"; } ?> <A Href="ejemplo281.php?<?php echo session_name()."=".session_id()?>">Volver a esta pgina</A>
ejemplo281.php

Las configuraciones de session.cookie pueden cambiarse sin necesidad de modificar el fichero php.ini. Para ello disponemos de la funcin: session_set_cookie_params(duracin ,'path','dominio',segura) que permite configurar esos parmetros de forma temporal unicamente para la pgina en la que est insertado y que como en los casos anteriores puede configurarse slo para el caso de que el navegador acepte cookies como para las situaciones en la que esa opcin est deshabilitada. En estos ejemplos escribir siempre que est configurada la opcin aceptar cookies en el navegador del cliente una cookie que tendr una caducidad de DIEZ minutos (el valor 10 de session_set_cookie_params). Esa cookie se guardar en el mismo directorio (/) donde se guardan las pginas web visitadas (el famoso C:\WINDOWS\Temporary Internet Files, en la configuracin por defecto de IE), pero..., eso solo ocurrir si tal como ves en el ejemplo pones en el parmetro dominio elnombre real del dominio donde est alojada la web. Si el nombre de dominio no coincide con que alberga la pgina razonable criterio de seguridad no se guardar la cookie.

<?php session_set_cookie_params (10,"/","localhost", 0); session_name('mi_sesion'); session_start(); echo session_id(),"<br>"; echo session_name(),"<br>"; $a=session_get_cookie_params(); foreach($a as $c=>$v){ echo $c,"--->",$v,"<br>"; } ?> <A Href="ejemplo282.php">Volver a llamar esta pgina</A>
ejemplo282.php

<?php session_set_cookie_params (10,"/","localhost", 0);

session_name('mi_sesion'); session_start(); echo session_id(),"<br>"; echo session_name(),"<br>"; $a=session_get_cookie_params(); foreach($a as $c=>$v){ echo $c,"--->",$v,"<br>"; } ?> <A Href="ejemplo284.php?<?php echo session_name()."=".session_id()?>">Volver a esta pgina</A>
ejemplo284.php

Manejo de variables de sesin


Las funciones ms importantes para el manejo de variables de sesin son las siguientes: $_SESSION['variable']=valor es una de las formas de definir una variable de sesin. El ndice variable debe contener entre comillas el nombre que pretendamos asignarle a esa variable de sesin y valor sera el valor asignado a esa variable. Si ya existiera le reasignara el nuevo valor. unset($_SESSION); La funcin unset destruye las variables contenidas en el parntesis. En este caso, al contener el array $_SESSION destruira todas las variables contenidas en l. unset($_SESSION['variable']); Es similar a la anterior. En este caso solo sera destruida el elemento del array cuyo ndice sea var. isset($_SESSION['variable']); La funcin isset no es especfica del tratamiento de sesiones devuelve un valor booleano (UNO NUL) segn que exista o no exista la variable contenida en el parntesis. De hecho, se comporta con las variables de sesin de forma idntica a como lo hara con cualquier otro tipo de variable.

<?php # iniciamos la sesin session_start(); # visualizamos el identificador de sesin print "Este es el identificador de sesion: ".session_id()."<br>"; # registramos una variable de sesin asignandole un nombre $_SESSION['variable1']=""; #asignamos un valor a esa variable de sesin $_SESSION['variable1']="Filiberto Gmez"; /* registramos una nueva variable de sesin asignandole directamente un valor */ $_SESSION['variable2']="Otro filiberto, este Prez"; #comprobamos la existencia de la variables de sesin @print "Mi_variable1 esta registrada: ".isset($_SESSION['variable1'])."<br>"; #leemos el contenido de esa variable @print "Su valor es: ".$_SESSION['variable1']."<br>"; #comprobamos la existencia de la otra variable y la visualizamos @print "Mi variable2 esta registrada :".isset($_SESSION['variable2'])."<br>"; print $_SESSION['variable2']."<br>"; #destruimos la variable1 unset($_SESSION['variable1']); @print "La variable1 ha sido destruida:".isset($_SESSION['variable1'])."<br>";

@print $_SESSION['variable1']."<br>"; #destruimos todas las variables restantes unset($_SESSION); #comprobamos que han sido destruidas @print "La variable1 ya estaba vacia: ".isset($_SESSION['variable1'])."<br>"; @print $_SESSION['variable1']."<br>"; @print "Tambin ha sido destruida la variable2: ".$_SESSION['variable2']."<br>"; @print $_SESSION['variable2']."<br>"; ?>
ejemplo285.php

Propagacin de sesiones
Los tres scripts siguientes son un ejemplo del uso de sesiones para la propagacin de sesiones. Funcionan bajo cualquier forma de register_globals y tambin en el caso en que las cookies estuvieran desactivadas en el navegador del cliente

<?php /* recuerda que entre <?php y la primera lnea no puede haber lneas en blanco ni tampoco puede haberla encima de <? aunque como en este caso, si admite lneas de comentario pero no lneas en blanco */ # deactivamos la opcion de que las pginas puedan guardarse # en la cache del navegador del cliente session_cache_limiter('nocache,private'); # le asignamos un nombre a la sesin # aunque lo habitual sera dejar el nombre por defecto # que le asigna la configuracin de php.ini session_name('pruebas'); # iniciamos la sesion session_start(); # creamos variables de sesion y les asignamos valores $_SESSION['valor1']=25; $_SESSION['valor2']="Ambrosio de Morales"; $_SESSION['variable3']="Una prueba ms"; /* cerramos el script e insertamos un enlace a otra pgina y propagamos la sesin incluyendo en la llamada el nombre de la session y su identificador En esta pgina no se visualizara nada. Solo el enlace */ ?> <A Href="ejemplo287.php?<?php echo session_name()."=".session_id()?>">Propagar la sesion</A>
ejemplo286.php

<?php /* pese a que la sesion viene de la pgina anterior tenemos que poner nuevamente session_cache_limiter ya que esta instruccion no se conserva solo es vlida para la pgina en la que esta definida Tambin tenemos que poner en session_name el mismo nombre de la pgina anterior, de no hacerlo PHP entendera que se trata de iniciar una sesion distinta Por ultimo tambin debemos iniciar la sesin es obligatorio iniciarla */ session_cache_limiter('nocache,private'); session_name('pruebas');

session_start(); /* comprobaremos que la sesion se ha propagados visualizando el array asociativo $_SESSION que contiene todas la variables de Sesion */ foreach($_SESSION as $indice=>$valor){ print("Variable: ".$indice." Valor: ".$valor."<br>"); } # modificamos los valores de las variables de sesion # de igual forma que si fueran variables de cualquier otro tipo $_SESSION['valor1']+=87; $_SESSION['valor2'] .=" bonito nombre"; # destruimos la tercera variable unset($_SESSION['variable3']); # propagamos la sesion a la pgina siguiente # con identico proceso al del script anterior ?> <A Href="ejemplo288.php?<?php echo session_name()."=".session_id()?>">Propagar la sesion</A> <?php # identicos comentarios a los anteriores session_cache_limiter('nocache,private'); session_name('pruebas'); session_start(); # este bucle nos confirmar que se han propagado # los nuevos valores y que la tercera variable ha sido destruida foreach($_SESSION as $indice=>$valor){ print("Variable: ".$indice." Valor: ".$valor."<br>"); } ?>

Clases y objetos (I) Clases y objetos


Aunque PHP 5 no es un lenguaje orientado a objetos, s tiene recursos que permiten definir clases y construir objetos. El modelo de objetos de PHP 5 ha sido reescrito en su prctica totalidad y presenta sustanciales diferencias respecto a las versiones anteriores. El uso declases y objetos (POO Programacin Orientada a Objetos) no aade ninguna funcionalidad nueva a las posibilidades de PHP. Su verdadera utilidad es la de hacer la programacin de otra manera, con un cdigo ms legible y reutilizable.

Las clases
Una clase no es otra cosa que una especie de plantilla dentro de la cual se pueden definir una serie de variables llamadaspropiedades que pueden contener valores predefinidos y un conjunto de funciones denominadas mtodos que pueden ser invocadasdesde cualquier parte del documento por un objeto o instancia de esa clase. La sintaxis que permite definir una clase es siguiente: class nombre { .... ... definicin de variables y/o propiedades.... .... .. constructor (opcional)...

.... .. destructor (opcional)... .... .. definicin de mtodos o funciones ... .... }

Vayamos por partes. La palabra reservada class es obligatoria y ha de ir seguida de un nombre mediante el que ser identificada la clase. La definicin de la clase comienza con un llave de apertura ({) y acaba con una llave de cierre (}). Entre ambas llaves podemos incluir sus variables o propiedades y tambin sus mtodos o funciones. A las variables o propiedades pueden serles asignados valores, aunque no es imprescindible hacerlo. Los mtodos o funcionestienen una sintaxis muy similar a la utilizada en la programacin estructurada. Entre los mtodos o funciones susceptibles de ser incluidos en una clase existen dos bastante especiales. Son los llamadosconstructor y destructor. Ninguno de ellos tiene carcter obligatorio. Su peculiaridad estriba en que se ejecutan de forma automtica en determinadas circunstancias. Hablaremos de ellas un poco ms adelante.

Definicin de las propiedades


Para definir una variable o propiedad en una clase es obligatorio anteponer a su nombre una de estas tres palabras reservadas:public, private o protected. Por compabilidad con versiones anteriores de PHP si se usa la palabra var ser interpretada como un alias depublic. El nombre de la variable utiliza la sintaxis habitual de PHP y en el caso de que tratemos de asignarle un valor, bastar con poner detrs del nombre el signo = seguido de ese valor que en el caso de ser una cadena tienen que ir entre comillas. A modo de ejemplo podemos decir que public $pepe="Jose" es una sintaxis vlida, pero que $pepe="Jose" no lo es dado que le falta la palabra reservada (opcin de visibilidad) que obligatoriamente debe llevar delante de su nombre y que de no ser incluida provocara un error. Lo que se conoce como encapsulamiento es uno de los pilares bsicos de la Programacin Orientada a Objetos. Permite establecer las condiciones y/o restricciones de visibilidad de los diferentes elementos (propiedades y mtodos) de una clase. Cuando al definir una variable o propiedad anteponemos a su nombre la palabra public estamos estableciendo ese carcter pblico de visibilidad que significa que sus valores pueden ser vistos e incluso modificados desde cualquier parte del script en que sean invocadas. Por el contrario, si establecemos la visibilidad como private (privada) estamos encapsulando la informacin de forma que sus valores slo son accesibles a travs de mtodos o propiedades incluidos en la propia clase. La tercera de las posibilidades, protected (protegida), flexibiliza un poco la condicin private al permitir que el mtodo o propiedad sea ser visible desde la propia clase y desde sus clases extendidas (las trataremos un poco ms adelante cuando nos refiramos a la herencia).

Funciones o mtodos de clase


Los mtodos o funciones definidas en las clases que tienen una sintaxis casi idntica al resto de las funciones PHP function nombre( ){ ... instrucciones.... .... }

Las diferencias ms sustanciales respecto a las funciones de la programacin estructurada son: Los mtodos siguen los mismos criterios de encapsulamiento que hemos comentado al hablar de las propiedades. Se establecen anteponiendo a la palabra function una de las tres palabras public, private o protected aunque en este caso si se omite no se genera error sino que el mtodo es considerado como public. Siempre que desde un mtodo se invoque una variable o propiedad definida en la misma clase ha de hacerse mediante la sintaxis: $this ->propiedad. Los mtodos de la propia clase se invocan de esta forma: $this->nombre_de_la_funcion(). Como es lgico dentro del parntesis pueden incluirse los parmetros o argumentos que sean necesarios.

Prestemos mucha atencin. El $ va siempre delante de la palabra this y solo se escribe una vez y en esa posicin. El nombre de la variable (que va siempre despus de -> no lleva el $. Este es un ejemplo de una clase muy sencilla. Como ves el nombre de la clase es MiClase. Como es lgico, si tratas de ejecutar el ejemplo no obtendrs ningn resultado. Ser necesario que un objeto utilice esta clase.

<?php class MiClase{ public $factor1=7; // esta es pblica private $factor2=8; // variable privada protected $factor3=3; // variable protegida function calcula($a=3,$b=5){ // al no indicar visibilidad ser public return $this->factor1-$b^2+$this->factor2*$a-$this->factor3; } } ?>
ejemplo299.php

Los objetos
Las clases son solo plantillas y sus mtodos no sern ejecutados en tanto no exista un objeto que requiera su aplicacin. Dicho en forma coloquial, una clase es como una sartn. En tanto no tengamos algo que freir carece de utilidad alguna. Su razn de ser son los objetos susceptibles de se cocinados por ella. Lo mismo ocurre con las clases cuya autntica razn de ser es servir para la creacin y manejo de sus objetos.

Creacin y destruccin de objetos


Para crear un nuevo objeto (instancia de la clase) que utilice una clase determinada debemos usar la siguiente sintaxis: $objeto = new clase

donde objeto es una palabra cualquiera con la que identificar el objeto (como si se tratara de una variable), new es una palabra reservada obligatoria y clase es el nombre de una clase que puede estar escrita en el mismo documento o en un fichero externo. Si la clase est escrita en un documento distinto del que contiene el script que crea el objeto habremos de utilizar include o require para incluirla. Cuidado! Fjate que por el momento no hemos puesto los () requeridos para invocar las funcionesdetrs del nombre de la clase.

Cuando se trata de eliminar un objeto (liberar el rea de memoria que contiene toda la informacin relativa a este) podemos utilizar la siguiente sintaxis: $objeto = null o unset(objeto ) si bien es cierto que se destruyen de forma automtica una vez termina la ejecucin del script que los crea y utiliza.

Utilizacin de los objetos


Una vez creado un objeto ya se podrn utilizar (si su visibilidad lo permite) y modificar sus propiedades y tambin las funciones o mtodos de su clase. Los mtodos se invocan mediante la siguiente sintaxis: $objeto->funcion() o $objeto->funcion(p,q) o $objeto->funcion(p)

dnde $objeto es el objeto creado en la instruccin anterior, el -> es obligatorio, funcion es el nombre de uno de los mtodos o funciones definidos en la clase invocada y donde los () son obligatorios y adems como ocurra en las dems funciones PHP puede contener valores, variables, etctera separadas por comas. Las propiedades (siempre que su visibilidad lo permita) son accesibles mediante: $objeto->propiedad o $objeto->propiedad=valor

En el primer caso estaramos leyendo el valor de esa propiedad y en el segundo le estaramos asignando el incluido despus del signo igual.

<?php /* incluimos el fichero que contiene la clase que pretendemos utilizar */ include('ejemplo299.php'); /* creamos un objeto utilizando el nombre exacto de la clase*/ $MiObjeto1=new MiClase; //no lleva parntesis /* leeremos los valores de las propiedades */ print "<br />Valor por defecto de la propiedad factor1: "; /* solo podremos leer desde aqu la propiedad publica factor1 Las propiedades privadas y protegidas solo son accesibles desde la propia clase y aqu estamos haciendo desde uno objeto que la instancia */ print $MiObjeto1->factor1; print "<br />Aplicacin del mtodo calcula "; print "<br />No pasamos argumentos. Por tanto calcula con 'a'=3 y 'b'=5: "; print $MiObjeto1->calcula(); print "<br />Pasamos 15 como argumento por tanto calcula con 'a'=15 y 'b'=5: "; print $MiObjeto1->calcula(15); print "<br />Pasamos 125 y -98 como argumentos por tanto calcula con 'a'=125 y 'b'=98: "; print $MiObjeto1->calcula(125,-98); /* solo podemos modificar desde aqu la propiedad factor1. Las otras dos por su carcter privado y restringido solo podran ser modificadas desde dentro de la propia clase o de una clase extendida */ print "<br />Modificamos el valor de la propiedad factor1: "; $MiObjeto1->factor1=196; print$MiObjeto1->factor1; print "<br />Clculo con los nuevos valores por defecto: "; print $MiObjeto1->calcula(); print "<br />Clculo con nuevos valores por defecto pero asignando a 'a' el valor 25: "; print $MiObjeto1->calcula(25); print "<br />Clculo con nuevos valores por defecto con 'a'=15 y 'b'=-8: "; print$MiObjeto1->calcula(15,-8); /* creamos un nuevo objeto y comprobamos que la modificacin de la propiedad factor1 no afectar al nuevo objeto (la modificacin se hizo en el objeto anterior no en la clase) */ $MiObjeto2=new MiClase; print "<br />Clculo con valores por defecto del nuevo objeto: "; print $MiObjeto2->calcula(); print "<br />Clculo con valores por defecto del objeto anterior: "; print $MiObjeto1->calcula(); /* destruimos el primero de los objetos aunque no sea necesario hacerlo. Al finalizar el script se destruira de forma automtica */ $MiObjeto1=null; ?>
ejemplo300.php

En este otro ejemplo trataremos de ver el comportamiento de los mtodos y propiedades de carcter no pblico.

<?php /* crearemos una clase con los diferentes tipos de variables y mtodos */ class Coche{ /* las propiedades han de tener especificada su visibilidad */ public $potencia="135 C.V."; public $tipo_iva="33"; private $precio="24535 euros"; protected $modelo="HF345"; /* un mtodo publico ya que no especificamos visibilidad */ function precio_final(){ return (int)($this->precio)*(1+$this->tipo_iva/100); } /* un mtodo privado al que solo podremos acceder desde la propia clase*/ private function precio_amigo($descuento=15){ return $this->precio_final()*(1-$descuento/100); } /* un metodo publico que nos lleva a otro privado. La funcion siguiente es accesible por su condicin de pblica. Ella puede acceder a las funciones privadas de la propia clase. Asi que le pedimos que "se cuele" por "la puerta trasera" en el mtodo precio_amigo y nos devuelva el resultado */ function puerta_trasera($porcentaje){ return $this->precio_amigo($porcentaje); } /* un metodo publico que accede a una propiedad privada. No podemos cambiar precios directamente porque estn en una variable privada. Pero esta funcin pblica si tiene acceso a cualquier propiedad o mtodo de su clase. La utilizamos para cambiar el precio */ function cambia_precios($precio){ $this->precio=$precio; } } /*Hasta aqu la clase. Ahora toca instanciar objetos de la clase Coche */ $MiNuevoCoche= new Coche; /* visualizamos sus propiedades publicas */ print "<br>La potencia es: ".$MiNuevoCoche->potencia; print "<br>El tipo de IVA es: ".$MiNuevoCoche->tipo_iva; print "<br>No puedo conocer el modelo. Es una propiedad absurdamente protegida"; print "<br>Tampoco puedo acceder al precio. Es una propiedad privada"; print "<br>Cambio el precio: a 100 euros"; $MiNuevoCoche->cambia_precios('100 euros'); print "<br>Compruebo el precio final: ".$MiNuevoCoche->precio_final(); print "<br>El precio de amigo (25% descuento)es: ".$MiNuevoCoche->puerta_trasera(25); /* instanciemos un nuevo objeto. Al nuevo cliente no le afectarn las modificaciones anteriores */ $TuNuevoCoche= new Coche; print "<br>Para el nuevo objeto el precio final: ".$TuNuevoCoche->precio_final(); ?>
ejemplo298.php

Constructores y destructores
Un constructor es una funcin que se ejecuta de forma automtica cada vez que se instancia un nuevo objeto. Para que PHP considere a una funcin como tal ha de estar definida en la propia clase y adems debe tener por nombre la palabra reservada __constructque tal como puedes ver comienza por dos guiones bajos. Cuando est definido, el constructor la instancia del nuevo objeto puede hacerse de una de estas formas: $objeto=new nombre_clase;

No difiere en nada de la comentada anteriormente. El constructor usuar como valores de las variables que necesite utilizar los definidos en la propia funcin __construct y/o los valores de la propiedades establecidas en la propia clase. $objeto=new nombre_clase (valor1, valor2, ...)

En este caso se incluyen, dentro del parntesis, los valores que deben asignarse a una o varias de las variables que requieran ser utilizadas por la funcin __construct. Cuando se le pasan valores la funcin se ejecuta sin tomar en consideracin los asignados por defecto y cuando se le pasan slo parte de esos valores utiliza los valores recibidos y para los no asignados en la llamada utiliza los valores delconstructor. Un destructor es tambin una funcin que se ejecuta de forma automtica cada vez que se destruye objeto. Esa funcin ha de estar definida en la propia clase con el nombre __destruct (tambin comienza por dos guiones bajos). Hemos de tener en cuenta que esta funcin no destruye el objeto. Simplemente se ejecuta cuando se produce esa destruccin. Podramos decir que es algo as como un timbre de alarma. El timbre no provoca el incendio. Lo nico que hace es sonar cuando se produce uno. Los objetos van a dejar de ser necesarios cuando se finalice la ejecucin de un script. Al llegar a ese punto ser cuando, de forma autmatica, se libere la memoria usada para contenerlos y como consecuencia de ello se destruyan. Al producirse ese evento (liberacin de memoria) ser cuando se ejecute la secuencia de instrucciones contenidas en la funcin __destruct. Tambin podramos destruir un objeto en cualquier punto del proceso por medio de $objeto= null o unset($objeto) tal como ya hemos comentado. El objeto $objeto sera eliminado de la memoria y como consecuencia de esa destruccin se ejecutara de forma automtica la funcin __destruct. Aqu tienes un ejemplo de una clase que incluye un constructor y un destructor.

<?php class Operador1{ public $factor1=7; // esta es pblica private $factor2=8; // variable privada protected $factor3=3; // variable protegida function __construct($a=0,$b=0){ print "El constructor de MiObjeto".$a." ha fabricado esta fecha: "; print date("j-n-Y",(time()+($this->factor1+$b)*24*3600)); print "<br />"; } function opera($a=3,$b=46){ return $this->factor1-$b^2+$this->factor2*$a-$this->factor3; } function __destruct(){ print "O se acaba de destruir un objeto o me han llamado (soy __destruct)<br />"; } } ?>
ejemplo301.php

Si intentas ejecutar el ejemplo anterior no obtendrs ningn resultado. Slo es una clase. En este otro ejemplo instanciaremos esa clase y crearemos algunos objetos para tratar de comprobar el funcionamiento del constructor y el destructor.

<?php /* incluimos el fichero que contiene la clase que pretendemos utilizar */ include('ejemplo301.php'); /* creamos vaios objeto utilizando la clase que acabamos de incluir*/ $MiObjeto0=new Operador1; //no lleva parntesis y no incluye ningun valor $MiObjeto1=new Operador1(1); //solo lleva el primero de los parmetros del constructor $MiObjeto2=new Operador1(2,8); //incluye dos parmetros $MiObjeto3=new Operador1(3,98); /* llamo a la funcin destruct que pese a su nombre no destruye nada. Se llama as porque se ejecuta automticamente cuando un objeto deja de estar referenciado por una variable y se autodestruye. */ $MiObjeto0->__destruct();

print "El destructor no destruy. El objeto mantiene sus propiedades Este es factor 1: "; print $MiObjeto0->factor1."<br />"; print " Clculos en MiObjeto1. Empezamos por valores por defecto: "; print $MiObjeto1->opera(); print "<br />Clculo con valores por defecto pero asignando a 'a' el valor 25: "; print$MiObjeto1->opera(25); print "<br />Clculo con 'a'=15 y 'b'=-8: "; print$MiObjeto1->opera(15,-8); print "<br />Modificamos el valor de la propiedad factor1 en el objeto 1: "; $MiObjeto1->factor1=196; /* vamos a destruir MiObjeto2 y comprobaremos como al hacerlo se dispara automaticamente la funcion __destruct */ print "<br>Me van a borrar ahora mismo: "; $MiObjeto2 = null; print $MiObjeto1->factor1; print "<br />Clculo con los nuevos valores por defecto: "; print $MiObjeto1->opera(); print "<br />Clculo en MiObjeto3 pero asignando a 'a' el valor 25 al objeto 3: "; print $MiObjeto3->opera(25); print "<br />Clculo con nuevos valores por defecto con 'a'=15 y 'b'=-8 al objeto 4: "; print $MiObjeto3->opera(15,-8); print "<br />Vamos a acabar el script. Lo objetos se autodestruirn y aparecern los mensajes alusivos a eso.<br />"; print "Quedan tres objetos y tres autodestrucciones. Cada una de ellas disparar la funcin __destruct<br />"; ?>
ejemplo302.php

Clases extendidas y clases finales


La herencia es otra de las razones de ser de la Programacin Orientada a Objetos. En PHP tambin tenemos la posibilidad de crearclases extendidas o clases derivadas de una clase padre. Su caracterstica ms importante es que pueden heredar todas las propiedades y mtodos de esta y, adems, tienen la posibilidad de agregar otros nuevos y/o modificar o redefinir los heredados (polimorfismo).

Sintaxis de las clases extendidas


Para definir una clase clases extendida se requiere la siguiente sintaxis: class hija extends padre { .... ... definicin o redefinicin de variables (opcional).... .... .. constructores (opcional)... .... .. definicin o redefinicin de funciones (opcional)... .... }

dnde hija es el nombre de la nueva clase (la extendida), padre es el nombre de la clase padre y extends es la palabra reservada que indica a PHP que se trata de una clase extendida. Se puede impedir que una clase pueda extenderse. Para ello basta con anteponer a la palabra class la palabra final. Si escribimos: final class nieta extends hija {.....}

estaremos imposibilitando que puedan definirse clases extendidas de la clase nieta. Las restricciones de PHP 5 en lo relacionado con las herencias son las que puedes ver en este grfico:

Este es un ejemplo de clase extendida de una de las anteriores. Si intentas ejecutar el script te dar un mensaje de error advirtiendo de que no encuentra la clase padre. En este caso es irrelevante dado que el documento solo tiene la finalidad de escribir la clase extendida.

<?php /* esta clase no podra ser extendida y es hija de la llamada Operador1. Heredar de ella sus mtodos y sus propiedades. Podr modificarlos y tambin incluir los propios */ final class Operador2 extends Operador1{ /* modificamos esta propiedad cambiando su valor */ public $factor1=297; // esta es pblica /* aadimos una nueva propiedad */ public $factor4=-67; /* Este es el constructor de la clase extendida. Sustituira al de la clase padre */ function __construct(){ print "Soy el constructor extendido y punto.<br>"; } /* redefinimos la funcin opera. Dar otros resultados */ function opera($a=3,$b=46){ /* utilizaremos solo factor1 y factor3 porque son los nicos visibles desde esta clase. factor1 por su condicin de pblico y factor3 porque su condicin de protegido le hace tambin visible desde la clase extendida */ return $this->factor1-$a^2+$this->factor3*$b+$this->factor3; } /* omitimos la funcin __destruct pero podremos usar la definida en la clase padre */ function nueva(){ print "Soy el resultado de una nueva funcin. <br />"; } } ?>
ejemplo303.php

Aqu tienes un ejemplo de utilizacin de algunas de las posibilidades de la clase extendida anterior. Ahora ya incluimos ambas clases (padre y extendida) y no tendremos mensajes de error al ejecutar el script.

<?php /* hemos de incluir los ficheros que contienen ambas clases */ include('ejemplo301.php'); include('ejemplo303.php'); /* crearemos un objeto instanciando la clase padre y otro instanciando la extendida*/ $Objeto_de_clase_padre=new Operador1; /* este primer objeto no va a tomar en cuenta nada de lo contenido en la clase extendida*/ $Objeto_de_clase_extendida=new Operador2; /*este segundo objeto ya va a utilizar el constructor de la clase extendida. Al ejecutar el script podrn verse las diferencias */ print "<br>Este el valor del factor1 en el objeto creado a partir de la clase padre: "; print $Objeto_de_clase_padre->factor1; print "<br>Este el valor del factor1 en el objeto creado a partir de la clase extendida: "; print $Objeto_de_clase_extendida->factor1; /* la funcin (mtodo) nueva solamente puede ser usada en objetos creados mediante la clase extendida ya que para la clase padre no est definida. */ print "<br>Soy el resultado de la funcion nueva() aplicada al objeto de la clase extendida: "; $Objeto_de_clase_extendida->nueva(); /* la funcin (mtodo) opera es distinta segn el objeto pertenezca a una u otra clase. */ print "<br>Soy el resultado de la funcion opera() aplicada al objeto de la clase padre: "; print $Objeto_de_clase_padre->opera(); print "<br>Soy el resultado de la funcion opera() aplicada al objeto de la clase extendida: "; print $Objeto_de_clase_extendida->opera(); print "<br>Esta es la ltima instruccin del script. Lo que leas de aqu en adelante "; print "ser obra de los destructores que se activarn al destruirse los dos objetos<br>"; ?>
ejemplo304.php

Bibliotecas de clases
Una de las ventajas ms importantes de las clases es la posibilidad de reutilizacin de sus scripts tanto si se trata de rutinas propias o de desarrollos de terceros. Bastara con disponer del fichero que contiene la clase correspondiente conocer sus mtodos pblicos (los nicos accesibles de la forma que lo hemos hecho en los ejemplos anteriores) y utilizarlos con la sintaxis que hemos venido usando en los ejemplos anteriores. Existen algunos sitios en la red en los que pueden obtener una gran cantidad de materiales de este tipo. Uno de los ms populares puedes encontrarlo en la direccin: phpclasses.org. Adems existen otros sitios dnde se pueden obtener algunas clases muy interesantes. Cuando tratemos lo relativo a ficheros en formato PDF veremos el enorme abanico de posibilidades que nos ofrece la clase TCPDF. Por el momento, para intentar ilustrar un poco la utilizacin de clases de terceros, incluimos un ejemplo que permite el envo de mensajes de correo con ficheros adjuntos (similares a los que hemos podido ver al tratar el tema de mensajes de correo) utilizando la clase phpmailer. Pese a que el enlace de descarga incluye abundante material y documentacin solo hemos extraido de l los dos ficheros que necesitamos para el ejemplo: class.phpmailer.php y class.smtp.php que podemos utilizar de la siguiente forma:

<?php /* evito con esta opcin init_set evitamos queaparezca un mensaje de advertencia relativo a una funcin utilizada en la clase y que est deprecated */

ini_set('display_errors','Off'); /* incluimos el fichero que contiene la clase llamada PHPMailer */ require("class.phpmailer.php"); /* creamos un nuevo objeto (mi_mensaje) instanciando la clase PHPMailer*/ $mi_mensaje = new PHPMailer(); $mi_mensaje->IsSMTP(); // este metodo publico especifica el tipo de servidor a utilizar (SMTP) /* asignamos valores a una serie de propiedades (variables) de la clase */ $mi_mensaje->Host = "127.0.0.1"; //modificamos la propiedad Host asignandole la IP del servidor $mi_mensaje->From = "juan@mispruebas.as"; // Correo del remitente asignado a al propiedad From $mi_mensaje->FromName = "Juan Mis Pruebas"; // nombre del remitente a la propiedad FromName $mi_mensaje->AddAddress("perico@mispruebas.as", "Perico Mis Pruebas"); // un destinatario $mi_mensaje->AddAddress("andres@mispruebas.as"); // otro destinatario el nombre es opcional $mi_mensaje->AddReplyTo("juan@mispruebas.as", "Juan Mis Pruebas"); //direccin de respuesta $mi_mensaje->WordWrap = 50; // longitud de la lnea del mensaje $mi_mensaje->Subject = "Prueba con adjuntos usando la clase phpmailer"; //Asunto $mi_mensaje->Body = "Este es un mensaje de prueba con ficheros adjuntos que usa la clase phpmailer"; //cuerpo $mi_mensaje->AltBody = "Este es un mensaje de prueba con ficheros adjuntos que usa la clase phpmailer"; //cuerpo cuando no utiliza HTML /* aplicamos al objeto los mtodos (funciones) de la clase necesarios para nuestro propsito */ $mi_mensaje->IsHTML(true); // enviar mensaje con formato html $mi_mensaje->AddAttachment("apachito.zip"); // aadir adjunto $mi_mensaje->AddAttachment("casa08.jpg", "leocadio.jpg"); // adjunto con nombre /* aplicamos al objeto el mtodo Send y comprobamos si tod se ha realizado correctamente */ if(!$mi_mensaje->Send()){ echo "El mensaje no ha podido enviarse. <br />"; echo "Error al enviar el mensaje: " . $mi_mensaje->ErrorInfo; exit; }else{ echo "El mensaje ha sido enviado"; } ?> Cuidado! No olvides que para ejecutar este script es imprescindible que tengas activo tu servidor de correo.

Como habrs podido ver, la nica dificultad que nos plantea el uso de esta clase es conocer los mtodos y propiedades que incluye y la utilidad de los mismos. Ese tipo de informacin suele venir incluida como comentarios dentro de la propia clase y/o en la documentacin relativa a la misma.

Uso de la clase phpmailer mediante el SMTP de gmail


Para enviar mensajes de correo externos utilizando el SMTP de Gmail slo es necesario disponer de una cuenta de usuario en Gmail y agregar o sustituir en el script del ejemplo anterior lo siguiente: $mi_mensaje->Host = 'ssl://smtp.gmail.com'; $mi_mensaje->Port = 465;

$mi_mensaje->SMTPAuth = true; $mi_mensaje->Username = 'direccion_completa_de_la_cuenta_de_gmail'; $mi_mensaje->Password = 'contrasea_de_la_cuenta_de_gmail'; $mi_mensaje->From = 'direccion_completa_de_la_cuenta_de_gmail';

Como es obvio, adems de tener en marcha el servidor Apache en modo local es preciso que nuestro equipo disponga de acceso a Internet.

Clases y objetos (II) Constantes. Variables y mtodos estticos


En la pgina anterior slo hemos visto una parte de las opciones de definicin y uso de clases y objetos. Intentaremos ampliar un poco ms aquellos conceptos.

Constantes
Uno de los elementos no imprescindibles que puede contener una clase son las constantes. Para definirlas debemos escribir: const nombre = valor

dnde const es una palabra reservada que establece la condicin de constante, nombre es el nombre de la propia constante (no va precedido de $) y valor el nmero o cadena alfanumrica asignada a esa constante.

Variables estticas y mtodos estticos


Las propiedades que hemos estudiado en la pgina anterior son conocidas como propiedades y tambin como variables de objeto. Sin embargo pueden definirse otro tipo de variables conocidas como variables de clase, variables estticas o simplemente estticas. Se caracterizan por ser inherentes a la propia clase pudiendo existir y ser utilizadas sin necesidad de instanciar ningn objeto. Es decir, no forman parte de los objetos. A modo de ejemplo podramos decir que entre las propiedades de una perforada puede estar la de hacer funciones de cascanueces y que para hacer uso de esta propiedad (partir una nuez) no se requiere de ninguno de los objetos especficos (hojas de papel o cualquier otro objeto susceptible de ser perforado) para los que fu diseada la perforada (la clase). Son ese tipo de propiedades inherentes a la propia clase y que no requieren de un objeto para ser utilizadas las conocidas comoestticas. Para definirlas basta anteponer al nombre de la propiedad la palabra reservada static. La sintaxis podra ser as: static nombre = valor

La condicin de esttica de una propiedad no es incompatible con la gestin de su visibilidad. Es perfectamente factible utilizar variables definidas como: public static, private static reserved static. Por una cuestin de compatibilidad con PHP4 en los casos en los que solo se indique static tendr la consideracin de public static. Aqu tienes algunos ejemplos de definiciones vlidas: public static $pepe="Jose" static $lola="Dolores" private static $rosa="Rosa"

Por lo que respecta a mtodos estticos (tampoco requieren definir un objeto para poder utilizarlos) la sintaxis es similar a la anterior.

Acceso a constantes y a variables y mtodos estticos


Las variables estticas, las constantes y los mtodos definidos como estticos tienen la peculiaridad de que pueden ser utilizadossin necesidad de haber creado o instanciado ningn objeto. Para acceder a ellos se usa, en vez del tradicional ->, el operador :: conocido como doble dos puntos, operador de resolucin de mbito o Paamayim Nekudotayim Para acceder a este tipo de variables y/o constantes sin instanciar un objeto debemos utilizar la siguiente sintaxis: $variable1= nombreClase::constante

recoge en $variable1 el valor de la constante establecida en la clase nombreClase. Los caracteres (::) son obligatorios y reservados. $variable2= nombreClase::$variable_estatica

recoge en $variable2 el valor de la $variable_estatica correspondiente a la clase nombreClase. Los caracteres (::) son obligatorios y reservados. El nombre de la variable, a diferencia de lo que ocurre con variables no estticas, debe ir precedido del carcter $. $variable3= nombreClase::metodo_estatico()

recoge en $variable3 el resultado de la ejecucin del netodo_estatico() correspondiente a la clase nombreClase. Los caracteres (::) son obligatorios y reservados. El parntesis puede incluir eventuales valores de los argumentos de la funcin. Si lo que pretendemos es acceder a la variables o mtodos estticos a partir de una instancia de objeto perteneciente a su clase utilizaremos la sintaxis: $objeto :: constante , $objeto :: variable_estatica o $objeto :: metodo_estatico()

y en el caso de ejercer esta opcin desde un mtodo de la propia clase lo haramos con la misma sintaxis pero sustituyendo $objetopor el pseudobjeto $this. Cuando el acceso a constantes, variables o mtodos estticos se produce desde un mtodo de la propia clase puede sustituirsenombreClase por la palabra reservada self (yo mismo). Obsrvalo en los ejemplos. Este primero gestiona nicamente constantes y elementos estticos.

<?php class MiClase { /* definimos constantes */ const cadena1="Soy una cadena"; const cadena2=1.234; /* aqui usamos sintaxis de documento incrustado */ const cadena3=<<<'cde' Soy una cadena incluida dentro de una constante mediante la sintaxis de documento incrustado. Esta sintaxis funciona siempre que la versin de PHP sea superior a 5.3 cde; /* definimos una variable esttica */ public static $estatica=<<<'fdg' Soy una variable esttica y soy pblica. Tanto yo como las constantes podemos ser visualizadas sin necesidad de crear un objeto. Utilizando :: puede vrseme sin problemas. fdg; /* incluyamos dos funciones definidas como estticas */

public static function mi_estatica($a,$b){ return pow($a, $b)*self::cadena2- MiClase::otra_estatica($a,$b); } public static function otra_estatica($a=3,$b=2){ return pow($b, $a) + MiClase::cadena2; } } /* he escrito la clase pero no voy a crear ningn objeto. Visualizo los elementos y ejecutar los mtodos estticos */ print MiClase::cadena1."<br />"; print MiClase::cadena2."<br />"; print MiClase::cadena3."<br />"; print MiClase::$estatica."<br />"; print MiClase::mi_estatica(6,5)."<br />"; print MiClase::otra_estatica()."<br />"; ?>
ejemplo306.php

Cuidado! La sintaxis de documento inscrutado no funciona en versiones de PHP inferiores a la 5.3. Ocurre lo mismo con $objeto :: constante , $objeto :: variable_estatica o $objeto :: metodo_estatico() que en versiones inferiores han de ser sutituidos por: Nombre_de_la_Clase::constante , Nombre_de_la_Clase::variable_estatica oNombre_de_la_Clase::metodo_estatic o()

En este otro ejemplo estamos mezclando llamadas a variables y mtodos estticos junto con otros que lo no son. Todos tienen en comn la condicin de visibilidad pblica.

<?php /* definimos una clase */ class MiPagina { /* establecemos los valores de las constantes y las variables cuidando que todas estas sean publica */ const cabeza1="<html><head><title>"; static $titulo="Probando clases y objetos"; const cabeza2="</title></head><body bgcolor='"; public $color='yellow'; const cabeza3="'>"; public $cuerpo=<<<'CUERPO' Las clases en PHP permiten la sintaxis de <b>documento incrustado</b> solo a partir de la versin 5.3.<br /> En esta pgina utilizamos constantes y propiedades de tipo <b>public</b> (las estticas siempre lo son). Por esa razn son accesibles desde cualquier lugar.<br /> Modificaremos el <i>color de fondo</i> y el <i>ttulo</i>. CUERPO; public $pie="</body></html>"; /* en este caso la clase no incluye ningn mtodo */ } /* creamos un nuevo objeto instanciando esta clase */ $MiObjeto= new MiPagina; /* modificamos el color y el ttulo. Observa la diferente forma en que tratamos las variables estticas */ $MiObjeto->color='Coral'; /* cambiamos el valor de la variable esttica $titulo;

MiPagina::$titulo='Ha cambiado el titulo de esta pagina'; /* visualizamos los diferentes elementos (constantes, variables y variables estticas aplicando la sintaxis adecaduada a cada caso) */ print $MiObjeto::cabeza1; print $MiObjeto::$titulo; print $MiObjeto::cabeza2; print $MiObjeto->color; print $MiObjeto::cabeza3; print $MiObjeto->cuerpo; print $MiObjeto->pie; ?>
ejemplo307.php

Aqu tienes un tercer ejemplo en el se utilizan distintos tipos de visibilidades


ejemplo308.php Ver cdigo fuente

Mtodos y/o propiedades con el mismo nombre en clases extendidas


Cuando una clase incluye un mtodo o propiedad cuyo nombre coincide con el de otro mtodo o propiedad de una de sus clases extendidas los objetos utilizarn los mtodos o propiedades de la clase que ha sido instanciada para crearlos. Esta situacin, conocida bajo el nombre de polimorfismo (varias formas de un mismo mtodo) es algo muy habitual en la programacin orientada a objetos. Hay que tener en cuenta que cuando se trata de constantes, variables estticas o mtodos estticos que no requieren un objeto puede accederse indistintamente a los de una u otra clase por medio de la siguiente sintaxis: nombre_de_clase:: constante, variable o mtodo pudiendo tambin reemplazarse el nombre_de_clase por un objeto de esa misma clase. La cuestin es: puede accederse desde un objeto de una clase extendida a un mtodo de la clase padre cuano se da una coincidencia de nombres?. La respuesta es s. Una posibilidad es utilizar esta sintaxis: nombre_de_la_clase_padre :: nombre_del_metodo()

dnde se ejecutara el mtodo nombre_del_metodo() de la forma en que est definido en la clase nombre_de_la_clase_padre. Otra forma de hacerlo sera dotar a la clase extendida de un mtodo similar a este: function intermediaria () { return parent::metodo(); }

de esta forma la funcin intermediaria devolver (return) el resultado de ejecutar el mtodo de la clase padre (parent). Observa en el ejemplo los resultados las diferentes opciones.

<?php /* creamos las clases A, B extendida de A */ class A { /* habr en la clase extendida otra constante con const CONSTANTE=3.141592; /* Hay otra variable esttica con el mismo nombre public static $estatica="Soy la variable publica /* Hay otra variable publica con el mismo nombre public $variable=" Soy publica y de la clase A";

el mismo nombre CONSTANTE*/ (estatica) en la clase B */ esttica de la clase A"; (variable) en la clase B */

/* incluimos un contructor en la clase padre */ function __construct(){ print "<br><b>Se instanci un objeto de la clase A.</b> <br>"; } /* Hay otro metodo esttico con el mismo nombre (estatico )en la clase B */ public static function estatico(){ return "Me enva el mtodo esttico de la clase A (padre)"; } /* Hay otro metodo con el mismo nombre (metodo)en la clase B */ public static function metodo(){ return "Me llamo mtodo y soy de la clase A (padre)"; } } class B extends A{ /* Hay otra constante con el mismo nombre CONSTANTE en la clase A (padre)*/ const CONSTANTE=6.28; /* Hay otra variable esttica con el mismo nombre (estatica) en la clase A (padre)*/ public static $estatica="Soy una variable publica esttica de la clase B"; /* Hay otra variable publica con el mismo nombre (variable) en la clase A (padre) */ public $variable=" Soy publica y de la clase B"; /* incluimos un contructor en la clase extendida */ function __construct(){ print "<br><b>Se instanci un objeto de la clase B</b><br>"; } /* Hay otro metodo esttico con el mismo nombre (estatico )en la clase A (padre) */ public static function estatico(){ return "He surgido del mtodo esttico de la clase B"; } /* Hay otro metodo con el mismo nombre (metodo)en la clase A padre */ public static function metodo(){ return "Me llamo mtodo y soy de la clase B"; } /* Creo una funcion puente para poder acceder a mtodos de la clase padre que tienen un nombre coincidente con uno de de la extendida */ public static function puente(){ return parent::metodo(); } } /* creamos un objeto instanciando la clase A */ $objeto_clase_A= new A(); /* creamos un objeto instanciando la clase B */ $objeto_clase_B= new B(); print print print print print print print print print print "<br><br>LECTURA DE CONSTANTES<br>"; "<br>\$objeto_clase_A::CONSTANTE= ".$objeto_clase_A::CONSTANTE; "<br>\$objeto_clase_B::CONSTANTE= ".$objeto_clase_B::CONSTANTE; "<br>A::CONSTANTE= ".A::CONSTANTE; "<br>B::CONSTANTE= ".B::CONSTANTE; "<br><br>LECTURA DE VARIABLES ESTTICAS<br>"; "<br>\$objeto_clase_A::\$estatica= ".$objeto_clase_A::$estatica; "<br>\$objeto_clase_B::\$estatica= ".$objeto_clase_B::$estatica; "<br>A::\$estatica= ".A::$estatica; "<br>B::\$estatica= ".B::$estatica;

print "<br><br>LECTURA DE VARIABLES PUBLICAS<br>"; print "<br>\$objeto_clase_A->variable= ".$objeto_clase_A->variable; print "<br>\$objeto_clase_B->variable= ".$objeto_clase_B->variable; print "<br><br>EJECUCIN DE METODOS ESTATICOS<br>"; print "<br>\$objeto_clase_A::estatico()= ".$objeto_clase_A::estatico();

print "<br>\$objeto_clase_B::estatico()= ".$objeto_clase_B::estatico(); print "<br>A::estatico()= ".A::estatico(); print "<br>B::estatico()= ".B::estatico(); print print print print print clase print ?> "<br><br>EJECUCIN DE METODOS <br>"; "<br>\$objeto_clase_A->metodo()= ".$objeto_clase_A->metodo(); "<br>\$objeto_clase_B->metodo()= ".$objeto_clase_B->metodo(); "<br>A::metodo()= ".A::metodo(); "<br>Tambin podemos recurrir a la funcin puente para ejecutar el mtodo de la padre"; "<br>\$objeto_clase_B->puente()= ".$objeto_clase_B->puente();

ejemplo310.php

Funciones con clases y objetos


Existen tambin algunas funciones que pueden resultarte tiles a la hora de depurar los scripts en los que manejes clases y objetos. Son las siguientes: method_exists(objeto, nombre_funcion)

Comprueba si est definida la funcin nombre_funcion (entenderemos funcin y mtodo como sinnimos) en el objeto $objeto. Devuelve un valor booleano. Cierto (true) en el caso de que exista esa funcin o falso (false) en el caso de que no exista. get_class_vars(nombre_de_la_clase)

Crea un array asociativo cuyos ndices son los nombres de las propiedades de la clase nombre_de_la_clase y cuyos valores coinciden con los valores preasignados a cada una de esas propiedades. En este array solo se recogen las variables que han sidoinicializadas asignndoles un valor. get_class_methods(clase)

Devuelve un array conteniendo los valores de todos los mtodos (funciones) definidas en la clase. get_object_vars(objeto)

Devuelve las variables visibles (y sus valores) contenidas en el objeto.

Incluyendo clases desde ficheros externos


A lo largo de nuestros ejemplos hemos guardado muchas de las clases en ficheros independientes y posteriormente las hemos incluido en los script mediante las funciones include o require_once. No habra restriccin en cuanto al nombre a utilizar, sin embargo, resulta muy aconsejable fijar una metodologia simple y cmoda para hacerlo. Si establecemos la pauta de guardar siempre los ficheros que contienen una clase con el nombre de la propia clase (exactamente el nombre de la misma) seguido de una extensin que tambin vamos a mantener fija y que podra ser, por ejemplo, .class.php podemos hacer uso de una comodsima funcin (__autoload) que intentaremos concretar con el ejemplo y que comentamos en l. Hemos duplicado el fichero ejemplo299.php de la pgina anterior (aqu est su cdigo fuente) y lo hemos guardado comoMiClase.class.php porque MiClase es precisamente el nombre de la clase que contiene.

<?php

function __autoload($nombre_de_clase){ include $nombre_de_clase .'.class.php'; } /* esta funcion se encarga de que cada vez que sea instanciada una clase se cargue mediante include el fichero cuyo nombre coincide con el de la clase y cuya extensin es .class.php. De este modo ya podemos despreocuparnos de incluir clases. */ $objeto= new MiClase; /* se cargara la clase MiClase.class.php y se creara el objeto A partir de aqu comprobaremos los resultados de las diferentes funciones informativas visualizando sus resultados mediante print_r con lo cual estaremos en condiciones de visualizar de forma cmoda nombres de variables y/o mtodos y sus valores */ print "<br />Resultados de var_dump<br /><br /><pre>"; var_dump($objeto); print "</pre><br /><br />Resultados de print_r<br /><br /><pre>"; print_r($objeto); print "</pre><br /><br />Resultados de var_export<br /><br /><pre>"; var_export($objeto); print "</pre><br /><br />Resultados de get_object_vars<br /><br /><pre>"; print_r(get_object_vars($objeto)); print "</pre><br /><br />Resultados de get_class_methods<br /><br /><pre>"; print_r(get_class_methods($objeto)); print "</pre><br /><br />Resultados de get_class_vars<br /><br /><pre>"; print_r(get_class_vars('MiClase')); method_exists('MiClase','lee') ? print "<br>Existe el mtodo" : print "<br>No existe el mtodo"; method_exists('MiClase', 'calcula')? print "<br>Existe el mtodo" : print "<br>No existe el mtodo"; print "</pre>"; ?>
ejemplo309.php

Objetos nicos
La utilizacin de clases est ntimamente ligada a la creacin de objetos (en plural). Si pensamos en un centro de enseanza veremos que varias son las aulas, los profesores o los alumnos. Pero puede que nos planteemos que el centro como tal sea un objeto nico. Para aquellos casos en los que queramos impedir la creacin de ms de un objeto podra ser aplicable el procedimiento descrito en este ejemplo.

<?php /* escribiremos una clase cuyos nico objeto sea un centro educativo. Para poder utilizar la funcin __autoload el fichero tendr como nombre Centro.class.php que coincide con el nombre de la clase */ class Centro{ /* establecemos las propiedades con condicin de protegidas*/ protected $nombre="I.E.S. Las Pruebas y los Objetos"; //nombre del centro protected $identificador="Q337777777x"; //podra ser el N.I.F. protected $localidad="Fuentes de Narcea (Degaa)" protected $aulas=array(); // ser un array destinado a contener aulas (objetos de otra clase) /* insertamos un costructor con visibilidad protegida. As evitamos que pueda ser invocado desde fuera de la clase o de sus extendidas */ protected function __construct(){ print "Objeto creado satisfactoriamente<br>"; }

/* Agregamos una variable privada y estatica con valor nulo que solo ser visible desde la propia clase y no requerir un objeto para ser instanciada */ protected static $instancia; /* Incluimos un mtodo pblico y esttico con nombre Unico() que: Comprueba si la propiedad $instancia tiene valor. En caso de tenerlo nos da un mensaje de advertencia. Si no lo tiene crea un nuevo objeto de la clase actual. */ public static function Unico(){ if (!isset(self::$instancia)) { $objeto =__CLASS__; // __CLASS__ contiene el nombre de la clase actual self::$instancia = new $objeto; }else{ print "Ya existe un objeto Centro y ha de ser nico"; } return self::$instancia; //devuelve el objeto recien creado } } ?> <?php /* la funcion autoload nos permitir cargar la clase Centro que es la que se instanciar para crear el objeto */ function __autoload($clase){ include $clase.'.class.php'; } /* la sintaxis habitual \$objeto=mew Centro dara un mensaje de error ya que el mtodo __construct tiene el carcter de protected con lo cual se impide que puede ejecutarse desde esta opcin */ /* Lo nico visible de la clase Centro es el mtodo Unico. Dado que es un mtodo esttico habr que invocarlo con la sintaxis adecuada a su condicin */ Centro::Unico(); /* Al ser invocado por primera el mtodo Unico crea el objeto. */ Centro::Unico(); /* Cuando se invoca por segunda vez el mtodo Unico ya no puede crea el objeto y da el mensaje de advertencia. */ ?>
ejemplo311.php

Objetos mltiples
Aqu puedes ver el cdigo fuente de algunas clases que hemos creado y que utilizaremos para la creacin del mltiples objetos tal como puede verse en el ejemplo que hay a continuacin
Ver clase Centro Ver clase Aula Ver clase Alumnos Ver clase Profesores

<?php /* la funcion autoload nos evita problemas a la hora de incluir los ficheros que contienen las clases requeridas */ function __autoload($clase){ include $clase.'.class.php'; } /* creamos el objeto miCentro tal como se describe en los ejemplos anteriores */ $miCentro=Centro::Unico(); /* comprobemos el contenido del objeto */

print print print print

"<br>Estas son las propiedades del objeto miCentro<br>"; "<pre>"; var_dump($miCentro); "</pre>";

/* vamos a crear el objetos de la clase Aula si miras el cdigo fuente de la clase Aula.class.php vers que el contructor agrega el valor correspondiente al identificador de cada objeto por esa razn cuando instanciemos objetos Aula vamos a incluir como argumento el valor de ese identificador */ /* un array nos puede ser util para crear masivamente las aulas */ $nombre_aulas=array('1 A','2 C','4 F','3 B','1B A'); /* Leeremos este array e iremos creando nuevos objetos de la clase Aula incluyendo el identificador que requiere el constructor */ for ($i=0;$i<sizeof($nombre_aulas);$i++){ /* Haremos que los nuevos objetos sean elementos de un array escalar Para ello solo tenemos que agregar [] a misAulas y cada objeto creado pasar a ser un elemento de ese array */ $misAulas[]=new Aula($nombre_aulas[$i]); } /* comprobemos el contenido de los objetos */ print "<br>Comprobacin de los objetos misAulas<br>"; print "<pre>"; print var_dump($misAulas); print "</pre>"; /* con una estrategia similar podremos crear los objetos de la clase Alumnos Ahora al instanciar cada objeto incliremos su nombre y apellido */ /* estos son los datos para los objetos alumnos */ $nombre_alumnos=array('Ana','Benito','Carla','Dionisio','Esther', 'Fernando','Guiomar','Herminio','Isabel','Jenaro'); $apellidos_alumnos=array('Jimnez','Iglesias','Husillos','Gmez','Fernndez', 'Escapa','Daz','Casado','Blzquez','Alonso'); for ($i=0;$i<sizeof($nombre_alumnos);$i++){ $misAlumnos[]=new Alumnos($nombre_alumnos[$i],$apellidos_alumnos[$i]); } /* comprobemos el contenido de los nuevos objetos */ print "<br>Comprobacin de los objetos misAlumnos<br>"; print "<pre>"; print var_dump($misAlumnos); print "</pre>"; ?>
ejemplo313.php

La ejecucin de este script nos permite comprobar que efectivamente se han creado los objetos pretendidos pero tiene un par de deficiencias manifiestas. Los diferentes tipos de objetos carecen de relacin. Hemos creado un centro, aulas y alumnos pero no tienen relacin alguna. Sus clases son independientes entre s. Los alumnos podran ser de ese u otro centro y lo mismo podra ocurrir con las aulas. Un segundo problema es que una vez que finaliza la ejecucin del script los objetos se destruyen y se pierde toda la informacin relativa a ellos. Vamos a tratar de ver a continuacin como evitar esa prdida.

Serializacin de objetos
Toda la informacin relativa a un objeto puede se transformada en una cadena mediante la funcin:

serialize(nombre_del_objeto)

donde nombre_del_objeto indica el objeto que pretendemos serializar. Los resultados de la serializacin son susceptibles de ser guardados en un fichero. De esta forma (puedes verlo en el ejemplo) los objetos pueden estar disponibles para su uso posterior.

<?php /* para evitar reescribir incluimos el ejemplo anterior. Se ejecutar integramente */ include('ejemplo313.php'); /* visualizamos la serializacion de cada objeto */ print "<brEsta es la serializacin de misAlumnos<br>"; print serialize($misAlumnos); print "<brEsta es la serializacin de misAulas<br>"; print serialize($misAulas); print "<brEsta es la serializacin de misAulas<br>"; print serialize($miCentro); /* tambin podemos guardar cada objeto en una variable o en un array tal como hacemos en las instrucciones siguientes */ $serializado[] = serialize($misAlumnos); $serializado[] = serialize($misAulas); $serializado[] = serialize($miCentro); /* vamos a hacer una segunda serializacin. Serializaremos y guardaremos en una variable los contenidos del array resultante de la serializacin anterior */ $todo=serialize($serializado); /*guardaremos en un fichero (le ponemos como nombre Almacenado)la serializacin resultante */ file_put_contents('Almacenado', $todo); ?>
ejemplo314.php

Recuperacin de objetos serializados


Los objetos contenidos de las cadenas (o ficheros) que contienen el resultado de una o varias serializaciones pueden ser recuperados por medio de la funcin: $objeto_recuperado= unserialize($cadena_serializada)

donde $objeto_recuperado es el nombre que pretendemos asignar al objeto recuperado (no tiene por qu coincidir que el que tena en el momento de ser serializado) y $cadena_serializada una variable que contiene el resultado de la serializacin previa. Es necesario que estn disponibles las clases a las que pertenecen los objetos que pretendemos recuperar.

<?php /* la funcion autoload no va a incluir los ficheros con las clases necesarias */ function __autoload($clase){ include $clase.'.class.php'; } /* leemeos el fichero y recogemos su contenido en una variable */ $serializado = file_get_contents('Almacenado'); /* recuperamos la serializacin y visualizmos el contenido */ $todo_junto = unserialize($serializado); print "<pre>";var_dump($todo_junto);print "</pre>"; print "<br>Podemos leer el array mediante un bucle<br>"; for($i=0;$i<sizeof($todo_junto);$i++){

print "<pre>"; var_dump(unserialize($todo_junto[$i])); print "</pre>"; } ?>


ejemplo315.php

Objetos que contienen objetos


Las propiedades (variables) de los objetos pueden contener valores alfanumricos o numricos, arrays, objetos y tambin arrays cuyos elementos sean objetos. La forma de asignar valores a las propiedades puede tener alguna de las formas siguientes: $objeto -> propiedad=valor

es la forma ms sencilla. Se asigna un nuevo valor (numrico o alfanumrico) a la propiedad del $objeto. Como es lgico requiere la preexistencia del objeto. $objeto -> propiedad [ ] = valor

Se asigna un nuevo valor (numrico o alfanumrico) a la propiedad [] del $objeto . Como es lgico la propiedad habr sido definida como array escalar en su clase y el resultado sera un nuevo elemento cuyo ndice se conformara de forma automtica sumando una unidad al del ltimo existente. $objeto -> propiedad = $otro_objeto

se asigna $otro_objeto (objeto preexistente de otra clase) como valor de la propiedad del $objeto . $objeto -> propiedad [ ] = $otro_objeto

se asigna $otro_objeto (objeto preexistente de otra clase) como valor de la propiedad del $objeto . El hecho de la propiedad tenga forma de array significa que $otro_objeto ser el valor asignado a un nuevo elementos del array. $objeto -> propiedad[] =new clase_del_objeto_a_incluir()

tambin en este caso se asigna un objeto como valor de la propiedad del $objeto . La diferencia estriba en que el objeto aadido no existe previamente. Por esa razn se crea en el momento de la inclusin mediante new seguido de clase_del_objeto_a_incluir() con los eventuales argumentos que pudiera requerir el constructor de la nueva clase. $objeto -> propiedad [ ] =new clase_del_objeto_a_incluir()

su nica diferencia con el caso anterior es que ahora el nuevo objeto ser almacenado en un array. En estos enlaces puedes ver el cdigo fuente de las clases utilizadas en el ejemplo que se incluye a continuacin de ellos.
Ver clase Centro Ver clase Aula Ver clase Alumnos Ver clase Profesores

<?php /* la funcion autoload nos evita problemas a la hora de incluir los ficheros que contienen las clases requeridas */ function __autoload($clase){ include $clase.'.class.php';

} /*creamos un nuevo objeto asignndole valor al identificador al instanciar de la clase Aula Puedes visualizar el constructor desde enlace que hay aqui encima */ $miAula=new Aula('Primero B'); /* la propiedad profesor va a contener un objeto de la clase Profesores que crearemos incluyendo los argumentos que utiliza su constructor */ $miAula->profesor=new Profesores('Juan','Lpez','Matemticas'); /* agregamos un nuevo elemento al array materiales */ $miAula->materiales[]="Pizarra digital"; /* modificamos el nmero de puestos ecolares del aula */ $miAula->puestos=45; /* haremos una inclusin masiva de objetos de la clase Alumnos (tambin puedes ver en el enlace el cdigo fuente de esta clase) utilizamos como valores los nombres y apellidos contenidos en los array */ $nombre_alumnos=array('Ana','Benito','Carla','Dionisio','Esther','Fernando','Guiomar'); $apellidos_alumnos=array('Jimnez','Iglesias','Husillos','Gmez','Fernndez','Escapa','D az'); for ($i=0;$i<sizeof($nombre_alumnos);$i++){ /* la propiedad alumnos de la clase Aula es un array de ahi que incluyamos los nuevos objetos (Alumnos) en alumnos[] */ $miAula->alumnos[]=new Alumnos($nombre_alumnos[$i],$apellidos_alumnos[$i]); } /* Visualizamos el contenido de el objeto Aula que incluye otros objetos en sus propiedades */ print "<pre>"; print var_dump($miAula); print "</pre>"; ?>
ejemplo316.php

Manipulacin de objetos contenidos en objetos


En los ejemplos que incluimos a continuacin puedes ver, comentados, algos casos de manipulacin de objetos contenidos en otros objetos.

<?php class AulaExtendida extends Aula { function lista_profes(){ print $this->profesor->nombre; print $this->profesor->apellidos; } function lista_profes1(){ print $this->profesor->nombre; print $this->profesor->apellidos; print $this->profesor->materia; } function lista_alumnos(){ foreach ($this->alumnos as $indice=>$contenido){ print $contenido->nombre." ".$contenido->apellidos." ".$contenido>ruta."<br>"; } }

function modifica_alumnos($nom_act='',$ap_act='',$nom_nue='',$ap_nue='', $ruta_nue=''){ foreach ($this->alumnos as $ind=>$cont){ if($this->alumnos[$ind]->nombre==$nom_act && $this->alumnos[$ind]>apellidos==$ap_act){ if ($nom_nue !='')$this->alumnos[$ind]->nombre=$nom_nue; if ($ap_nue !='')$this->alumnos[$ind]->apellidos=$ap_nue; if ($ruta_nue !='')$this->alumnos[$ind]->ruta=$ruta_nue; } } } function borra_alumnos($nom_act='',$ap_act=''){ foreach ($this->alumnos as $ind=>$cont){ if($this->alumnos[$ind]->nombre==$nom_act && $this->alumnos[$ind]>apellidos==$ap_act){ unset($this->alumnos[$ind]); } } $this->alumnos=array_values($this->alumnos); } } /****** comienza una porcin de cdigo idntica a la del ejemplo anterior ******/ function __autoload($clase){ include $clase.'.class.php'; } $miAula=new AulaExtendida('Primero B'); //instanciamos la clase extendida para usar sus metodos $miAula->profesor=new Profesores('Juan','Lpez','Matemticas'); $miAula->materiales[]="Pizarra digital"; $miAula->puestos=45; $nombre_alumnos=array('Ana','Benito','Carla','Dionisio','Esther','Fernando','Guiomar'); $apellidos_alumnos=array('Jimnez','Iglesias','Husillos','Gmez','Fernndez','Escapa','D az'); for ($i=0;$i<sizeof($nombre_alumnos);$i++){ $miAula->alumnos[]=new Alumnos($nombre_alumnos[$i],$apellidos_alumnos[$i]); } /**** acaba el cdigo idntica a la del ejemplo anterior ****/ $miAula->lista_profes(); print "<br /><br />"; /* lista alumnos */ $miAula->lista_alumnos(); print "<br />"; /* modifica alumnos sin busqueda*/ $miAula->alumnos[2]->nombre="Heliodoro"; $miAula->alumnos[3]->apellidos="de los Ros"; /* modifica alumnos con busqueda*/ $miAula->modifica_alumnos('Ana','Jimnez','Mara Gertrudis','Cucaln',48); /* borra alumnos con bsqueda*/ $miAula->borra_alumnos('Benito','Iglesias'); $miAula->lista_alumnos(); print "<br />"; print "<pre>"; print var_dump($miAula); print "</pre>"; print "<br><br>"; foreach ($miAula->alumnos[1] as $propiedad=>$valor){

print $propiedad."....".$valor."<br>"; } print "<br><br>"; foreach ($miAula->alumnos as $indice=>$objeto){ foreach ($objeto as $propiedad=>$valor){ print $indice."...".$propiedad."....".$valor."<br>"; } } $miAula->lista_profes1(); ?>
ejemplo317.php

<?php function __autoload($clase){ include $clase.'.class.php'; } /* crearemos un objeto de la clase Aula */ $aula=new Aula('Aula Magna'); print "<br><i>El identificador del aula recien creada es</i>: ".$aula->identificador; /* creamos tres objetos de la clase Alumnos */ $alumno[0]=new Alumnos ('Juan Carlos', 'Rodriguez'); $alumno[1]=new Alumnos ('Feliciano','Perez'); $alumno[2]=new Alumnos ('Luisindo','Orcasitas'); print "<br /><br /><i>Los objetos del array alumnos son estos</i>: "; /* El primer bucle nos permite leer los elementos del array (objetos) y el segundo extrae el nombre de la propiedad y su valor */ foreach ($alumno as $indice=>$objeto){ print "<br>".$indice." "; foreach ($objeto as $propiedad=>$valor){ print "<i>".$propiedad."</i>: ".$valor."; "; } } /* aadimos algunos objetos Alumnos a la propiedad alumnos de la clase Aula */ $aula->alumnos[]=$alumno[0]; $aula->alumnos[]=$alumno[1]; /* incluimos un nuevo objeto en el array alumnos de la clase Aula */ $aula->alumnos[]=new Alumnos ('Sindulfo','Yebra'); /* copiamos el objeto recien creado en un nuevo objeto */ $alumno[3]=$aula->alumnos[2]; print "<br /><br /><i>Los objetos de la propiedad alumnos de la clase Aula son estos</i>: "; foreach ($aula->alumnos as $indice=>$objeto){ print "<br>".$indice." "; foreach ($objeto as $propiedad=>$valor){ print "<i>".$propiedad."</i>: ".$valor."; "; } } /* modificamos nombres de alumnos tanto en el array alumnos como en los objetos aula>alumnos */ $aula->alumnos[0]->nombre="Tcito Petronio"; $alumno[1]->nombre="Francisca Maria"; $alumno[3]->nombre="Iigo Francisco"; print "<br><br><br>La modificacin se produce en ambos lugares<br><br>"; print "<br /><br /><i>Los objetos del array alumnos despus de los cambios son</i>: "; foreach ($alumno as $indice=>$objeto){ print "<br>".$indice." "; foreach ($objeto as $propiedad=>$valor){ print "<i>".$propiedad."</i>: ".$valor."; "; }

} print "<br><br><i>En la clase Aula vemos esto despus de los cambios:</i>: "; foreach ($aula->alumnos as $indice=>$objeto){ print "<br>".$indice." "; foreach ($objeto as $propiedad=>$valor){ print "<i>".$propiedad."</i>: ".$valor."; "; } } /* eliminaremos algunos objetos. En un caso lo haremos en los de clase Aula y en otros en el array alumno */ unset($aula->alumnos[0]); unset($alumno[1]); unset($aula->alumnos[2]); print "<br><br><br>Despus de destruir objetos.<br>"; print "<br>Tcito e Iigo en el objeto de la Clase Aula"; print "<br>Francisca en el objeto alumnos"; print "<br><br><i>Los objetos del array alumno despus de eliminar foreach ($alumno as $indice=>$objeto){ print "<br>".$indice." "; foreach ($objeto as $propiedad=>$valor){ print "<i>".$propiedad."</i>: ".$valor."; "; } } son</i>: ";

print "<br /><br /><i>Los objetos de la clase Aula despus de eliminar son estos</i>: "; foreach ($aula->alumnos as $indice=>$objeto){ print "<br>".$indice." "; foreach ($objeto as $propiedad=>$valor){ print "<i>".$propiedad."</i>: ".$valor."; "; } } ?>
ejemplo318.php

Clases y objetos (III) Sobrecargas de propiedades


Al hablar de la privacidad decamos que las propiedades privadas y protegidas nicamente son accesibles desde funciones incluidas en la propia clase (o en una clase extendida si es protected). Eso significara que opciones del tipo print $objeto>propiedad o $objeto->propiedad=valor solo funcionaran en el caso de que la propiedad tuviera condicin de pblica. En esas situaciones la solucin para acceder a las propiedades no visibles (private y protected) sera agregar dentro de la propia clase algo como esto: ...... public function lee_privado($propiedad){ return $this->propiedad } ......

que hara de intermediario y que mediante algo similar a: print $objeto->lee_privado(propiedad) nos permitira conocer el valor de tal propiedad. Mediante procedimientos similares podramos modificar valores, eliminar propiedades o comprobar su existencia.

Para simplificar este proceso disponemos de palabras reservadas que permiten que determinadas funciones se ejecuten, si estn incluidas en la propia clase, de forma automtica. Enumeraremos el comportamiento de algunas de ellas. public function __get($propiedad) { return $this->$propiedad; }

cuando incluimos una funcin idntica a esta en una clase (es imprescindible que tenga la condicin de public y que el nombre de la funcin sea __get) podemos despreocuparnos de si una propiedad es public o tiene la condicin de private, protected. En el momento que intentamos conocer el valor de una propiedad del objeto escribiendo: $objeto->propiedad se ejecutar (si es necesario) de forma automtica esa funcin y nos devolver el valor requerido. public function __set($propiedad,$valor) { $this->$propiedad=$valor; }

Una funcin idntica a esta (tambin es imprescindible la condicin de public y que el nombre de la funcin sea __set) nos permite asignar un valor a cualquier propiedad del objeto independientemente de que su condicin sea public, private o protected. En el momento que intentamos asignar un valor escribiendo: $objeto->propiedad=valor se ejecutar (si es necesario) de forma automtica esa funcin y asignar a la propiedad el valor indicado. public function __unset($propiedad) { unset ($this->$propiedad); }

Eliminar la propiedad cuando escribamos: unset ($objeto->propiedad) ejecutndose de forma automtica, cuando sea necesario, la funcin __unset. public function __isset($propiedad) { return isset($this->$propiedad); }

Devolver TRUE o FALSE (dependiendo de que exista o no exista la propiedad) cuando escribamos: isset($objeto>propiedad). En el ejemplo puedes ver el funcionamiento de estos mtodos incluso en los casos en los que los valores de las propiedades sean arrays u objetos.

<?php /* esta clase tiene como una finalidad la creacin de un objeto para pruebas lo nico que hace cuando es instanciada es asignar valores a las propiedades publicas a y b.*/ class ObjetoAuxiliar{ public $a; public $b; function __construct($a=7,$b=14){ $this->a=$a; $this->b=$b; } } /* esta nueva clase es la que usaremos para nuestras pruebas */ class Pruebas { protected $propiedad1="13"; protected $matriz=array('Uno','Dos','Tres'); protected $objeto; function __construct(){ $this->objeto=new ObjetoAuxiliar; }

/* esta funcion mgica __get nos permitir ver desde fuera de la propia clase los contenidos de sus propiedades protegidas y privadas */ public function __get($variable){ return $this->$variable; } /* esta funcion mgica __get nos permitir, desde fuera de la propia clase, asignar valores a sus propiedades protegidas y privadas */ public function __set($propiedad,$valor){ $this->$propiedad=$valor; } /* esta funcion mgica __unset nos permitir, desde fuera de la propia clase, eliminar propiedades protegidas y privadas */ public function __unset($propiedad){ print "Eliminando: ".$propiedad."<br />"; unset($this->$propiedad); } /* esta funcion mgica __isset nos permitir, desde fuera de la propia clase, comprobar si est definidan propiedades protegidas y privadas */ public function __isset($propiedad){ return isset($this->$propiedad); } } /* creamos un nuevo objeto de la clase pruebas */ $miObjeto=new Pruebas(); /* la propiedad1 es protected. Eso significa que solo se visualizara desde una funcin de la propia clase o de una de sus extendidas. Cuando al invocarla resulta no ser accesible PHP comprueba si est definido el mtodo __get en la clase. Si lo est lo ejecuta de forma automtica considerando la propiedad1 como parmetro de la funcin __get. Dado que esa funcin pertenece a la propia clase si puede leer la propiedad y devolver el resultado */ print $miObjeto->propiedad1."<br>"; /* comprobamos que __get funciona tanto cuando la propiedad contiene un array como cuando se trata de un objeto. */ print_r($miObjeto->matriz)."<br>"; print_r($miObjeto->objeto)."<br>"; /* comprobemos ahora la funcin mgica __set. Se comporta identica a la anterior con la diferencia de que ahora recoge como parmetros el nombre de la propiedad y el valor que se pretende asignar */ $miObjeto->propiedad1=7456; print $miObjeto->propiedad1."<br>"; $miObjeto->matriz=array(7,4,5,6); print_r($miObjeto->matriz)."<br>"; $miObjeto->objeto= new ObjetoAuxiliar(25,987); print_r($miObjeto->objeto)."<br>"; /* comprobamos que se pueden borrar propiedades con los tres tipos de valores */ unset($miObjeto->propiedad1); unset($miObjeto->matriz); unset($miObjeto->objeto); /* comprobamos la existencia de la propiedad utilizando de forma idntica a los casos anteriores la funcin mgica __isset */ if (isset($miObjeto->propiedad1)){ print "La propiedad1 si existe"; }else{ print "La propiedad1 no existe"; } ?>

ejemplo319.php

Cuidado! Presta atencin a la sintaxis de las funciones que hemos descrito. Observa que hemos utilizado $this>$propiedadcuando lo habitual en las funciones sera $this->propiedad. Si omitimos el $ nos dar error.

Clases y mtodos abstractos


Quiz nos sea de utilidad detenernos en un caso de la vida cotidiana. Pensemos en una ITV. Los inspectores han de seguir un protocolo que consiste en verificar el funcionamiento de: carroceria, gases, bocina, luces, suspensin, frenos, direccin, etctera, de cadavehculo y, posteriormente, emitir y firmar un documento acreditativo de los resultados de tal inspeccin. Este protocolo contiene (o puede contener) instrucciones precisas para emitir y firmar los documentos (se sigue el mismo procedimiento sea cual sea el tipo de vehculo). Nos encontramos ante dos situaciones distintas: especificaciones concretas (mtodos) para la burocracia y especificaciones abstractas para la parte tcnica. Nadie nos ha dicho an como inspeccionar una direccin o unas luces. Este protocolo inicial podramos entenderlo como una clase abstracta con mtodos abstractos. El inspector necesita con carcter imprescindible mtodos concretos para los diferentes tipos de vehculos. Si se trata de una motocicleta el mtodo de inspeccin ser radicalmente distinto al de un turismo y el de este ser tambin distinto al de un autobs. As pues, habr de contar como mtodos de comprobacin de cada uno de los elementos para cada una de las clases de vehculo. En nuestro argotdiramos que son necesarias clases extendidas: motocicleta, turismo y autobs, y adems, cada una de esas clases ha de disponer de mtodos para todas y cada una de las verificaciones: carroceria, gases, etctera. Dicho de otra forma: es imprescindible redefinir cada uno de los mtodos abstractos para cada una de las clases extendidas. Algo muy similar ocurre con la Programacin Orientada a Objetos.

Clases y mtodos abstractos


Para definir un mtodo como la condicin de abstracto hemos de utilizar la siguiente sintaxis: abstract protected function nombre_del_metodo () dnde la palabra reservada abstract especifica su condicin de abstracto, protected establece el carcter protegido del mismo y adems, con caracter imprescidible, la function nombre_del_metodo () ha de estar declarada pero no definida (observa que faltan las {} y el habitual contenido de ellas que realmente es lo que define el mtodo o funcin). Otra cuestin sumamente importante. Para que una clase pueda incluir un mtodo abstracto tambin ella ha de tener la condicin de abstracta. Es decir, no podemos definir un mtodo como abstracto sin que la clase que lo contiene lo sea. Para definir como abstracta una clase hemos de hacer utilizar la siguiente sintaxis: abstract class nombre_de_la_clase

una clase definida como abstracta puede no contener mtodos abstractos y propiedades con cualquier tipo de visibilidad. Por el contrario, un mtodo abstracto solo puede ser incluido en una clase abstracta.

Restricciones de las clases y mtodos abstractos


El uso de clases abstractas requiere tener muy presentes las siguientes cuestiones: Las clases abstractas no pueden ser instanciadas para crear objetos Los mtodos no abstractos y/o las propiedades de una clase abstracta slo son accesibles desde sus clases extendidas. Estonos obliga a definir clases extendidas. Los mtodos abstractos de una clase (abstracta) han de ser obligatoriamente redefinidos en todas sus clases extendidas. Cuando se redefine un mtodo abstracto en una clase extendida ha de hacerse con una condicin de visibilidad igual o ms permisiva a la que se estableci en la clase abstracta. Si un mtodo abstracto tiene condicin de protected slo puede ser redefinido como public (ms permisivo) o protected (igual de permisivo)

<?php

/*creamos una clase abstracta en la que incluimos mtodos tanto abstractos como no abstractos, variables y constantes. Los mtodo abstractos solo se declaran pero no se define lo que deben hacer cuando sean invocados */ abstract class Figuras{ /*incluimos los mtodos abstractos */ abstract protected function calculaArea(); abstract protected function calculaPerimetro(); /* los restantes metodos, propiedades y constantes de la clase */ const PI=3.141592; protected $tipo; public function Imprime($a,$b){ print "La ".$this->tipo." cuyos radios son: ". $a." y ".$b."<br />"; print "El area es:".$this->calculaArea($a,$b)."<br />"; print "El permetro es:".$this->calculaPerimetro($a,$b)."<br />"; } } /* las clases abstractas no pueden ser instanciadas para crear objetos. Por tanto es imprescindible una clase extendida */ class Redondas extends Figuras{ public function calculaArea($radio1=0,$radio2=''){ if ($radio2=='') $radio2=$radio1; return self::PI*$radio1*$radio2; } public function calculaPerimetro($radio1=0,$radio2=''){ if ($radio2==''){ $radio2=$radio1; return self::PI*2*$radio1; }else{ return self::PI*(3*($radio1+$radio2)sqrt((3*$radio1+$radio2)*($radio1+3*$radio2))); } } } /* instanciamos un objeto de la clase extendida (la abstracta no lo permitiria)*/ $circulo= new Redondas(); /* desde este objeto ya se puede llamar a mtodos de cualquiera de las clases */ $circulo->Imprime (5,5); ?>
ejemplo320.php

Interfaces
Las interfaces tienen un cierto paralelismo con las clases y mtodos abstractos pero ni su sintaxis ni su comportamiento son iguales. Podemos decir que una interface es un declaracin o lista de mtodos publicos no definidos que han de incluirse (y definirse) con carcter obligatorio en todas las clases que implementen esa interface. Desde una perspectiva utilitarista podramos entenderlas como una lista de obligaciones y tareas obligatorias (mtodos que han de incluirse en una clase) que imposibilitar el olvido ya que de no realizarse todas (omitir algn mtodo establecido en la interface) las instancias de la clase producirn un error. En una interface solo pueden incluirse mtodos (funciones) con visibilidad public y constantes.

Sintaxis de las interfaces

Para declarar una interface es necesario una sintaxis como esta: interface nombre_de_la_interface { public function nombre_de_una_funcion (argumento1, argumento2,...) public function nombre_de_otra_funcion (argumento1, argumento2,...) ....... const nombre = valor (opcional) }

Para utilizar interface es necesario una sintaxis como esta: class nombre_de_la_clase implements nombre_de_una_interface, nombre_de_otra_interface { /*TODOS los mtodos de nombre_de_una_interface */ public function nombre_de_una_funcion (argumento1, argumento2,...){ .......(cdigo del mtodo) ......... ................ } public function nombre_de_otra_funcion (argumento1, argumento2,...){ .......(cdigo del mtodo) ......... ................ } /* TODOS los mtodos de nombre_de_otra_interface */ ................ ................ }

Restricciones de las interfaces y sus clases


Cuando una clase usa ms de una interface hay que cuidar que estas no contengan mtodos con el mismo nombre. De darse esa circunstancia se producira un error. Hay que definir en la clase todos los mtodos de todas las interfaces que impelenta. Las constantes definidas en una interface se utilizan exactamente igual que las constantes de clase. Su nica particularidad es que que no pueden ser sobrescritas por una clase/interfaz extendidas.

<?php /* creamos una interface que solo puede contener mtodos publicos no definidos y constantes */ interface Figuras{ public function calculaArea(); public function calculaPerimetro(); const PI=3.141592; } /* una nueva interface que en este caso no incluye ninguna constante */ interface Cuerpos{ public function calculaVolumen(); } /* definimos una clase que implementa las dos interfaces (Figuras y Cuerpos) ello le obliga a definir todas las funciones declaradas en ambas clases Si hubiera dos funciones con el mismo nombre se producira una ambiguedad que generara un error */ class Redondas implements Figuras, Cuerpos{ public $tipo; public function calculaArea($radio1=0,$radio2=''){

if ($radio2=='') $radio2=$radio1; return $this::PI*$radio1*$radio2; } public function calculaPerimetro($radio1=0,$radio2=''){ if ($radio2==''){ $radio2=$radio1; return self::PI*2*$radio1; }else{ return self::PI*(3*($radio1+$radio2)sqrt((3*$radio1+$radio2)*($radio1+3*$radio2))); } } public function calculaVolumen($radio1=0,$radio2=''){ if ($radio2=='') { $radio2=$radio1; return 4/3*self::PI*pow($radio1,3); }else{ return 4/3*self::PI*$radio1*pow($radio2,2); } } } /* instanciamos objetos pertenecientes a la clase de la forma habitual. La constante PI definida en el interface es asumida como propia por la clase */ $circulo= new Redondas(); print "El area de la figura es: ". $circulo->calculaArea(5,5) ."<br>"; print "El perimetro de la figura es: ". $circulo->calculaPerimetro(5,5) ."<br>"; print "El volumen del cuerpo es: ". $circulo->calculaVolumen(5,5) ."<br>"; ?>
ejemplo321.php

Mtodos que manejan objetos o arrays


Los mtodos definidos en una clase pueden manejar objetos de la propia clase o de otra. Esta ltima posibilidad requiere disponer de un objeto de cada una de las dos clases y, adems, que en una de ellas se incluyan mtodos con esta sintaxis: function nombre_del_metodo ( Otra_Clase, $objeto_cualquier_nombre , $argumento1, $argumento2,...) { $objeto_cualquier_nombre->propiedad $objeto_cualquier_nombre->metodo ( $argumento1, $argumento2,...) } La utilizacin de estos mtodos requiere haber creado previamente un objeto de cada una de las clases que vamos a llamar$Objeto_Base y $Objeto_Externo. Con estas premisas la ejecucin de un mtodo requerira esta sintaxis: $Objeto_Base->nombre_del_metodo ($Objeto_Externo, argumento1, argumento2) los nombres corresponden a los anteriormente descritos y los argumentos incluidos en la llamada se corresponden con los eventualmente requeridos por el mtodo referenciado en la que hemos llamado Otra_Clase tal como puedes ver en este ejemplo. Tambin es posible pasar arrays a los mtodos de una clase y manejar sus contenidos mediante funciones incluidas en el mtodo. Para ello se requiere la siguiente sintaxis: function nombre_del_metodo ( array, $variable) { ......... funciones php que manejan el array $variable

......... }

dnde array es una palabra reservada que especifica la condicin de tal de lo recogido por $variable. El mtodo debe ser invocado de la forma siguiente: $objeto -> nombre_del_metodo( array('elemento1','elemento2',...) ) o, como es lgico $matriz = array('elemento1','elemento2',...); $objeto -> nombre_del_metodo ( $matriz )

<?php /* definimos una clase que llamaremos externa (ser la auxiliar) que incluye mtodos aritmticos. La funcion suma puede recibir valores como argumentos y, en caso de recibirnos modificar las propiedades de sumando1 y sumando 2 */ class Externa { public $sumando1=1; public $sumando2=2; function if ($a if ($b return } Suma($a='',$b=''){ !='') $this->sumando1=$a; !='') $this->sumando2=$b; $this->sumando1+$this->sumando2;

function Resta(){ return $this->sumando1-$this->sumando2; } function Multiplica(){ return $this->sumando1*$this->sumando2; } function Divide(){ return $this->sumando1/$this->sumando2; } } /* definiremos ahora una nueva clase (que ser la Base de nuestro ejemplo) con la peculiaridad de que sus mtodos hacen referencia a otra clase y a objetos de esa otra clase. En todos los mtodos de esta clase (con una excepcin que comentaremos) se incluyen como parmetros el nombre de la clase auxiliar (Externa), una variable que recibir los objetos de la clase Externa y los eventuales argumentos requeridos por la funcin que en el caso de la suma son dos */ class Base { function adicion (Externa $exterior, $a='',$b='') { /* este mtodo pasar el objeto exterior (recibido en la llamada) junto con los valores de las variables a y b. Devolver el resultado de ejecutar el mtodo Suma (de la clase externa) sobre el objeto exterior tambin de la clase externa */ return $exterior->Suma($a,$b); } function sustracion (Externa $exterior) { return $exterior->Resta(); }

function multiplicacion (Externa $exterior) { return $exterior->Multiplica(); } function division (Externa $exterior) { return $exterior->Divide(); } function cambia_a (Externa $exterior, $a) { return $exterior->sumando1=$a; } /* en este caso el objeto recibido en la peticin es una instancia de la propia clase Base y se le aplicar un mtodo (neperiano) definido en esta misma clase. */ function lee_logaritmo (Base $exterior,$a) { return $exterior->neperiano($a); } /* el mtodo neperiano que ser instanciados por anterior */ function neperiano($a){ return log($a); } /* esta funcin recibe como argumento un array que ser recogido por la funcin en la variable la_matriz y tratado como tal. Requiere obligatoriamente la palabra reservada array en la misma posicin que en las funciones anteriores incluyen el nombre de la clase a la que pertenece el objeto. Ahora podra decirse que el array la_matriz es un objeto de la clase array */ function lee_matriz (array $la_matriz){ print "El array tiene: ".sizeof ($la_matriz)." elementos<br>"; foreach ($la_matriz as $indice=>$valor){ print $indice." * ".$valor."<br>"; } } } /*manejo de las clases anteriores */ /* Creamos un objeto de cada de las dos clases */ $Objeto_Externo = new Externa; $Objeto_Base = new Base; /* el objeto base ejecuta sus mtodos incluyendo como argumentos el identificado del objeto externo junto con los eventuales argumentos*/ print "La suma es: ". $Objeto_Base->adicion($Objeto_Externo)."<br />"; print "La suma con parmetros es: ". $Objeto_Base->adicion($Objeto_Externo,25,89)."<br />"; print print print print />"; "Los valores pasados a la funcin producirn una modificacin "; "en los valores de las propiedades sumando1 y sumando 2 del Objeto_externo. "; " Esas nuevos valores se mantendrn en tanto no vuelvan a ser modificados.<br>"; "La suma con un parmetro es: ". $Objeto_Base->adicion($Objeto_Externo,749)."<br

print "La suma con un parmetro es: ". $Objeto_Base>adicion($Objeto_Externo,'',125)."<br />"; print "La diferencia es: ".$Objeto_Base->sustracion($Objeto_Externo)."<br />";

print "El producto es: ".$Objeto_Base->multiplicacion($Objeto_Externo)."<br />"; print "El cociente es: ".$Objeto_Base->division($Objeto_Externo)."<br />"; print "El nuevo valor de a: ".$Objeto_Base->cambia_a($Objeto_Externo,1013)."<br />"; print "La suma es: ". $Objeto_Base->adicion($Objeto_Externo)."<br />"; print "El logaritmo neperiano de 10 es: ". $Objeto_Base>lee_logaritmo($Objeto_Base,10)."<br />"; print "Probando un array<br> "; print $Objeto_Base->lee_matriz(array(13,27,128,945,'pepe'))."<br>"; ?>
ejemplo322.php

Crear ficheros PDF Creacin de ficheros PDF


Exiten varias opciones para la creacin mediante funciones PHP de ficheros en formato PDF. El abanico de posibilidades se extiende desde las aplicaciones de pago tales como PDFlib hasta las clases open source tales como FPDF o TCPDF, que amplia las prestaciones de la anterior y que ser la que utilizaremos para desarrollar los contenidos de este tema.

La clase TCPDF
La clase TCPDF est en constante evolucin. Por ello se van produciendo, con mucha frecuencia, continuas actualizaciones, correcciones de errores y mejoras. Las versiones ms recientes pueden encontrarse en este enlace. Hemos descargado desdehttp://www.tcpdf.org el fichero tcpdf_5_9_088.zip (la ltima versin disponible en el momento de elaborar estos materiales) y lo hemos descomprimido en nuestro directorio php. Durante la descompresin se cre de forma automtica un directorio llamado tcpdf en el que se incluyeron una serie de subdirectorios tales como: config, examples y fonts y una serie de ficheros entre los que podremos encontrar el denominado tcpdf.php que es el que realmente contiene la clase. La creacin de ficheros PDF mediante la clase TCPDF requiere que en los scripts se incluyan los ficheros: tcpdf.php, tcpdf_config.phpy spa.php que corresponden a la clase propiamente dicha, a su configuracin y al idioma en uso. Tales ficheros se encuentran en los directorios: tcpdf y en sus subdirectorios tcpdf/config y tcpdf/config/lang. Para mayor comodidad en el manejo hemos creado un fichero llamado tcpdf.inc.php que sirve para realizar la inclusin de los tres anteriores. Puedes ver aqu su contenido. Si los ficheros estuvieran en directorios distintos de los indicados habran de adecuarse las rutas absolutas incluidas en el ficherotcpdf.inc.php.

El constructor de la clase TCPDF


La clase incluida en el fichero tcpdf.php tiene por nombre TCPDF. Por tanto su uso requerir adems del necesarioinclude('tcpdf.inc.php') la creacin de un objeto mediante la sintaxis: $objeto= new TCPDF();

Al instanciar un nuevo objeto se ejecuta siempre el constructor (recuerda que un constructor es una mtodo con nombre __constructque se ejecuta de forma automtica el momento en que es creado un nuevo objeto) que en esta clase permite seis argumentos: orientacion,unidad de medida, formato, unicode, codificacin y diskcach. Por tanto, al instanciar la clase para crear el nuevo objeto podramos escribir:

$objeto= new TCPDF( orientacion, unidad_de_medida, formato, unicode, codificacion, disckcache );

dnde: orientacion admite dos valores: 'P' (normal Portrait) y 'L' (apaisado Landscape en denominacin inglesa). El valor por defecto es 'P' (normal). unidad_de_medida permite especificar las dimensiones del documento en: 'in' (pulgadas), 'pt' (puntos), 'mm' (milmetros) y tambin 'cm' (centmetros). El valor por defecto es 'mm'' (milmetros). Recuerda que una pulgada equivale a 25,4 milmetros y queun punto equivale a 1/72 pulgadas (0,35277 mm.). formato permite especificar las dimensiones de cada pgina del documento mediante las convenciones de los formatos ISO 216 serie A desde 'A0' (841x1189 mm) hasta 'A12'; la serie B de ISO 216 desde 'B0' (1000x1414 mm) hasta 'B12' y la serie C de las misma norma desde 'C0' (917x1297 mm) hasta 'C12'. El valor por defecto es 'A4' (297x210 mm). unicode es un parmetro booleano (true o false) que permite indicar si los textos que se incluirn en el documento tendrn formato UNICODE o no. Por defecto su valor es TRUE codificacin permite indicar el formato de codificacin de los textos incluidos en el documento. Por defecto su valor es 'UTF-8'. diskcach es otro parmetro booleano que permite configurar el uso de la memoria RAM. Si est configurado como TRUE se utilizar menos memoria RAM almacenando los datos temporales en cach. El ahorro de memoria puede ralentizar fuertemente el proceso. El valor por defecto de este parmetro es false. Una vez creado el objeto es necesario aadirle una o ms pginas. Para ello se utiliza el mtodo AddPage. Su sintaxis ms simple es la siguiente: $objeto->AddPage()

Formatos a medida
La clase TCPDF tambin permite especificar formatos a medida. Para ello hemos definir las dimensiones deseadas mediante la sintaxis: $medidas=array(ancho,alto)

dnde ancho y alto son las dimensiones deseadas (especificadas en la unidad establecida para el documento) e incluir este array ($medidas) como valor del parmetro formato en la llamada al constructor de la clase.

El mtodo Output()
La clase TCPDF incluye la funcin Output que permite visualizar o guardar el objeto creado. Mediante la sintaxis: $obj->Output(nombre,destino)

puede asignarse cualquier nombre, con o sin extensin, al objeto generado. Cuando no se especifica el nombre, se le asigna por defecto el valor doc.pdf. El parmetro destino puede tener uno o varios de los siguientes valores: 'I' Permite visualizar el fichero directamente en el navegador si el plugin si est disponible. La opcin Guardar como... asignara, por defecto, el nombre especificado en el parmetro nombre. 'D' Enva el fichero al navegador mostrando la ventana de opcin que permite elegir entre Abrir o Descargar. Si se elige esta ltima, guardar el fichero con el nombre especificado en el parmetro nombre. 'F' Guarda el fichero en el directorio actual del servidor con el nombre asignado en la opcin nombre.

El mtodo SetDisplayMode()

Este mtodo slo afecta a la forma en la se visualiza el documento en la pantalla del cliente permite configurar dos parmetros:tamao y forma de visualizacin. $obj->SetDisplayMode( tamao,visualizacion)

El tamao (no se refiere al documento impreso sino a la visualizacin en pantalla) permite una de estas opciones: fullpage (el zoom del visor se adapta de modo que encaje la pgina completa en la pantalla); fullwidth (ajusta el zoom de forma que se visualize el documento ajustando el ancho al de la pantalla); real (ajusta el zoom del visor al 100%) default que usa el modo por defecto del visor. La forma de visualizacin permite, entre otras, las opciones: single muestras las pginas separadas de una en una; continuous va mostrndolas una detrs de otra de forma continua; two muestras dos columnas (con dos pginas) simultaneamente, y default que, como en el caso anterior, usa el modo por defecto del visor.

Algunsos ejemplos
Como primer ejemplo crearemos un fichero con dos pginas en blanco.

<?php # incluimos todos los ficheros requeridos # tal como lo hemos recogido en el fichero tcpdf.inc.php # creado tal como se indica al margen include("tcpdf.inc.php"); # creamos un nuevo objeto (MiPDF) utilizando la clase FPDF $MiPDF=new TCPDF(); # creamos una pgina en blanco $MiPDF->Addpage(); # creamos una segunda pgina en blanco $MiPDF->Addpage(); # visualizamos el documento $MiPDF->Output(); ?>
ejemplo323.php

Si observas con detalle el pdf del ejemplo anterior observars que en la parte superior de las pginas aparece una extraa lnea horizontal. Se debe a que, por defecto, esta clase incluye en cada documento un encabezado y un pie de pgina. La forma de evitarlo ser desactivar esa opcin incluyendo en el script llamadas a los mtodos setPrintHeader(false) y setPrintFooter(false) con el valor booleanofalse tal como puedes ver en este otro ejemplo.
ejemplo324.php Ver cdigo fuente

En este ejemplo establecemos dimensiones, unidades de medida y orientacin del documento. Comprobaremos que podemos cambiar la orientacin (de normal a apaisada o viceversa) de cada una las pginas del documento.

<?php # incluimos todos los ficheros requeridos # tal como lo hemos recogido en el fichero tcpdf.inc.php # creado tal como se indica al margen include("tcpdf.inc.php"); /* vamos a configurar el documento como apaisado (P), utilizando las pulgadas como unidad de medida y unas dimensiones "no estandar" de 10 x 20 pulgadas */ # creamos un array con las dimensiones (ancho y alto); $dimensiones=array (10,20); # creamos un nuevo objeto (MiPDF) utilizando la clase FPDF

# incluyendo en este caso los valores a utilizar por el constructor $MiPDF=new TCPDF('P','in',$dimensiones); # creamos una pgina en blanco con las indicaciones del constructor $MiPDF->Addpage(); #Incluimos una segunda pgina cambiando la orientacin # un cambio de orientacin respecto a la inicial $MiPDF->Addpage('L'); # creamos una segunda pgina en blanco # en la que, al no incluir el parmetro de orientacin # utilizar el valor utilizado en la anterior $MiPDF->Addpage(); # visualizamos el documento $MiPDF->Output(); ?>
ejemplo325.php

Otros mtodos de la clase TCPDF


Aunque no tienen excesiva utilidad prctica, vamos a comentar someramente aqu -tambin los incluimos en el ejemploalgunos de los mtodos, de carcter bsicamente informativo, que incluye la clase FPDF. SetAuthor("nombre del autor"). Permite incluir una cadena con el nombre del autor. SetCreator("nombre de la aplicacin"). Permite incluir una cadena con el nombre del programa utilizado para crear el documento. SetTitle("ttulo del documento"). Permite incluir una cadena con el ttulo del documento. SetKeywords("palabras clave"). Permite incluir una cadena con una lista de palabras clave separadas por espacios. SetSubject(tema) Permite incluir una cadena de texto explicativa de los temas tratados en el contenido del documento Los datos incluidos en el documento mediante los mtodos anteriores no son presentados diractamente en el documento. Slo son visualizables cuando se exploran los metadatos del documento.

<?php # incluimos la clase fpdf que est en este mismo directorio include("tcpdf.inc.php"); /* vamos a configurar el documento como apaisado (P), utilizando los milmetros como unidad de medida y unas dimensiones "no estandar" de 140 x 200 milimetros */ # creamos un array con las dimensiones (ancho y alto); $dimensiones=array (140,200); # creamos un nuevo objeto (MiPDF) utilizando la clase TCPDF # incluyendo en este caso los valores a utilizar por el constructor $MiPDF=new TCPDF('P','mm',$dimensiones); #desactivamos encabezado y pie de pgina $MiPDF->setPrintHeader(false); $MiPDF->setPrintFooter(false); # el mtodo SetAuthor nos permite incluir el nombre del autor $MiPDF->SetAuthor('Pepe Prez'); # el mtodo SetCreator nos permite incluir el nombre de la # aplicacion que genera el pdf $MiPDF->SetCreator('clase TCPDF'); # el mtodo SetTitle nos permite incluir un ttulo $MiPDF->SetTitle('Pruebas del pdf'); # el mtodo SetKeywords nos permite incluir palabras claves # separadas por espacios y dentro de una misma cadena $MiPDF->SetKeywords('palabra1 palabra2'); # el mtodo SetDisplayMode nos permite incluir palabras claves # separadas por espacios y dentro de una misma cadena

$MiPDF->SetDisplayMode('fullpage','two'); # creamos una pgina en blanco. Incluimos, para esta primera pgina # un cambio de orientacin respecto a la inicial $MiPDF->Addpage('L'); # creamos una segunda pgina en blanco # en la que, al no incluir el parmetro de orientacin # utilizar el valor usado en el ltimo Addpage que ha sido L. $MiPDF->Addpage(); /* insertamos unas nuevas dimensiones */ $dimension2=array(97,234); /* las dimensiones anteriores pero invirtiendo el orden */ $dimension3=array(234,97); /* insertamos pginas con la misma orientacin pero utilizando cada uno de los dos arrays anteriores. Veremos que las pginas que se visualizan tienen igual tamao y orientacin. Es decir, no importa el orden en que incluyamos las dimensiones ya que ser la orientacin establecida la situe esas medidas */ $MiPDF->Addpage('L',$dimension2); $MiPDF->Addpage('L',$dimension3); # visualizamos el documento $MiPDF->Output('donpepito.pdf','I'); ?>
Los ejemplos siguientes son similares. La nica modificacin que contienen respecto al cdigo fuente anterior es la correspondiente al segundo parmetro (destino) del mtodo Output.
Destino="I" Destino="D" Destino="F"

Textos en PDF Fijacin de mrgenes


Algunas funciones de insercin de textos permiten colocar los mismos dentro de lo que podra llamarse caja de texto que no es otra cosa que la superficie de la pgina delimitada por los mrgenes de la misma. Por defecto, estos mrgenes miden 15 milmetros, por laizquierda y por la derecha del documento y 27 y 25 milmetros por la parte superior e inferior del mismo. As mismo, tambin por defecto, se establecen mrgenes para encabezado y pie de pgina de 5 y 10 milmetros respectivamente. Los valores de esta configuracin por defecto estn contenidos en constantes del fichero tcpdf_config.php. Si editamos este fichero y modificamos los valores asignado mediante la funcin define a las constantes cuyo nombre comienza por PDF_MARGIN_ (seguido de left,top, etctera) podremos adecuar a nuestras necesidades los valores de esos parmetros. Tambin podemos hacer esas modificaciones (nicamente para el documento actual) por medio del mtodo siguiente: $objeto->SetMargins(izquierdo,superior,derecho )

dnde los parmetros izquierdo, superior y derecho son los valores numricos que permiten establecer, por este orden y en la unidad de medida que se indique en el constructor, los mrgenes del documento. Si se omite el tercer parmetro (derecho) se le asignar el valor que se haya indicado para el izquierdo. Cuando se trata de establecer mrgenes entre textos y bordes de celdas contenedoras (lo veremos en los mtodos Cell y Multicell) puede utilizarse el mtodo: $objeto->SetCellPaddings( izquierda, superior, derecha, inferior)

donde izquierda, superior, derecha e inferior son, por este orden, las distancias entre texto y borde de la celda contenedora.

Si lo que pretendemos es establecer o modificar las distancias entre bordes de celdas contiguas utilizaremos el mtodo: $objeto->SetCellMargins( izquierda, superior, derecha, inferior)

donde izquierda, superior, derecha e inferior son, por este orden, las distancias entre dos celdas contiguas.

Margen inferior y salto de pgina


Por medio del mtodo: $objeto->SetAutoPageBreak( automatico, margen_inferior )

donde automatico es un valor booleano (1 0 ) que permite activar o desactivar el salto de pgina automtico. Cuando est activotrue o 1 se van aadiendo nuevas pginas, de forma automtica, hasta que se incluya la totalidad del texto especificado. En el caso de estar desactivado false o 0, los textos que excedieran los lmites de la pgina no se visualizaran, ya que no se aadira una nueva pgina. Por defecto est opcin est configurada como true. El segundo parmetro, el valor margen_inferior, permite especificar el margen inferior mnimo de la pgina. Su valor numrico deber indicarse en las unidades establecidas por el constructor. Si no se indica asumir cero con margen por defecto.

Tipo de letra, estilo, tamao y colores de texto y fondo


La eleccin del tipo de letra puede haceres mediante la funcin: $objeto->SetFont ( nombre,estilo,tamao)

donde nombre es una cadena que debe indicar el nombre del tipo de letra (helvetica, times, zapfdingbats, courier y symbol son las fuentes incluidas en la distribucin). Puedes verlas desde este enlace. El parmetro estilo puede especificarse mediante la cadena vaca ("") para el tipo normal o mediante 'B', 'I', 'U' (negrita, cursiva,subrayada) o sus combinaciones. Por ejemplo, 'BU' indicar negrita subrayada. Las fuentes de smbolos slo permiten el estilo normal. Por medio del parmetro tamao se especifica el tamao de la letra expresado en puntos. Si no se especifica otra cosa los valores por defecto son: helvetica normal de 12 puntos. $objeto->SetFontSize( numero )

Permite modificar unicamente el tamao de la fuente en uso asignndole en adelante el valor en puntos especificado en numero. $objeto->setFontSpacing ( numero )

Permite modificar en la cantidad especificada en numero la distancia entre caracteres. Por defecto su valor es 0. $objeto->setFontStretching ( numero )

Permite estrechar la fuente al porcentaje indicado en numero. Por defecto su valor es 100. $objeto->SetTextColor ( rojo,verde ,azul )

Establece el color del texto mediante los valores numricos comprendidos entre 0 y 255 representan las respectivas componentes de los colores primarios rojo, verde y azul.

$objeto->SetTextColor ( negro )

En este caso, el valor numrico negro, tambin comprendido entre 0 y 255, establece colores de la escala de grises desde el negro (cero) hasta el blanco (255). Si no se especifica un color los textos aparecern en negro. Una vez establecido un color su valor se mantiente hasta que no sea invocada nuevamente la funcin SetTextColor para su modificacin. Una forma alternativa de utilizar los colores es la de definir un color mediante el mtodo: $objeto->AddSpotColor( nombre, cyan,magenta, amarillo, negro )

permite asignar mediante una cadena cualquiera un nombre a un color (por ejemplo: micolor) y los valores cyan, magenta, amarillo ynegro son los valores porcentuales de cada una de las tintas en la composicin del color. Siempre que se les asignen nombres distintos podrn definirse cuantos colores sean necesarios. El uso de los colores anteriores para la impresin de textos requiere el mtodo: $objeto->SetTextSpotColor ( nombre, porcentaje)

donde nombre es el nombre de un color previamente creado mediante AddSpotColor y porcentaje representa el tanto por ciento de opacidad de esa tinta (100 la hara absolutamente opaca y 0 la convertira en totalmente transparente). Cuando se trata de asignar un color de fondo (fill) para textos, celdas o dibujos se utiliza una de estas opciones: $objeto->SetFillColor ( rojo, verde, azul) $objeto->SetFillColor ( negro) $objeto->SetFillSpotColor ( nombre, porcentaje )

cuyo comportamiento es idntico al descrito para el caso de colores de texto.

Posicin actual
La clase TCPDF dispone de mtodos que permiten determinar el valor actual de las coordenadas del punto de insercin (lugar donde se va a posicionar el texto, imagen o elemento grfico que se incluya) y tambin modificar el valor actual de esos puntos. Son las siguientes: $objeto->GetX() y $objeto->GetY()

permiten conocer los valores de la posiciones actuales, horizontal (X) y vertical (Y), del punto de insercin. El resultado estar expresado en las unidades establecidas por el constructor considerando como origen de coordenadas la esquina superior izquierda del documento y valores positivos horizontal y vertical los colocados a la derecha (X) y debajo (Y) del origen. Para establecer una nuevo punto de insercin se pueden usar cualquiera de estas funciones: $objeto->SetX(valor X) $objeto->SetY(valor Y) $objeto->SetXY(valor X, valor Y)

mediante las cuales estableceremos sus coordenadas: horizontal, vertical o ambas. Cuando el valor de X (en el caso SetX) es negativo se considera con referencia al margen derecho de la pgina. De igual modo, cuando se asigna un valor negativo en SetY se considera respecto a la parte inferior de la pgina.

Nmeros de pgina
La numeracin de las pginas de los documentos es factible ya que TCPDF dispone de mtodos especficos para ello. $objeto->getAliasNumPage()

Este mtodo devuelve una cadena que contiene el nmero de la pgina actual. $objeto->getAliasNbPage()()

Complementario al anterior, este mtodo devuelve el nmero total de pginas del documento.

Saltos de lnea
Mediante $objeto->Ln (medida) se ejecuta un salto de lnea. La posicin actual regresa al margen izquierdo y la vertical se desplaza en el nmero de unidades indicado en el parmetro medida.

Estilos de lnea
Cuando se trata de establecer estilos de lnea podemos recurrir a alguna de las siguientes funciones: $objeto->SetDrawColor rojo, verde, azul ) o $objeto->SetDrawColor ( negro )

permiten establecer el color de las lneas (bordes de celdas y otros elementos grficos)siguiendo el mismo criterio ya comentado para rellenos y textos. $objeto->SetDrawSpotColor ( nombre)

Igual que ocurra para textos y rellenos permite asignar a la lneas un color cuyo nombre debe haber sido definido previamente por medio de AddSpotColor. $objeto->SetLineWidth ( espesor )

Permite establece el espesor de las lneas mediante un nmero que puede un nmero decimal que debe interpretarse expresado en las unidades de medida en uso en la pgina. $objeto->SetLineStyle( $array )

Establece el estilo de una lnea segn los datos contenidos en un $array asociativo cuyos elementos son los siguientes: $array['widht']=numero Este elemento del array permite establecer el espesor de la lnea. Es una opcin alternativa a SetLineWidth $array['join']=['miter'|'round'|'bevel'] Admite uno de los tres valores indicados: miter (inglete), round (redondeado) o bevel (bisel) y establece la forma en la que se perfilarn los extremos de los trazos de las lneas discontinuas. $array['cap']=['but'|'round'|'square']. Admite uno de los tres valores indicados: but (inglete), round (redondeado) o square (cuadrado) y establece la forma en la que se dibujarn las uniones de las lneas en las esquinas del rectngulo de la celda. $array['dash']="cadena" Permite establecer el tipo de trazos que formarn la lnea. Si se indica 0 dibujar una lnea continua. Si se especificara algo como 20,10 lo que representara sera una lnea discontinua formada por trazos de color de 20 unidades de longitud seguidos de espacio en blanco de 10 unidades. Si este parmetro fuera "20,10,8,6,5,8" lo que representara sera: un trazo de 20 unidades seguido de un espacio de 10, despus ira un trazo de 8 unidades seguido de un espacio de 6 y, a continuacin, un nuevo trazo de 5 y un nuevo espacio de 8 repitindose la secuencia completa cuantas veces fuera necesario para efectuar el trazado completo.

$array['phase']= numero Permite especificar mediante un numero entero por cual de los valores indicados en dash comienza el trazado de la lnea. $array['color']=array(cyan,magenta,amarilo,negro) Permite incluir un array escalar que contenga los valores cyan, magenta,amarillo,negro que componen el color de la lnea. Esta opcin es alternativa al uso de SetDrawColor y/o SetDrawSpotColor>. En el ejemplo330 tienes algunas muestras de como definir estilos de lnea.

Inclusn de textos en el documento


El mtodo Write
La inclusin de textos multilnea puede hacerse utilizando el mtodo: $objeto-> Write ($interlinea, $texto, $enlace="", $fondo=false, $alineacion="", $nueva_linea=false)

dnde los parmetros tienen la utilidad descrita en la tabla siguiente.


Parmetro Valores Utilidad Permite establecer la interlnea del texto. Cuando se establecen valores inferiores a la separacin mnima entre renglones desoye el mandato y estable la interlnea mnima. Cadena o variable conteniendo el texto que debe incluirse mediante el mtodo Write. Es aconsejable tomar la cautela de comprobar que la codificacin del texto utiliza la misma codificacin establecida por el constructor del objeto. El texto puede extraerse de un fichero externo mediante una funcin que permita su lectura. Tal es el caso delfile_get_contents('nombre_del_fichero_externo') Permite incluir una cadena con una direccin URI. El texto se comportara como un hiperenlace Cuando este parmetro est como true el texto aparece sobre un color de fondo (puede establecerse medianteSetFillColor (negro por defecto). Establece la forma de alineacin (izquierda, centrada, derecha o justificada) del texto respecto a la caja de texto del documento. Para que los Write consecutivos cambien de alineacin hay que producir un salto de lnea. Puede hacerse mediante el parmetro $nueva_linea Cuando se establece como true el cursor se sita en la lnea a la del ltimo texto incluido. En caso contrario (false) se mantiene en la misma lnea.

$interlinea $texto $enlace $fondo $alineacion $nueva_linea

nmero cadena cadena booleano L, C, R o J booleano

ejemplo329.php

Ver cdigo fuente

Insercin de celdas con una sola lnea de texto


La forma ms simple de insercin de textos bien como elementos individuales (por ejemplo ttulos de una sola lnea) o tablas formadas por celdas que contengan una sola lnea de texto es la que utiliza el mtodo: $objeto->Cell ($ancho, $alto=0, $texto="", $borde=0, $salto_de_linea=0, $alineacion="", $fondo=false, $enlace="", $ajuste_horizontal=0, $ignore_min_height=false, $alin_vertical_texto='T', $alineacion_vertical='M')

que imprime un rea rectangular, con fondo y bordes opcionales y que puede contener una cadena de texto que puede alinearse respecto a los bordes de la celda. La esquina superior izquierda de la celda se sita en la posicin actual del punto de insercin. Despus de ser invocado este mtodo el punto de insercin puede desplazarse a la derecha o a la lnea siguiente. El texto puede ser utilizado con un hiperenlace y, adems, puede expandirse en tamao o en espaciado para ajustarse a las dimensiones de la celda. Los parmetro que utiliza esta funcin, cuyos valores por defecto puedes ver detrs del nombre de cada uno de ellos, son los que comentamos en la tabla siguiente.
Parmetro Valores Utilidad Ancho de la celda expresado unidad de medida establecida en la llamada al constructor TCPDF. Si es cero se extiende desde el punto de insercin hasta el margen derecho de la pgina

$ancho

nmero

$alto $texto

nmero cadena 0 1

Alto mnimo de la celda expresado en la unidad de medida establecida en la llamada al constructor. La altura de la celda se ajustar al texto contenido en ella. Si se estable altura cero la celda se adaptar a las dimensiones de su contenido Cadena o variable conteniendo el texto que debe incluirse mediante el mtodo Cell. Es aconsejable tomar la cautela de comprobar que la codificacin del texto utiliza la misma codificacin establecida por el constructor del objeto. La celda se visualizar sin bordes Pertime visualizar la celda con un borde del color y ancho especificados por los mtodos SetDrawColor ySetLineWidth o por las opciones poder defecto de estos (negro de 1 unidad de espesor) Esta cadena que permite, siempre que se mantenga el orden, elegir todas o varias de las letras indicadas sirve para establecer por qu parte de la de la celda se aadirn bordes. L alude a la izquierda, T a la parte superior, R a la derecha y B a la parte inferior. Por ejemplo: 'TB' dibujara bordes por la parte superior e inferior de la celda, 'LB' los pondra por la izquierda y por debajo Y 'LRB' pondra bordes por todas partes excepto por la parte inferior. Cuando no se especifica este valor o se especifica 0 (valor por defecto) se establece que el punto de insercin, despus de la llamada a este mtodo, se sita justamente en el borde derecho de la celda. Mediante esta opcin, la celda siguiente que se incluya se situar en el margen izquierdo de la pgina y debajo de la fila actual. Cuando se indica este valor, la prxima celda que se incluya aparecer debajo de la actual y alineada al borde izquierdo de esta. Establece la forma de alineacin (izquierda, centrada, derecha o justificada) del texto respecto a la celda

$borde 'LTRB' 0 $salto_de_linea 1 2 $alineacion $fondo $enlace

L, C, R o J contenedora. booleano cadena 0 1 2 3 4

Cuando este parmetro est como true la caja contenedora aparece un color de fondo (puede establecerse mediante SetFillColor (negro por defecto). Permite incluir una cadena con una direccin URI. El texto se comportara como un hiperenlace No realiza ningn ajuste del texto que puede desbordar el espacio delimitado por el recuadro contenedor Se producir, slo si es necesario un estrechamiento del texto hasta lograr que quepa en el recuadro contenedor. Reducir o expandir el ancho del texto para ajustarlo a las dimensiones del recuadro contenedor Reducir la separacin entre caracteres (sin alterar el ancho de la tipografa) si resulta necesario para que quepa el texto en el marco contenedor Aumenta o reduce la separacin entre caracteres para ajustar el texto al marco contenedor Cuando la altura asignada a la celda es demasiado pequea para contener el texto con la fuente establecida si este parmetro est como false (0) la altura de la celda se ajustar para contener el texto. Si esta opcin est configurada como true (1) se respetar la altura de la celda y el texto aparecer fuera de los bordes de esta.l El borde superior del contenedor se alinear con el valor de la ordenada especificada en el parmetro y El borde superior de las letras se alinear con el valor de la ordenada especificada en el parmetro y La lnea base de las letras se alinear con el valor de la ordenada especificada en el parmetro y El borde inferior del contenedor se alinear con el valor de la ordenada especificada en el parmetro y El texto se alinea verticalmente a la parte superior del contenedor El texto se alinea verticalmente al centro del contenedor El texto se alinea verticalmente al borde inferior del contenedor

$ajuste_horizontal

$ignore _min_ height

booleano

T A $alin_vertical_texto L B T $alineacion_vertical C B

El punto de insercin de cada una de las celdas se establece de la forma siguiente: El resultante de la ejecucin anterior de otro mtodo de la clase. Si va precedido de una llamada al mtodo AddPage se situar en el vrtice superior izquierdo de la caja de texto (despus de aplicar los mrgenes) de la pgina. Si va precedido de una llamada al mtodo Ln se situar en el margen izquierdo de esa nueva lnea. Si va precedido de SetXY se situar en los coordenadas establecidas por este mtodo. Si va precedido de una llamada anterior al mtodo Cell se situar en la posicin condicionada por el valor del parmetro Lnincluido en aquella llamada.
ejemplo330.php Ver cdigo fuente

Cuidado! Segn las prestaciones del equipo que estemos utilizando y la complejidad de PDF que tratemos de generar puede aparecernos el mensaje de error: Fatal error: Maximum execution time of 30 seconds exceeded. Esto se debe a se ha sobresado el tiempo mximo por defecto. Hay dos maneras de evitar ese error. Una de ellas sera modificar ese tiempo en fichero php.ini. La segunda sera incluir en el encabezado del script la instruccinset_time_limit(segundos) dnde segundos el nuevo lmite de ejecucin que tendr nicamente validez para el documento actual.

Transformaciones en celdas
La clase TCPDF dispone de mtodos que permiten efectuar transformaciones grficas de algunos elementos entre los que se incluyen las celdas. Toda trasformacin comienza con una llamada al mtodo $objeto->StartTransform() y acaba con $objeto>StopTransform(). La estructura del cdigo podra ser similar a esta: $objeto->StartTransform() ... ... aplicacin de las funciones de transformacin obj->Cell(....) Incluir la celda que ser abjeto de transformacin $obj->StartTransform();

Este tipo de acciones requieren los mtodos siguientes: $objeto-> Rotate (angulo,x,y)

dnde el angulo de giro se expresa en grados sexagesimales y se mide en sentido trigonomtrico y los valores de x e y son las coordenadas del centro de giro. La transformacin producir un giro de la celda respecto a su centro de giro. o $objeto-> Rotate (angulo) o o $objeto-> Rotate (angulo, "","")

cuando no se especifica el centro de giro la transformacin producir un giro de la celda respecto a su vrtice superior izquierdo. Esta funcin es equivalente a utilizar en la anterior, las coordenadas actuales del punto de insercin como centro de giro.

Cuidado! Rotate(ang,"","") y Rotate(ang,0,0) producen resultados distintos. El primero considera como centro de giro las coordenadas actuales del punto de insercin y el segundo considera que ese centro est situado en la esquina superior izquierda de la pgina.
$objeto-> Translate (x, y)

produce una translacin de la celda desde el punto de insercin actual hasta otro punto situado x unidades a su derecha (izquierda si su valor es negativo) e y unidades hacia abajo (arriba si su valor es negativo). $objeto-> SkewX (angulo, x, y)

transforma la celda (rectangular) en un paralelogramo inclinando los lados verticales del rectngulo original en la medida indicada porang (tambin en grados sexagesimales y medido en sentido trigonmetrico) siendo el centro de la tranformacin el punto de coordenadasx,y. Si se omiten estos valores consider con centro el punto de insercin actual. $objeto-> SkewX (angulo, x, y)

transforma la celda (rectangular) de modo similar al anterior aunque ahora los lados que sufren el cambio de orientacin son los horizontales. $objeto-> ScaleX (porcentaje, x, y), $objeto-> ScaleY (porcentaje, x, y) y $objeto-> ScaleXY (porcentaje, x, y)

son tres opciones que permiten transformar la celda modificando sus dimensiones horizontales, verticales ambas y sus contenidos en el porcentaje incluido como parmetro en cada una de las funciones. Las coordenas x e y corresponden al centro de la transformacin. Si se omiten se tomar como tal el punto de insercin actual. $objeto-> MirrorV (angulo, y)

transforma la celda mediante una simetra axial (como si se tratara de un espejo) cuyo eje de simetria es la recta horizontal de ordenada y. Si se omite se considerar la ordenada del punto de insercin actual $objeto-> MirrorH (angulo, x)

transforma la celda mediante una simetra axial (como si se tratara de un espejo) cuyo eje de simetria es la recta vertical de abscisax. Si se omite se considerar la ordenada del punto de insercin actual $objeto-> MirrorP (angulo,x, y)

transforma la celda mediante dos simetras axiales (como si se tratara del efecto de un espejo reflejado en otro espejo). La primera transformacin ser realiza respecto a la recta vertical de abscisa x y la segunda respecto a la horizontal de ordenada x. Si se omiten se considerar la ordenada del punto de insercin actual
ejemplo331.php Ver cdigo fuente

Celdas multilnea
La creacin de celdas sin la restriccin del mtodo anterior en cuanto al nmero de lneas es posible mediante el mtodo: $obj->Multicell ($ancho, $alto, $texto, $borde=0, $alineacion='J', $fondo=false, $salto_de_linea=1, $x='', $y='', $reseth=true, $ajuste_horizontal=0, $ishtml=false, $autopadding=true, $maxh=0, $alineacion_vertical='T', $fitcell=false)) cuyas propiedades $ancho, $alto, $texto, $borde, $alineacion, $fondo, $salto_de_linea, $ajuste_horizontal y $alineacion_vertical, coinciden con los indicados para cell en la tabla anterior, siendo los restantes los que se indican en la tabla siguiente.
Parmetro Valores Utilidad Abscisa del punto de insercin expresada en las unidad de medida establecida en la llamada al constructor TCPDF Ordenada del punto de insercin expresada en las unidad de medida establecida en la llamada al constructor TCPDF Si se establece como false la celda actual mantendr como interlnea la altura que tuviera la celda que le precede. Caso de ser true (valor por defecto, la interlnea se establecer automaticamente ajustndose al tamao de la letra en uso). La altura de la celda previa ser a estos efectos la altura real de la celda despus de haberle incluido el texto (si excede lo establecido en el parmetro $alto) o el valor de $alto en caso de no sobrepasar esa altura Si se establece true permite incluir textos en formato HTML. Esta opcin en la versin actual de la clase presenta bastantes restricciones. Si se configura como true (1) el margen interior de la celda se ajusta de manera automtica a lo establecido mediante SetCellPaddings a los cuatro bordes de la celda. Si su valor es false(0) ese ajuste de espacios se realiza nicamente respecto a los bordes izquierdo y derecho. Establece la altura mxima que puede tener la celda. Cuando se especifica, este valor debe ser mayor o igual que parmetro h y su valor mximo puede permitir que la celda sobrepase el margen inferior de la pgina. Cuando se especifica cero se desactiva la opcin. Requiere que el parametro ishtml est configurado como false Si se configura como true el tamao de la fuente puede ser reducido hasta adaptarse a las dimensiones de la celda contenedora. Requiere que est definido $maxh con un valor distinto de cero

$x $y $reseth $ishtml

nmero nmero Booleano Booleano

$autopadding Booleano $maxh $fitcell nmero Booleano

Sigue los mismos criterios indicados para Cell en lo relativo al posicionamiento del punto de insercin cuando se hace una llamada a este mtodo y permite todas las transformaciones comentadas anteriormente.
ejemplo332.php Ver cdigo fuente

Veremos ahora un ejemplo de como crear un documento a partir de un fichero de texto. En el primer ejemplo se utiliza el mtodo Writemientras que en el segundo utilizamos Multicell aplicado un padding para modificar la esttica de la presentacin
ejemplo333.php Ver cdigo fuente ejemplo334.php Ver cdigo fuente

Convertir HTML en PDF


Cuando se trata de mantener el formato HTML en un documento pdf puede utilizarse el mtodo (tiene algunas restricciones) siguiente: $objeto->WriteHTML($html, $ln=true, $fondo=false, $reseth=false, $cell=false, $alineacion='')

Para que los resultados sean correctos es muy importante que el cdigo HTML est limpio y bien formado. De lo contrario los resultados pueden resultar muy diferentes a los deseados. Los parmetros $fondo, $reseth y $alineacion coinciden con lo descrito en funciones anteriores. Los restantes son estos:
Parmetro Valores Utilidad Es el texto a incluir en el documento junto con sus etiquetas HTML. Si se establece como true agrega un salto de lnea al final del texto. Si es cierto agrega el contenido en una celda a la derecha de lo anterior

$html $ln $cell

cadena booleano booleano

ejemplo335.php

Ver cdigo fuente

Textos multicolumna
La clase TCPDF dispone de dos mtodos que permiten incluir, utilizando el mtodo Write, textos varias columnas. Para ello es preciso establecer en nmero de columnas deseado utilizando la funcin: $objeto->setEqualColumns(columnas, ancho)

mediante la cual se puede establecer el nmero de columnas deseadas y el ancho de las mismas. La funcin determinar de forma automtica el espacio entre columnas a partir del ancho de la pgina (deducidos los mrgenes izquierdo y derecho) y del nmero y ancho de las columnas. Si el ancho se estableciera de tal forma que no hubiera espacio entre columnas la propia funcin restringira ese ancho a un valor mximo que permita un margen mnimo entre columnas. Si no se especifican los parmetros columnas y ancho ser considerada una sola columna cuyo ancho sera igual al espacio entre los mrgenes izquierdo y derecho de la pgina. Una vez definido el nmero y ancho de las columnas y antes de incluir textos ser preciso situar el punto de insercin en la columna adecuada. Para ello la clase dispone del mtodo siguiente: $objeto->selectColumn(columna)

Cuando no se incluye el parmetro columna se interpreta la primera columna de la izquierda de la pgina. Una vez ejecutadas estas dos funciones solo faltara insertar el texto mediante la funcin Write tal como puede verse en los ejemplos siguientes.

ejemplo336.php

Ver cdigo fuente

ejemplo337.php

Ver cdigo fuente

Reservar espacios en pginas


Cuando se incluyen textos en documento PDF puede ser necesario reservar reas de las pginas para incluir en ellas imgenes u otros elementos grficos de forma similar a lo que ocurre cuando se trabaja con cdigo HTML o con programas grficos de autoedicin La clase TCPDF dispone de un mtodo que permite hacer esa reserva de espacios. Es el siguiente: $objeto->setPageRegions(array_de_regiones)

Este mtodo debe incluirse antes de empezar a escribir nada en las pginas y requiere que se hayan definido los espaciones en blanco mediante el array_de_regiones que es un array bidimensional de esta forma: $array_de_definiciones=Array(); $array_de_regiones[ ]=array('page' =>"pagina", 'xt' =>num, 'yt' =>num, 'xb' =>num, 'yb' =>num, 'side' =>"L")

donde page recoge en una cadena el nmero de la pgina en la que pretendemos reservar el espacio; side, que puede tomar los valores "L"(izquierda) o "R" (derecha), especifica si la reserva del espacio que pretendemos se har en el margen izquierdo o derecho de la pgina. Los parmetros xt, yt, xb e yb corresponden a las coordenadas de los puntos sealados en la imagen. Si establecemos xt y xb con el mismo valor el rea reservada se trasnsformar en un rectngulo. Podremos establecer y combinar las reas que deseemos tal como puedes ver en el ejemplo.
ejemplo338.php Ver cdigo fuente

Grficos e imgenes en PDF Dibujar segmentos y lneas


Segmentos
Para dibujar segmentos rectilneos TCPDF dispone del mtodo: $objeto->Line ( x0, y0, x1, y1, $estilo_segmento )

donde x0, y0, x1 e y1 son la coordenadas de los extremos del segmento y donde $estilo_segmento es un array que incluye los valores requeridos por el mtodo SetLineStyle. Si no se especifica este valor la lnea utilizar el estilo por defecto o el ltimo que haya sido definido en el script. En este ejemplo, adems de aplicar el dibujo de segmentos, procuraremos ver las diferentes opciones de definicin y modificacin de los estilos tal como hemos sealado en la pgina anterior al referirnos a los bordes de las celdas.
ejemplo339.php Ver cdigo fuente

Lneas poligonales
El dibujo de lneas poligonales puede hacerse mediante el mtodo: $objeto->Polyline ( poligonal, tipo_de_trazado, estilo*, color_fondo )

donde poligonal es un array que contiene las coordenadas de los puntos de la misma. El parmetro tipo_de_trazado es uno de los valores que comentamos en la tabla de siguiente y que permiten establecer eventuales rellenos, bordes y cierres en la poligonal.
Valor Utilidad Traza la lnea sin cerrar la poligonal Cierra la poligonal (agregando un segmento que une el primer punto y el ltimo) y dibuja la lnea Rellena el trazado sin dibujar la lnea. Utiliza la regla del nmero distinto (nonzero winding number) para determinar la regin a rellenar. Rellena el trazado sin dibujar la lnea. Utiliza la regla del par - impar (even-odd) para determinar la regin a rellenar. Traza la lnea (sin cerrarla) y rellena el trazado usando lla regla del nmero distinto (nonzero winding number) para determinar la regin a rellenar Traza la lnea (sin cerrarla) y rellena el trazado, usando la regla del par - impar (even-odd) para determinar la regin a rellenar. Cierra el trazado, dibuja la lnea y rellena usando lla regla del nmero distinto (nonzero winding number) Cierra el trazado, dibuja la lnea y rellena usando la regla par-impar (even-odd) para determinar la regin a rellenar Esta opcin permite utilizar elementos grficos cerrados (rectngulos, circulos, etctera) para recortar imgenes.

D d F F* DF DF* df df* CNZ

Mediante el array estilo* puede definirse el modo de trazar la polilnea que puede aplicar un estilo_segmento distinto para cada uno de los segmentos que componen la poligonal. Si no se establece aplicar a todos los segmentos el ltimo de los definidos en el documento. El array estilo* puede tener una de estas formas: $estilo=array ( 'all'=>estilo_segmento) aplicar el estilo_segmento a todos los segmentos del trazado. Recuerda que lo hemos comentado en la pgina anterior al referirnos al mtodo SetLineStyle y podra tener una forma similar a esta: $estilo_segmento =array('width' => 0.5,'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(255, 0, 255)) $estilo=array ( estilo_segmento1, estilo_segmento2, ...) ira aplicando los sucesivos estilos incluidos en el array a cada uno de los segmentos que conforman la polnea. Si el nmero de segmentos fuera mayor que el nmero de elementos del array de estilos aplicar a los no indicados el ltimo de los indicados en el array. Si el array de estilos contuviera valores igual a cero se entendera que los segmentos afectados no seran trazados.

Para el caso de trazados cerrados y con un color_de_fondo podremos especificar como cuarto parmetro del mtodo un array que contenga los valores RGB del color de fondo aplicable.
ejemplo340.php Ver cdigo fuente

Curvas de Bezier
Mediante el mtodo: $objeto->Curve(x0, y0, x1, y1, x2, y2, x3, y0, tipo_de_trazado, estilo_segmento, color_fondo)

dnde x0 e y0 son las coordenadas del punto inicial, x3 e y3 las del punto final los puntos x1, y1, x2 e y2 son las respectivas coordenadas de los puntos de control (manejadores de las curvas de Bezier) de los puntos inicial o final se consigue dibujar una porcin de curva entre ambos extemos. En la imagen pueden verse con ms detalle la posicin de los puntos. El resto de los valores, tipo_de_trazado,estilo_segmento y color_de_fondo son exactamente los mismos definidos anteriormente para el caso de las polilneas.

Las curvas obtenidas mediante este mtodo son susceptibles de ser modificadas utilizando la funciones de transformacin que hemos comentado en la pgina anterior.
ejemplo341.php Ver cdigo fuente

Rectngulos, crculos y elipses


Para representar estas figuras planas se dispone de los siguientes mtodos: $objeto->Rect ( x,y,ancho,alto,tipo_de_trazado, estilo*, color_fondo )

Dibuja un rectngulo cuyo vrtice superior izquierdo est situado en el punto sealado por las coordenadas x e y con dimensionesancho y alto. Los parmetros tipo_de_trazado y color_fondo son los mismos sealados para curvas y poligonales y , estilo* define el estilo de cada uno de los lados mediante array asociativo que puede tener la forma array('all'=>estilo_segmento) si se trata de aplicar un estilo nico a los cuatro lados. Si pretendemos que cada lado tenga un estilo diferente debemos utilizar una forma del tipo: array('L'=>estilo_izquierda, 'R'=>estilo_derecha,'T'=>estilo_superior,'B'=>estilo_inferior) donde los diferentes estilos incluidos como valores de los elementos del array asociativo son a su vez arrays que definen los estilo_segmento respectivos. Cuando se incluye un cero como valor de una o varias de las posiciones estas no sern dibujadas. $objeto->Circle(x, y, radio, inicio,final, tipo_de_trazado, estilo_segmento, color_fondo ) Dubuja un crculo con las lneas y rellenos indicados en los parmetros tipo_de_trazado, estilo_segmento y color_fondo con su centro situado en el punto de coordenadas x e y y con el radio especificado. Si se especifican valores para inicio y final (sus valores por defecto son 0 y 360) se representara nicamente el sector circular delimitado por los radios que forman angulos inicio y inicio con el eje horizontal. $objeto->Ellipse(x, y, semieje_horizontal, semieje_vertical, inclinacion, inicio, final, tipo_de_trazado, estilo_segmento, color_fondo)

Dibuja una elipse (o una porcin de ella) siguiendo idnticos criterios a los indicados para el crculo. La nica diferencia en cuanto a parmetros es que se incluyen semieje_horizontal y semieje_vertical (medida de los semiejes de la elipse) e inclinacion que indica el angulo que forma con la horizontal el eje de la elipse. $objeto->RoundedRect(x,y,ancho,alto,radio_esquina,forma_esquinas,tipo_de_trazado, estilo_segmento, color_fondo ) Dibuja un rectngulo del ancho y alto especificados con sus esquinas redondeadas y con un radio_esquina, cuyo vrtice superior izquierdo viene especificados por los valores de x e y. El parmetro forma_esquinas es una cadena del tipo "1011" que indica cuales de las esquinas (las sealadas con 1) han de ser redondeas y cuales no (las marcadas con 0). El primer valor corresponde a la esquina superior derecha continuando por las siguientes en el sentido de avance de las agujas del reloj. Los parmetros tipo_de_trazado, estilo_segmento,color_fondo son los mismos comentados anteriormente. El rectngulo redondeado debe utilizar el mismo estilo de lnea para todo su contorno y tanto los rectngulos de todo tipo como los crculos, elipse y tambin los polgonos soportan las funciones de transformacin que hemos comentado en la pgina anterior.

ejemplo342.php

Ver cdigo fuente

Polgonos regulares y estrellados


Polgonos regulares
Para dibujar polgonos regulares podemos utilizar el mtodo: $objeto->RegularPolygon ( Xc, Yc, radio, lados, angulo_inicial, circunferencia, tipo_de_trazado, estilo*, color_fondo , tipo_circunferencia, estilo_circunferencia, relleno_circulo)

dnde Xc e Yc son las coordenadas del centro de la circunferencia circunscrita, radio es el radio, lados el nmero de lados,angulo_inicial el ngulo (medido en sentido trigonmetrico) que forma con la parte negativa del eje vertical el radio correspondiente al primer vrtice del polgono, circunferencia es un valor booleano que indica si debe representarse o no la circunferencia circunscrita, tipo_de_trazadolas opciones de relleno y trazado del polgono siguiendo el criterio de la tabla ya comentada en mtodos anteriores, estilo* un array especificando los estilos de lnea del polgono (igual que ocurra con las poligonales puede aplicarse un estilo distinto a cada uno de los lados), color_fondo el color de relleno del polgono, siendo tipo_circunferencia, estilo_circunferencia y relleno_circulo los parmetros ya conocidos aplicados esta vez a la circunferencia circunscrita en el caso de que sea representada.

Polgonos estrellados
Cuando se trata de polgonos estrellados puede utilizarse el mtodo: $objeto->StarPolygon(Xc, Yc, radio, lados, ng, angulo_inicial, circunferencia, tipo_de_trazado, estilo*, color_fondo , tipo_circunferencia, estilo_circunferencia, relleno_circulo)

cuyos parmetros coinciden exactamente con los descritos para el caso del polgono regular con la nica salvedad de que aade uno nuevo, ng, cuya funcionalidad puede verse en esta imagen.

El mtodo StarPolygon lo que hace es determinar las posiciones de los vrtices de un polgono regular y trazar una poligonal cerrada(el trazado acaba al llegar al punto de partida) formada por las diagonales que unen dos vrtices separados ng posiciones. Obviamente cuando el valor de ng es 1 los vrtices a unir sern consecutivos y por lo tanto dibujar un polgono regular.
ejemplo343.php Ver cdigo fuente

Imgenes
Insertar imgenes

La integracin de imgenes en un documento PDF puede hacerse mediante el mtodo: $objeto->Image ( imagen, x, y, ancho, alto, tipo, enlace, punto_insercion, remuestreo, resolucion, alineacion, imk, imgk, borde, proporcionalidad, ocultar, encajar)

dnde: imagen es la ruta y nombre de la imagen, x e y las coordenadas donde se posicionar la esquina superior izquierda de la misma, ancho y alto sus dimensiones despus de ser insertada en el documento. Si se omitiera una de las dos dimensiones (o se asignara el valor cero) redimensionaria a la medida especificada manteniendo la otra un valor proporcional a sus dimensiones originales. Si especificamos ambos valores iguales a cero el resultado depender del valor que asignemos al parmetro booleano encajar. Si ese valor fuera false la imagen se incluira segn sus dimensiones originales y si su altura fuera mayor que el espacio disponible en la pgina actual producira un salto de pgina de forma automtica. Cuando encajar tuviera el valor true la imagen se redimensionara manteniendo la proporcionalidad y limitando su tamao de forma que no sobrepase los mrgenes del documento. Mediante el parmetro tipo se puede especificar el tipo de imagen que puede ser, entre otros: GIF, JPG, PNG BMP. Si no se especifica lo tomar de la extensin de fichero que contiene la imagen. El parmetro enlace permite incluir una cadena conteniendo el destino de un eventual hiperenlace. Mediante la propiedad punto_insercion se puede especificar la posicin en la que quedar el punto de insercin despus de haber incluido la imagen. Admite uno de estos valores: T (arriba a la derecha de la imagen), M (en el centro a la derecha de la imagen), B (en la parte inferior de la imagen a la derecha de la misma) o N (en una nueva lnea debajo de la imagen). El parmetro remuestreo es un valor booleano que est ntimamente relacionado con resolucion que es el que le sigue en la llamada al mtodo. Cuando remuestreo toma el valor false la imagen no ser remuestreada y mantendr su resolucin original. Cuando se le asigna el valor true o 1 remuestrear la imagen para ajustarla a la resolucin especificada en resolucion siempre que el valor de esta (expresada enpuntos por pulgada) sea superior al de la imagen original. En el caso de que remuestreo tuviera valor 2 el proceso se efectuara tanto si aumente como si disminuye la resolucin original. La visualizacin en pantalla no se afecta por estos parmetros sin embargo si puede tener gran importancia a la hora de producir un documento impreso. En esos casos lo aconsejable ser ajustar la resolucin de la imagen al valor que vaya a ser utilizado por la impresora. Mediante el parmetro alineacion es posible alinear una imagen dentro de la lnea en la se encuentre el punto de insercin. Admite como valores L, C o R dependiendo si pretendemos alinear a la izquierda, centro o derecha del documento. El parmetro imk parece estar obsoleto y se refieren a la creacin de reas de transparencia en imgenes. Tienen bastantes restricciones de uso y es absolutamente prescindible. Bastara con utilizar imgenes en formato PNG GIF que permiten directamente esas transparencias. Por el contrario, la opcin imgk si tiene gran utilidad cuando se trata de recortar imgenes siguiendo el borde de una figura cerrada tal como veremos cuando comentemos el proceso de este tipo de transformaciones.

Cuidado! Cuando al invocar el mtodo Image sea necesario incluir las opciones imk, imgk utiliza siempre false como valores. Hemos comprobado que si ponemos una cadena vacia '' (aparentemente podra parecer los mismo) aparecen mensajes de error en la visualizacin con algunas imgenes.

El parmetro borde permite asignarle un borde a la imagen. Los valores posibles son: 0 (sin bordes); 1 (borde por defecto) o un array idntico al descrito para el caso de los rectngulos que permite configurar las caractersticas especficas de los bordes de cada uno de los lados de la imagen. Cuando el valor de proporcionalidad es false la imagen se acomodara a las dimensiones especificadas en ancho y alto provocando distorsiones en la misma. Por el contrario, cuando su valor no es false la imagen se acomoda a la caja manteniendo la proporcionalidad. Como consecuencia de ello pueden quedar espacios sobrantes que podran distribuirse a nuestra voluntad dependiendo del valor que asignemos a proporcionalidad. Ese parmetro es una cadena formada por dos caracteres de los cuales el primero ha de ser L (izquierda), C(centro) R (derecha), mientras que para el segundo se requiere T (arriba), M (en medio) B (abajo). Dependiendo de esta configuracin la imagen se acomodar de una u otra forma al marco delimitado por los parmetros ancho y alto. Por ltimo, valor booleano ocultar establece la no visualizacin de la imagen en caso de asignarle el valor true. Cuando su valor esfalse (valor por defecto) la imagen se visualiza normalmente. En el ejemplo siguiente hemos desarrollado y comentado ejemplos con imgenes que utilizan las diferentes opciones aqu comentadas.

ejemplo344.php

Ver cdigo fuente

Recortar imgenes
Una de las posibilidades grficas de la clase TCPDF es la de recortar imgenes siguiendo el permetro de una figura cerrada. El procedimiento para ello es el siguiente: $objeto->StartTransform() Empezamos que invocar el mtodo que inicia una transformacin. $objeto->Rect(x,y,ancho,alto,'CNZ') Invocamos el mtodo que permita hacer un trazado cerrado (Circle, Elipse, Rect, RoundedRect, Polygon, StarPolygon) estableciendo como tipo_de_trazado el valor CNZ. $objeto->Image(imagen, x, y, ancho, alto, tipo) Insertamos la imagen de modo que por su posicin y dimensiones se superponga con la figura cerrada incluida en el mtodo anterior. $objeto->StopTransform() Finalizamos la transformacin. Como resultado del proceso solo se visualizar la parte de la imagen situada dentro del contorno de la figura cerrada que hace funcin de mscara. Si la figura tiene definidas bordes estos aparecern delimitando la imagen. Tambin es posible efectuar recordes de imgenes delimitndolas por los bordes de las letras que componen un texto. El proceso es bastante similar al anterior. Comienza como aquel con: $objeto->StartTransform(). A continuacin hay que utilizar este nuevo mtodo: $objeto->setTextRenderingMode(borde, relleno, recorte)

dnde borde es un valor numrico que indica el espesor de la lnea que dibuje el borde de las letras. Si se especifica cero no se visualizarn esos bordes. La opcin relleno es un valor booleano que permite especificar si la letra aparecer rellena en color negro o no. Por ltimo el paramtro recorte, tambin booleano, ha de configurarse con valor true para que permita recortar la imagen. Despus de aplicar el mtodo anterior hemos de escribir el texto. Para hacerlo utilizaremos el mtodo Write de una forma similar a esta: $objeto->Write(interlinea, texto)

El paso siguiente sera insertar la imagen con la posicin y dimensiones que permitan que texto e imagen se superpongan. $objeto->Image(imagenb, x, y, ancho, alto, tipo)

Por ltimo, tendramos que incluir el final de la transformacin mediante el ya conocido: $objeto->StopTransform() En este ejemplo pueden verse la diferentes posibilidades de utilizar elementos grficos como rutas para el recorte de imgenes tal como acabamos de describir.
ejemplo345.php Ver cdigo fuente

Transparencias y modos de superposicin


La clase TCPDF dispone del mtodo $objeto->SetAlpha(opacidad,modo)

en el que opacidad es un valor comprendido entre 0 y 1 que indica el grado de opacidad de la imagen o texto. Por defecto su valor es 1 (opacidad total). El segundo parmetro de la funcin, modo (permite uno de los valores descritos aqu debajo) se comporta de forma muy similar a la utilizada por los programas de retoque fotogrfico en la forma de combinar elementos grficos superpuestos (imgenes, textos, trazados).

Normal: No hay interaccion entre las imgenes superpuestas. El resultado ser la consecuencia del grado de opacidad de cada una de ellas. Multiply: El valor de los pxeles de la imagen de fondo se multiplica por el valor de los pxeles de la capa superpuesta y el resultado se divide entre 255. Generalmente se obtiene un oscurecimiento de la imagen. Screen: Realiza el efecto contrario a Multiplicar (usa el inverso de todos los valores para realizar la operacin) por lo que obtenemos una imagen mucho ms clara que la original. Overlay: Los colores brillantes de la imagen de fondo se dividen entre los de la capa superpuesta mientras que los colores oscuros se multiplican. El resultado ser una superposicin de los colores de ambas capas, conservndose las luces y las sombras de la imagen de fondo. Darken: Producir una imagen ms oscura como resultado de la comparacin que realiza el programa entre los pxeles de cada imagen, mostrando los ms oscuros de cada una. Lighten: Se comporta de forma idntica a la anterior pero ahora mostrando los colores ms claros de cada imagen. Color Dodge: Este efecto es similar al que se producira si en fotografa tradicional disemos un tiempo de exposicin prologando a la fotografa. Color Burn: Produce un efecto similar a la subexposicin de la fotografa tradicional Soft Light: Produce un efecto similar a iluminar la imagen con un foco de luz difusa y suave. Hard Light: Igual que el anterior pero iluminando con una luz ms dura. Difference: Rellena parte de la imagen inferior con partes de la superpuesta. Generalmente se sustraer color de la capa con el color ms brillante en el punto que se examine Exclusion: Produce efectos similares que Diferencia pero con un contraste menor. Hue: Mezcla el valor de Tono de la imagen con el de saturacin y brillo de la imagen inferior. Saturation: Mezcla el valor de saturacin del color de la imagen superpuesta con los valores de brillo y tono de la imagen de fondo. Color: Mezcla el valor de saturacin de color de la imagen superpuesta con el valor de brillo de la imagen inferior. Luminosity: Produce el efecto inverso que Color. Mezcla los valores de saturacin y tono de la imagen inferior con el valor de brillo de la imagen superpuesta.

ejemplo346.php

Ver cdigo fuente

Calidad de las imgenes


En el caso de incluir imgenes en formato JPG es posible establecer el grado de compresin de las mismas. Por defecto la clase establece un valor del 75%. Si pretendemos modificarlo podremos utilizar el mtodo: $objeto->setJPEGQuality(porcentaje)

Encabezados, pies de pgina y cdigos de barras Encabezados y pies de pgina


Existen dos opciones posibles de incluir encabezados y pies de pgina en un documento. La primera de ella sera utilizar el mtodo incluido en la propia clase. Los resultados que produce son bastante pobres y limitados. No obstante resumiremos su funcionamiento. Con carcter general deberemos tener en cuenta lo siguiente: $objeto->setPrintHeader ( true ) y $objeto->setPrintFooter ( true )

han de estar configuradas como true (su opcin por defecto) para permitir que se visualicen los encabezados y pies de pgina. $objeto->setHeaderMargin(numero)

debe tener asignado un valor numrico (la distancia del borde superior de la pgina al punto donde empezar la insercin de los elementos del encabezado). Caso de no establecerlo tomara valor cero y el encabezado se situara con margen cero (a sangre) respecto al borde superior del papel. $objeto->setFooterMargin(numero)

debera estar establecido ya que con su valor por defecto (cero) empezara a escribir el pie de pgina debajo de borde inferior del papel. El nmero positivo que incluyamos en este mtodo establecer a que distancia del borde inferior empieza a presentarse el pie de pgina.

$objeto->setHeaderFont(array(nombre,estilo,tamao))

permite establecer como elementos del array escalar: el nombre de letra nombre ('times', por ejemplo), el estilo estilo (podra ser algo como 'I' italic) y el tamao tamao expresado en las mismas unidades con que se definen las dimensiones de la pgina. $objeto->setFooterFont(array(nombre,estilo,tamao))

Se comporta exactamente igual que el anterior solo que en este caso se establece la tipografa para los pies de pgina. $obj->setHeaderData(logo, ancho, titulo, subtitulo)

Mediante este mtodo podremos indicar el nombre de una imagen (logo), el ancho que pretendemos que ocupe esa imagen ancho, una cadena de texto titulo que ser el ttulo del encabezado y subtitulo una lnea de texto que ira debajo de la anterior. El pie de pgina se incluye de forma automtica y estar formado nmero de la pgina y el nmero total de pginas del documento separadas por una barra. En ambos casos se dibujara una raya horizontal delimitadora del encabezado y pie de pgina que ocupa todo el espacio entre mrgenes. Los pies de pgina se alinearan al margen derecho y los encabezados al margen izquierdo.
ejemplo347.php Ver cdigo fuente

Cuidado! Salvo que hagamos una modificacin en el fichero de configuracin (o hagamos cambios en el fichero tcpdf.php que contiene la clase), la imagen que incluyamos en el encabezado deber estar en /images/ dentro del directorio tcpdf. Para alterar esa ruta sera necesario modificar el fichero de configuracin.

Clase extendida para encabezados y pies de pgina


La configuracin a medida de encabezados y pies de pgina requiere la creacin de una clase extendida de la clase TCPDF en la que el carcter polimrfico de las clases nos va a permitir redefinir los mtodos Header() y Footer() que son los que incluyen los encabezados y los pies de pgina. Los objetos de la nueva clase extendida utilizaran los mtodos incluidos en ella en lugar de los establecidos en la clase padre. Aqu tienes un ejemplo de aplicacin de una clase extendida.

<?php /*incluimos el fichero con las rutas y los include de las clases necesarias tal como venimos haciendo el los ejemplos anteriores */ include("tcpdf.inc.php"); /* empezaremos creando una clase extendida de TCPDF que permitir reescribir las funciones Header y Footer incluidas en el constructor de la clase TCPDF. Estas nuevas funciones sustituiran a las preexistentes */ class ConPies extends TCPDF { public function Header() { /*ponemos color al texto y a las lineas */ $this->SetTextColor(0,0,200); $this->SetDrawColor(255,0,0); /* definimos variables con titulo y subtitulo */ $titulo="Adios cordera"; $subtitulo="Leopoldo Alas (Clarin)"; /* posicionamos el puto de insercion 2mm. debajo del borde del papel */

$this->SetY(2); /* escribimos el titulo con la fuente que se establezca por el mtodo opcion SetHeaderFont */ $this->Cell(0, 5,$titulo,0,1,'C'); /* modificamos tipografia para el subtitulo e insertamos este */ $this->SetFont('helvetica', 'I', 7); $this->Cell(0, 2,$subtitulo,0,1,'C'); /* trazamos un rectangulo sombreado que por sus dimensiones ocupar el area de texto de la pagina */ $this->Rect(15,15,180,267,'F','',array(240,240,240)); /*trazamos una linea roja debajo del encabezado */ $this->Line(15,15,195,15); /* insertamos una imagen de fondo con 15% de opacidad */ $this->SetAlpha(0.15,'Normal'); $this->Image('./images/cordera2.jpg',55,84,100,104, '','','N','','','C'); /* recuperamos la opacidad por defecto */ $this->SetAlpha(1,'Normal'); } public function Footer() { /* establecemos el color del texto */ $this->SetTextColor(0,0,200); /* insertamos numero de pagina y total de paginas*/ $this->Cell(0, 10, 'Pagina '.$this->getAliasNumPage(). ' de un total de '. $this-> getAliasNbPages(), 0, false, 'C', 0, '', 0, false, 'T', 'M'); $this->SetDrawColor(255,0,0); /* dibujamos una linea roja delimitadora del pie de pgina */ $this->Line(15,282,195,282); } } /* creamos un nuevo objeto usando la clase extendida ConPies */ $MiPDF = new ConPies(); /* definimos margenes de encanbezado y pie de pagina, tipos de letra para encabezados y piel */ $MiPDF->setHeaderMargin(2); $MiPDF->setFooterMargin(15); $MiPDF->setHeaderFont(Array('times', '', 14)); $MiPDF->setFooterFont(Array('helvetica', 'I', 10)); /* fijamos el modo de visualizacion, agregamos dos paginas y visualizamos el resultado */ $MiPDF->SetDisplayMode('fullpage'); $MiPDF->AddPage(); $MiPDF->AddPage(); $MiPDF->Output(); ?>
ejemplo348.php Ver cdigo fuente ejemplo349.php Ver cdigo fuente

Cdigos de barras
Cdigos de barras lineales
TCPDF dispone de una funcin que permite incluir cdigos de barras en los documentos PDF. El mtodo es el siguiente:

$objeto->write1DBarcode ( codigo, tipo, x, y, ancho, alto, xres, estilo, alineacion)


Valor Utilidad Son los dgitos y/o caracteres que van a representarse en formato de cdigo de barras Ha de tener como valor una ds estas cadenas:C39, C39+, C39E, C39E+, C93, S25, S25+, I25,I25+, C128A, C128B, EAN2, EAN5, EAN8, EAN13, UPCA, UPCE, MSI, MSI+, POSTNET, PLANET, RMS4CC, KIX, IMB, CODABAR, CODE11, PHARMA, PHARMA2T. Representan algunos de los mltiples formatos de codificacin existentes en la actualidad. Son las coordenadas del puntos de insercin de la esquina superior izquierda del rectngulo contenedor del cdigo de barras. Son los valores del ancho y el alto del rectngulo contenedor Es el ancho de la barra ms estrecha expresada en las mismas unides con las que se define el tamao del documento. Por defecto su valor es 0,4 mm. Es un array asociativo que puede contener los siguientes elementos: Elemento Valor Utilidad Indica si ha de ponerse borde al rectngulo contenedor del cdigo de barras Establece la distancia que ha de separar la barras del los mrgenes del contenedor. Adems de valores numricos admita la opcin 'auto'. Establece la distancia que ha de separar la barras del los bordes laterales contenedor. Adems de valores numricos admita la opcin 'auto'. Establece la distancia que ha de separar la barras del los bordes superior e inferior del contenedor. Adems de valores numricos admita la opcin 'auto'. Es una array escalar formado por los valores de los componentes de color R, G, B del color que se utilizar para las barras y los textos Es una array escalar formado por los valores de los componentes de color R, G, B del color que se utilizar rellenar el fondo de rectnulo contenedor Cuando se le asigna el valor true se escribir una cadena de texto con los valores del cdigo de barras Permite definir el nombre de la fuente que se utilizar para presentar los textos. Si se omite se utilizar la fuente por defecto. Establece el tamao de la fuente El valor que se incluya en este elemento se incluir como texto debajo del cdigo de barras Si su valor es cero (0) no se producen modificaciones en la escala de los textos. Si se asigna valor uno (1) forzara la escala horizontal de los textos si fuera necesario para que cupiera dentro del rectngulo contenedor. Cuando el valor asignado sea dos (2) forzara la escala horizontal, ampliando o reduciendo, para adaptar el texto al espacio disponible. Si los valores son tres(3) o cuatro (4) el comportamiento sera similar a los anteriores (1 o 2) modificando el espacio entre caracteres en vez de ampliar o reducir el tamao de los mismos. Establece la posicin del cdigo de barras respecto a su rectngulo contenedor Posiciona el rectngulo contenedor respecto a los mrgenes laterales de la pgina Cuando est configurado como true adapta el ancho del cdigo al espacio contenedor. Si su valor es false se usa el ancho de barras establecido por el parmetro xres Si se asigna el valor de true adapta el ancho del rectngulo contenedor al espacio requerido por el cdigo de barras y los mrgenes laterales (padding) Esta opcin slo funciona cuando fitwidth es true y "position no est definido o est vaco. Ajuste la posicin horizontal de la celda que contiene cdigo de barras en el interior del rectngulo especificado: L = izquierda, C = centro, R = derecha.

codigo tipo x, y ancho, alto xres

'border' 'padding' 'hpadding' 'vpadding' 'fgcolor' 'bgcolor' 'text' 'font'


estilo

booleano numero numero numero array array booleano nombre booleano texto

'fontsize' 'label'

'stretchtext' numero 'position' 'align' 'stretch' 'fitwidth'


L,C,R L,C,R booleano booleano

'cellfitalign' booleano
alineacion

Establece la posicin del punto de insercin despus de haber incluido el cdigo de barras. Admite como valores T, M, B, N que se refieren a las partes: superior derecha, centro derecha,inferior derecha o nueva lnea siempre respecto al cdigo de barras actual.

En este ejemplo pueden verse las diferentes posibilidades de este tipo de cdigos de barras.
ejemplo350.php Ver cdigo fuente

Cdigos de barras 2D
La clase TCPDF tambin permite escribir cdigos de barras del tipo 2D utilizando el mtodo: $objeto-> write2DBarcode ( codigo, tipo, x, y, ancho, alto, estilo, alineacion, distorsion )

de gran similitud al descrito anteriormente aunque con algunos elementos diferenciados en lo que se refiere a tipo, estilo y distorsion.

Este formato de cdigos admite como tipos alguno de los siguientes: RAW, RAW2, QRCODE,L, QRCODE,M, QRCODE,Q, QRCODE,H,QRCODE,L o PDF417. Por lo que respecta al estilo se define, igual que en el caso anterior, mediante un array asociativo cuyos elementos son: 'border','padding', 'hpadding', 'vpadding', 'fgcolor', 'bgcolor', 'position' con comportamientos idnticos a los descritos en el prrafo anterior y tambin'module_height' y 'module_width' que permiten establecer mediante valores numricos el alto y el ancho (expresado en puntos) de un mdulo simple. El parmetro distorsion es un valor booleano. Cuando se le asigna true puede distorsionar el cdigo de barras para encajarlo con la anchura y la altura. Si el valor es false (valor por defecto) preservar la relacin de aspecto. En el ejemplo siguiente tienes comentadas algunas de las diferentes opciones de esta funcin.
ejemplo351.php Ver cdigo fuente

Formularios en PDF Formularios en PDF


En pginas anteriores hemos tratado del tema relativo a los formularios como medio de intercambio de informacin entre el cliente y el servidor. La clase TCPDF nos permite desarrollar formularios en formato PDF con algunas ventajas comparativas respecto a los tradicionales. Algunas de ellas son las siguientes: - Los archivos PDF que contienen los formularios interactivos podran estar residente en el cliente o ser descargados con disponibilidad plena sin conexin a internet. En el caso de los archivos HTML, cada vez que sean invocados por el cliente deben ser descargados desde el servidor. - La apariencia de los formularios interactivos en PDF es la misma independientemente del browser que se utilice. Esto no ocurre con HTML, donde las preferencias del browser inciden en la manera de visualizacin de los formularios. - Los documentos PDF pueden hacer uso de la opcin de firma digital, que garantiza la autenticidad de la autora de un documento y el manejo de opciones de seguridad. - Los documentos PDF incluyen todos los elementos necesarios para la visualizacin, tales como imgenes, tablas, etc. Los documentos HTML usualmente deben incluir archivos anexos que pueden no funcionar de manera adecuada en el momento de la descarga. - La navegabilidad de los documentos PDF se garantiza de manera automtica desde su creacin. En HTML la navegabilidad se debe construir desde el cdigo con hipervnculos o creando marcos (frames) en los documentos, los cuales presentan dificultades de visualizacin en algunos browser. Los mtodos que permiten incluir los distintos componentes de los formularios son los siguientes:

Cajas de texto
Este tipo de elemento puede ser utilizado de forma que cubra las necesidades de las entradas de texto, las entradas tipo password, las reas de texto y tambin las tipo file. El mtodo que permite insertarlas es el siguiente: $objeto->TextField(nombre, ancho, alto, propiedades, anotaciones, x, y)
Valor Utilidad Es el nombre identificador del elemento que servir para asignar nombre a la variable que recoja su contenido cuando el formulario sea transferido al servidor. Son los valores del ancho y el alto del rectngulo contenedor. (**) Son las coordenadas del puntos de insercin de la esquina superior izquierda del rectngulo contenedor del rea de texto. Es un array asociativo que puede contener, entre otros, los siguientes elementos: Elemento Valor Utilidad Indica si ha de cumplimentarse obligatoriamente (true) o si no es requerido necesariamente (false). Permite asignar un valor por defecto al elemento. Si no se incluye se cargar una cadena vaca.

nombre ancho, alto x, y

propiedades

'required' 'value'

booleano Su valor por defecto es false. cadena

'password' 'readonly' 'charLimit' 'multiline' 'fileSelect' 'lineWidth' 'borderStyle' 'fillColor'

booleano tpicos asteriscos de los campos tipo password. booleano defecto. numero

Cuando este valor se establece como true al teclear contenidos en el campo se visualizaran los

Permite, cuando se le asigna el valor true, impedir la modificacin de los valores asignados por Permite limitar el nmero mximo de caracteres susceptibles de ser incluidos en ese campo. Cuando este valor se configura como true permite mltiples lneas y su comportamiento es idntico al Cuando se configura como true permite seleccionar ficheros de forma similar a los formularios HTML.

booleano de los textarea del HMTL.

booleano Requiere ser complementado con un botn (en HTML se insertan simultneamente) mediante el cual
se ejecutar la accin que permita elegir el fichero a incluir.

numero cadena array

Permite especificar el ancho de la lnea que contornea el elemento. (*) Permite asignar un estilo al borde del elemento. Si se asigna la cadena 'solid' (valor por defecto) contornear con una lnea continua. Si se asigna 'dashed' lo har con lnea discontinua. (*) Permite establecer un color de fondo asignado mediante un array definido como array(R,G,B) dnde R, G y B son los valores de las componentes de los colores primarios. (*) Permite establecer un color de fondo asignado mediante un array definido como array(R,G,B) dnde R, G y B son los valores de las componentes de los colores primarios. (*)

'strokeColor' array
anotaciones

Permite incluir anotaciones de acuerdo con las especificaciones PDF32000_2008. Para nuestros fines no resulta necesario. Bastar que incluyamos este parmetro en forma de un array vaco: array()

(*) Este valor pueden asignados de forma global para todos los elementos del documento incuyndolo el mtodo setFormDefaultProp. (**) Si se asigna cero a los valores ancho y alto no se visualizar el campo. Si se le asignara un value podra emular perfectamente los campos ocultos (hidden) de los formularios HTML.

Botn de opcin
Este tipo de elemento puede ser utilizado de forma idntica a la contemplada en los formularios HTML. El mtodo que permite insertarlo es el siguiente: $objeto->RadioButton( nombre, ancho, propiedades, anotaciones, valor, marcado, x, y)

El parmetro nombre permite identificar el elemento (y el valor de la variable al ser enviado el formulario) y ha de ser el mismo en los diferentes elementos que conforman las opciones de eleccin. Mediante ancho especificamos el ancho del botn de opcin, las propiedadesen este caso se limitan a las caractersticas grficas ya sealadas para las cajas de texto. Las anotaciones tienen una funcionalidad y comportamiento similares (tambin aqu podemos incluir un array vaco). El parmetro valor permite especificar el valor que se asignara a la variable nombre en el caso de ser seleccionada la opcin mientras que marcado es un valor booleano que en caso de estar configurado como true hara que la opcin aparezca seleccionada por defecto. Los parmetros x e y son las coordenadas del punto de insercin del elemento.

Casillas de verificacin
Tambin se comportan de forma idntica a los formularios HTML. El mtodo que permite insertarlos es el siguiente: $objeto->CheckBox(nombre, ancho, marcado, propiedades, anotaciones, valor, x, y)

Utiliza los mismos parmetros, y con idnticas funcionalidades, que el botn de opcin. Las dos nicas diferencias a tener en cuenta es que se incluyen en distinto orden y que las casillas de verificacin deben tener siempre nombres diferentes.

Cuadro de lista
Presenta un cuadro de lista desplegando las diferentes opciones que pueden ser seleccionadas. Si se configura adecuadamente pueden hacerse una seleccin mltiple. El mtodo que permite insertarlo es el siguiente: $objeto->ListBox(nombre, ancho, alto, valores, propiedades, anotaciones, x, y)

Casi todos los parmetros son los ya conocidos. Las diferencias respecto a lo comentado para el caso de cajas de texto se refieren a los valores y a las propiedades. En caso de los valores deberemos incluir un array escalar que contenga como valores las

diferentes opciones posibles de la lista. En cuanto a propiedades pueden incluirse lo elementos de ese array asociativo relativos a la configuracin grfica y, adems, un nuevo elemento: 'multipleSelection' un valor booleano que en caso de tener asignado el valor true permite seleccionar varios items de la lista (bastara marcarlos manteniendo pulsada la tecla Ctrl). Cuando se utiliza esta opcin es muy importante tener la precaucin de agregar unos corchetes al nombre del elemento. Por ejemplo:aficiones[] en vez de aficiones. De esta forma cuando los datos sean enviados al servidor PHP interpretar la variable como un array y podr extraer de ella los diferentes valores seleccionados. Si se omitieran los corchetes PHP solo recogera el ltimo de los valores seleccionados. Si en el array propiedades incluyeramos un elemento con nombre 'value' y el asignramos como valor una de las opciones ocurrira que al ser cargado el formulario aparecera seleccionada ese valor de forma automtica.

Cuadro desplegable
Este tipo de elemento puede ser utilizado de forma idntica a la contemplada en los formularios HTML. El mtodo que permite insertarlo es el siguiente: $objeto->ComboBox(nombre, ancho, alto, valores, propiedades, anotaciones, x, y)

Se comporta de forma muy similar a la descrita en el elemento anterior. Como es lgico no permite la propiedad multipleSelection. De igual forma que ocurra en aquel caso si se incluye la propiedad value aparecer seleccionado el elemento correspondiente de la lista. Respecto al array que contiene los valores caben dos posibilidades de insercin. La primera es la ya descrita para el caso anterior:(array('valor1','valor2','valor3')). Alternativamente pueden usarse formas del tipo ( array (array ('item1','valor1'),array('item2','valor2'),array('item3','valor3') ) en la que en vez de los valores de los elementos se incluye un array de dos elementos por cada uno de ellos. El primer elemento de cada uno de esos arrays ser el texto que aparecer en el formulario y el segundo el valor que habra de asignarse al ser elegida esa opcin. Es decir, se visualizara item2 y se enviara al servidor valor2 que es el valor asociado a el.

Botones
Los botones son elementos imprescindibles en el caso del manejo de formularios. El mtodo que los incluye es este: $objeto->Button(nombre, ancho, alto, caption, accion, propiedades, anotaciones, x, y)

Los parmetros nombre, ancho, alto, propiedades, anotaciones, x e y tienen idntico significado que en casos anteriores (las propiedades se reducen a sus aspectos grficos). Incorpora como elementos nuevos el parmetro caption que ser una cadena con el texto que aparecer en el propio botn y el parmetro accion que podr incluir una llamada a una funcin de JavaScript o un array asociativo. Estos son algunos ejemplos del primer supuesto: $objeto->Button('imprime', 30, 10, 'Imprimir', 'print()', $estilo, array() , 30, 265);

insertara un botn con el estilo definido en $estilo en el que se visualizara la palabra Imprimir y que al ser pulsado ejecutarla la funcin print() del sistema del usuario. $objeto->Button('almacena', 30, 10, 'Imprimir', 'guardar()', $estilo, array() , 30, 265);

insertara un botn con el estilo definido en $estilo en el que se visualizara la palabra Guardar y que al ser pulsado ejecutarla la funcin JavaScript guardar() en el navegador del usuario. Las funciones JavaScript debe estar incluida en el propio documento pdf. Para ello la clase TCPDF dispone del mtodo: $objeto-> IncludeJS($texto_con_codigo_JavaScript)

dnde la variable $texto_con_codigo_JavaScript contiene el cdigo JavaScript que se pretende incluir en el documento. En el supuesto anterior podra ser una funcin tal como esta: function guardar(){app.execMenuItem("SaveAs");} Cuando se trata de enviar el formulario es necesario recurrir a un botn con las siguientes caractersticas: $objeto->Button('submit', ancho, alto, 'Enviar', array('S'=>'SubmitForm','F'=>'xxxxx.php','Flags'=>array('ExportFormat','IncludeNoValueFields')), $estilo, array() , x, y );

en cuyo array asociativo son obligatorios los elementos: 'S' con valor 'SubmitForm' (que har el envo del formulario); 'F' cuyo valor se la direccin del script que recoger los resultados del envo 'xxxxx.php' (equivale a action en el formulario convencional de HTML) y elemento'flags' ha de incluir un array conteniendo los valores 'ExportFormat' y 'IncludeNoValueFields'. De no hacerlo no se recibiran en el servidor los contenidos del formulario. Cuando se trata de borrar el contenido del formulario es necesario recurrir a un botn con las siguientes caractersticas: $objeto->Button('reset', ancho, alto, 'Borrar', array('S'=>'ResetForm'), $estilo, array() , x, y );

en cuyo array asociativo es obligatorio el elemento: 'S' con valor 'ResetForm' (que borrar los contenidos del formulario).

Ficheros adjuntos
El envo de ficheros adjuntos requiere el uso de tres elementos: un campo de texto, un botn y una funcin JavaScript. $objeto->TextField( 'nombre_campo',ancho,alto,array('fileSelect'=>true),array(),x,y)

el campo de texto requiere la opcin 'fileSelect'=>true $objeto->Button( 'Sube',ancho,alto,'Seleccione el archivo', "Cargar('nombre_campo')", $estilo_boton)

el botn debe incluir el la llamada una funcin JavaScript en la que debemos incluir como argumento una cadena que ha de coincidir con el el nombre_campo asignado como nombre al campo de texto. function Cargar(nombre){ var selecciona = this.getField(nombre); selecciona.browseForFileToSubmit(); } la funcion JavaScript tal como la ests viendo permite seleccionar un nombre de fichero y que de forma automtica se incluya su nombre y su ruta en el campo de texto. El comportamiento es idntico al caso de enviar ficheros desde los formularios HTML. En el cdigo fuente de este ejemplo puedes ver como hemos incluido las funciones JavaScript en una variable usando la sintaxis de documento incrustado.
ejemplo352.php Ver cdigo fuente

Inclusin de ficheros y firma digital Inclusin de ficheros


Otra de las posibilidades que ofrece la clase TCPDF es la inclusin de anotaciones y ficheros incrustados en el propio documento PDF. Para ello se utiliza el mtodo siguiente:

$Objecto->Annotation(x, y, ancho, alto, texto, array('Subtype'=>'FileAttachment', 'Name' =>'icono', 'FS'=>'nombre_fichero '))

dnde x e y son las coordenadas del punto dnde se insertar el icono que advierte de la existencia de una anotacin. Los valoresancho y alto especifican las dimensiones de ese icono. El parmetro texto permite incluir un texto alternativo que si visualizara cuando se colocara el puntero del ratn sobre el icono. Cuando se incluye ese texto aparecer a la derecha del icono una advertencia en forma de bocadillo de cmic. Si ese texto se deja como cadena vaca no se visualizar esta ltima marca. El array que se incluir como sexto parmetro es de tipo asociativo. Su primer elemento, Subtype, tendr como valor FileAttachement(alude a la inclusin de un fichero adjunto), el elemento cuyo ndice es Name especificar en su valor el tipo de icono que se visualizar en el documento. Son vlidos los tipos: Graph, Paperclip Tag y PushPin. El elemento de ndice FS tendr como valor el nombre y la extensin del fichero que incluir en el documento. Como es lgico tal fichero ha de estar ubicado en un lugar accesible por el servidor.

Cuidado! La descarga de ficheros adjuntos (pulsando con el botn derecho del ratn sobre el icono) est restringida en Adobe Reader por razones de seguridad. Ficheros ejecutables, comprimidos, etctera no se abren en prevencin de que pudieran contener elementos maliciosos.

Cuando se trata de incluir nicamente una nota de comentario puede utilizarse el mtodo anterior con la sintaxis siguiente: $Objecto->Annotation(x, y, ancho, alto, texto, array('Subtype'=>'Text', 'Name' =>'Comment', 'T'=>titulo, 'C' => array(255, 255, 0)))

las modificaciones respecto al supuesto anterior son: la modificacin del valor del elemento Subtype que ahora toma Text como valor; la modificacin de valor del elemento Name que ahora pasa a tener como valor Comment; la inclusin del elemento T al que podremos asignar como valor el ttulo de comentario y la posibilidad de aadir un color al icono de comentario mediante el elemento C al que se asigna como valor un array cuyos tres elementos son las componentes R, G, B del color que pretende aplicarse.

Firma digital de los documentos


Otra de posibilidades de la clase TCPDF es la firma digital de los documentos generados. Con ello, si el servidor dispone decertificados digitales (no es necesario que est configurado en modo seguro) los ficheros pdf pueden ser firmados de forma que al ser leidos por el cliente a travs de Adobe Reader pueda verificar la no manipulacin y la autenticidad de la firma. Para efectuar la firma de un documento necesitaremos acceder al certificado digital de servidor y tambin su clave privada. Si no hemos efectuado la instalacin en modo seguro del servidor Apache y no disponemos de los certificados all utilizados podemos utilizar a efectos de pruebas uno que viene incluido con la distribucin de TCPDF, dentro del directorio tcpdf, con nombre tcpdf.crt y cuya contrasea estcpdfdemo. El mtodo que permite incluir la firma digital del servidor es el siguiente: $objeto->setSignature( certificado, clave_privada, contrasea, extras, tipo, informacion)

dnde certificado es una cadena que comienza por file:// y va seguida de la ruta y nombre del fichero que contiene el certificado que va a ser utilizado para facilitar la comprobacin de la firma del documento; clave_privada es la clave privada del firmante (tambin debe indicarse mediante file:// y va seguida de la ruta y nombre del fichero). La contrasea ser la contrasea de uso de la clave privada. Si utilizamos el certificado de servidor mencionado en este enlace esa contrasea ser una cadena vaca ya que, tal como puedes recordar si visitas el enlace anterior, al crear la clave privada del servidor (la funcin genrsa de OpenSSL) habamos omitido el modificador -des3 precisamente para que tal contrasea no fuera requerida. Como parmetro extras vamos a utilizar una cadena vaca ya que nuestro certificados carecen de esa informacin complementaria. Como parmetro tipo podemos incluir 1 (cualquier cambio en el documento invalidar la firma), 2 (se permite la cumplimentacin de formularios sin invalidar la firma) o 3 (no invalida la firma ni la cumplimentacin de formularios ni la inclusin, modificacin o eliminacin de anotaciones).

Por ltimo, informacion es un array asociativo cuyos elementos tienen por ndices: 'Name', 'Reason' , 'Location' y 'ContactInfo' y contendrn como valores cadena conteniendo datos informativos sobre el titular del certificado digital utilizado. Esos valores podrn ser visualizados por el cliente de la forma que veremos en el prrafo siguiente. Aunque no resulta elemento imprescindible es habitual incluir en el documento algn tipo de imagen o smbolo que sugiera que el documento incluye una firma digital. Puede ser cualquier elemento grfico. Cuando se ejerce esa opcin suele complementarse con la definicin de un rea activa en el documento (normalmente la que ocupa el grfico que simboliza la firma) de modo que al pulsar con el ratn sobre esa zona se abra una ventana que facilite la informacin aludida en el prrafo anterior. En los ejemplos que incluimos a continuacin tienes una muestra del uso de anotaciones y firma digital. En el primero de ellos utilizaremos el certificado demostracin incluido con TCPDF y en el segundo haremos uso del certificado al que hemos hecho mencin encertificado de servidor mencionado en este enlace. Si no dispones de esos certificados o si la ruta no coincide el segundo de los ejemplos te dar error.
ejemplo353.php Ver cdigo fuente ejemplo354.php Ver cdigo fuente

Cuidado! En el ejemplo anterior habrs observado que en el caso de que el sistema operativo sea Ubuntu hemos aplicado la funcion realpath() a la ruta hasta el certificado y la clave privada. De no hacerlo as la ejecucin del script produce un error. La funcion realpath(ruta) devuelve el nombre de la ruta en forma de ruta absoluta cannica que tiene un valor nico y que no siempre coincide con la ruta absoluta que suele depender del sistema operativo en uso.

Tal como habrs podido observar a mirar el cdigo fuente, en este ejemplo he intentado incluir algunos fichero incrustados y a la vez crear un documento firmado con certificado digital, guardando el pdf resultante en el servidor con un nombre creado de forma aleatoria e incluyendo en el propio fichero la ruta hasta el mismo. Una vez creado el fichero se abrira de forma automtica en el navegador del cliente que podra guardarlo en su equipo y/o imprimirlo. La firma digital es facilmente comprobable en un documento digital pero es evidente que esa comprobacin es imposible en una copia impresa del documento. Al guardarlo en el servidor e incluir la direccin estaremos facilitando la posibilidad de comprobar la fidelidad de una copia a cualquiera que tenga acceso a ella.

Un ejemplo de aplicacin
Incluimos un ejemplo que intenta mostrar en alguna medida las posibilidades de esta herramienta emulando una ventanilla de registro clsica. Al ejecutar el script se carga un formulario que, una vez cumplimentado e incluidos los ficheros adjuntos solicitados, es enviado al servidor, donde se bloquean los campos del formulario y se agregan unos textos que emulan el sello de registro de entrada (en caso de identificacin mediante certificado electrnico podra incluir los datos de este). Tambin se incrustan en el documento, formando un todo con l, los ficheros adjuntos. El fichero resultante se almacena en el servidor (emulando el original para la administracin) y se devuelve al navegador una copia completa del mismo.
ejemplo355.php Ver cdigo fuente

Creacin de ndices de contenidos y fuentes Indices de contenidos


Otras de las mltiples posibilidades de la clase TCPDF es la inclusin de marcadores y la confeccin automtica de listas de contenidos. Los marcadores, como podrs ver en el ejemplo, pueden incluirse de modo que el ndice resultante pueda tener distintos niveles (captulos, apartados, sub apartados, etctera). El mtodo que permite la elaboracin de ese tipo de enlaces es el siguiente: $objeto->Bookmark(texto, nivel, posicion, pagina, estilo, color)

dnde texto es una cadena que contiene el texto que aparecer en el ndice del documento, nivel ser un nmero entero que indicar a qu nivel pertenece la marca. Cero significar primer nivel (por ejemplo TEMA), uno significar segundo nivel (en el ndice colgar del de primer nivel anterior a l) y as sucesivamente. El parmetro posicion admite como valores 0 y -1. Si se especifica 1 al pulsar sobre el enlace el navegador se punto de insercin en la parte superior de la ventana contenedora del documento. Si ese valor es 0 se situar en el borde superior de la pgina que contiene el marcador.> El parmetro pagina permite especificar la pgina a la que nos redirigir el enlace. Si se incluye una cadena vaca (lo habitual) nos redirigir a la pgina que incluye el marcador actual. El parmetro estilo admite como valores 'B' (negrita), 'I' o una cadena vaca (normal) y permite especificar el estilo del texto (en ndice del documento) con que se visualizar el enlace hacia la posicin sealada por el marcador. Por ltimo el parmetro color es un array que permite indicar en modo R,G,B el color del texto de los enlaces. En este ejemplo puedes ver una muestra de las posibilidades de esta opcin.
ejemplo356.php Ver cdigo fuente

Fuentes tipogrficas
Para generar las nuevas fuentes es necesario disponer del programa pfm2afm.exe que viene incluido en el paquete tcpdf. Concretamente en el directorio /tcpdf/fonts/utils

Creacin del fichero .afm


Este fichero, cuya extensin es el acrnimo de Adobe Font Metric contiene las informacin sobre ancho, alto y kerning de cada carcter de una fuente. El primer paso la utilizacin de una nueva fuente ha de ser la creacin de ese fichero. El procedimiento requiere lo siguiente: Copiar la fuente que pretendemos transformar al directorio C:/ServidoresLocales/Apache/htdocs/php/tcpdf/fonts/utils que es el que contiene el programa pfm2afm Acceder a la ventana de MS-DOS situarnos en el directorio C:/ServidoresLocales/Apache/htdocs/php/tcpdf/fonts/utils y ejecutar el siguiente comando: ttf2ufm -a nombre_de_la_fuente_TrueType.ttf nombre_del_nuevo_fichero donde nombre_de_la_fuente_TrueType.ttf es el nombre y extensin de la fuente que acabamos de incluir en ese directorio ynombre_del_nuevo_fichero una palabra cualquiera que permita asignar nombre a los nuevos ficheros. Por razones de comodidad lo aconsejable ser utilizar en mismo nombre de la fuente TrueType sin extensin.

Cuidado! En el caso de Ubuntu el proceso es idntico. Bastar con abrir el terminal, situarse en el directorio fuentes. Desde all se ejecuta el comando ttf2ufm de forma idntica a la descrita para MS-DOS.

Definicin de las fuentes


El directorio C:/ServidoresLocales/Apache/htdocs/php/tcpdf/fonts/utils incluye un script llamado makefont.php. La definicin de fuentes requiere la ejecucin de una de las funciones que contiene ese script llamada MakeFont() y que utiliza los siguientes parmetros: MakeFont( fuente_truetype, fuente_afm, incrustado, codificacion, modificadores )

donde fuente_truetype es el nombre, extensin y path de la fuente TrueType a utilizar (fichero .ttf), fuente_afm es el nombre del fichero.afm creado para esta misma fuente mediante ttf2ufm. Estos dos parmetros son obligatorios. Mediante el parmetro incrustado (por defecto true) se especifica si la fuente va a ser incrustada en los documentos pdf que la utilicen. El parmetro codificacin permite especificar el mapa de fuentes a utilizar. Si no se indica toma el valor por defecto que es cp1252. Por ltimo el paramtro opcional modificadores permite cambiar la codificacin de algunos caracteres.

La ejecucin de la funcin MakeFont() comentada anteriormente podra hacerse mediante un script similar a este:

<?php # incluimos el fichero makefont.php que est # en la ruta que se especifica (si lo tuvieramos en otra # ubicacin bastara cambiar el path del include include($_SERVER['DOCUMENT_ROOT']."/php/tcpdf/fonts/utils/makefont.php"); # ejecutamos la funcin MakeFont indicando como parametros # la ruta y el fichero ttf a convertir(la fuente trueType) # y como segundo parmetro la ruta y el nombre del fichero afm # creado en el proceso anterior MakeFont($_SERVER['DOCUMENT_ROOT']."/php/tcpdf/fonts/utils/bobcayge.ttf", $_SERVER['DOCUMENT_ROOT']."/php/tcpdf/fonts/utils/bobcayge.afm")){ ?>
cuya ejecucin de ese script dara como resultado la creacin en el directorio actual (es decir en el que contenga el script anterior) de dos ficheros con el mismo nombre y extensiones .z y .php. para poder usar la nueva fuente es necesarios incluirlos (ambos) en el directorio/tcpdf/fonts/.

Diferentes tipografas
Lo habitual es que entre las fuentes TrueType de un tipo determinado existan varios ficheros. Uno para la fuente normal, otro para la cursiva, etctera. Cuando se trabaja con este tipo de fuentes y se pretende usar estilos distintos, lo aconsejable es definir una fuente para cada tipo y tratarlos, a la hora de escribir el cdigo de los script como fuentes independientes. De esta forma podramos tener parejas de ficheros del estilo: fxx_normal.z y fxx_normal.php; fxx_cursiva.z y fxx_cursiva.php, etctera. A la hora de utilizarlas se hara como si se tratara de fuentes de distintas familias y habra de evitarse incluir el estilo en SetFont. Por tanto, la sintaxis de la asignacin de fuentes habra de ser: $objeto->SetFont("nombre","", 9);

dejando el valor del segundo parmetro (estilo) como una cadena vaca. La nica excepcin a esta norma sera el caso del subrayadado que no requiere otra cosa que asignar el valor U al parmetro estilo.

Precauciones con las fuentes


El uso de fuentes externas puede producir efectos indeseados si, por alguna circunstancia, tal como ocurre en los ejemplos la fuente utilizada carece de algunos carcteres (ees, letras con tilde, smbolos). Conviene tenerlo en cuenta para evitar que la eleccin de una tipografa pueda afectar a los contenidos del documento.
ejemplo357.php

En estos dos ejemplos pueden verse los resultados -con algunos problemas grficos- de la sustitucin de las fuentes en algunos de los ejemplos de pginas anteriores.
ejemplo358.php ejemplo359.php

Ficheros MariaDB y/o MySQL Los servidores de bases de datos MariaDB y MySQL
Una de las opciones ms interesantes de PHP es la posibilidad de gestionar bases de datos alojadas en equipos remotos. Existen multitud de aplicaciones de servidor de bases de datos (FilePro, dBase, DBM, Microsoft SQL, PostgreSQL, mSQL, InterBase, MariaDB yMySQL, entre otros) y PHP dispone de recursos para el manejo de todas las mencionadas. Hemos optado por MySQL atendiendo a su disponibilidad en el servidor que aloja este dominio. MySQL utiliza el lenguaje SQL(acrnimo de Structured Query Language, es decir, Lenguaje estructurado de consultas) que hasta el momento ha

sido contemplado como un estandar para gestin de bases de datos. Falta por ver cual ser la evolucin futura en cuanto a gratuidad y servicio. El cambio de propietarios ha generado una cierta inquietud en ese sentido en muchos de los mentideros de la red. Sea cual fuere esa evolucin futura los scripts desarrollados para MySQL son perfectamente compatibles con MariaDB, servidor de bases de datos desarrollado dentro de Open Database Alliance, un consorcio neutral diseado para convertirse en el centro de la industria de la base de datos de cdigo abierto.

Cuidado! Todos los ejemplos que incluimos aqu funcionan sin necesidad de hacer ninguna modificacin en servidores de bases de datos MariaDB.

Bases de datos y tablas


Si es este tu primer contacto con el mundo de las bases de datos, quiz sea importante conocer su argot ya que en adelante tendremos que referirnos a tablas, campos, registros e ndices y quiz no est de ms repasar un poco esas ideas. Pensemos en la base de datos como un armario archivador directorio que alberga una serie de cajones tablas en los que se permite almacenar nicamente documentos de idntico tipo registros. Imaginemos, por poner dos ejemplos, que las solicitudes de matrcula de un centro tienen un formato unificado y se guardan mismo cajn y que, con idntico criterio, se haga lo mismo con los expedientes de los profesores . Cada uno de los hipotticos formularios de los supuestos anteriores tendra las mismas casillas campos, con la nica diferencia de que los datos contenidos en esos campos de igual forma, dimensin y tamao en todos los registros seran lo nico que diferenciara realmente las solicitudes de matrcula de dos alumnos. Una oficina bien organizada no se conformara con esto. A medida que crezca el nmero de solicitudes de los alumnos irn surgiendo las dificultades para localizar un registro (la ficha de un alumno). Sera una excelente idea organizar el archivo de tal forma que esa localizacin resulte lo ms fcil y rpida posible. Una clasificacin alfabtica ndice alfabtico o por fecha de nacimiento otro ndice podra facilitar sustancialmente las cosas. Las bases de datos MySQL disponen de todos esos rescursos. Cuando hemos instalado MySQL en el directorio C:/ServidoresLocales/mysql y durante el proceso de instalacin se cre un subdirectorio llamado data (C:/ServidoresLocales/mysql/data) destinado a albergar todas las bases de datos de nuestro servidor. En el caso de Ubuntu ese directorio es /var/lib/mysql. Cada una de las bases de datos que albergue el servidor estar contenida en un subdirectorio cuyo nombre coincide con el de la propia base de datos. Tanto en el caso de Windows como en el de Ubuntu, el instalador crea una base de datos llamada mysql y, por tanto un subdirectorio para contenerla. En Windows ser C:/ServidoresLocales/mysql/data/mysql mientras que en Ubuntu se trata de /var/lib/mysql/mysql. Si visualizamos los contenidos de ese subdirectorio podremos ver que mysql contiene una serie de ficheros en los que un mismo nombre se repite con tres extensiones diferentes: .frm, .MYD y .MYI. El directorio C:/ServidoresLocales/data

Las carpetas del subdirectorio data corresponden a cada una de las bases de datos que contiene

Cada una de las tablas que contiene una base de datos requiere tres ficheros de extensiones .frm, MYD y MYI

Cada fichero con extensin .frm contienen la estructura de una tabla. Es en alguna medida una especie de formulario en blanco oformulario tipo. Los ficheros que tienen extensin MYD contiene los datos y aquellos que acaban .MYI contienen los ndices de cada tabla que cumplen una funcin idntica a los ndices de los libros. Por medio de ellos resulta mucho ms rpido encontrar una determinada informacin y al igual que ocurre con los libros ndice general, onomstico, etctera pueden ser varios y de tipos distintos. La base de datos mysql creada durante la instalacin incluye una serie de tablas necesarias para la gestin del servidor. Una de ellas (puedes verla en la imagen) es la tabla user la ms importante para nuestros fines que contiene informacin relativa a los usuarios del servidor de base de datos tales como: permisos y restricciones de acceso, nombres usuarios, contraseas, etctera.

Cuidado! El uso de los tres ficheros anteriores, es condicin de las tablas tipo MyISAM .Otros tipos, que veremos en temas posteriores, tales como InnoDB almacenan la informacin con una estructura diferente.

Cmo empezar con las bases de datos?


Igual que en el caso del ejemplo de la secretara, lo razonable ser empezar creando nuestros armarios bases de datos para que posteriormente podamos ir diseando los documentos los campos y la estructura de cada uno de los tipos de impreso (tablas) que vayamos a manejar. En nuestros ejemplos nos referiremo siempre a una base de datos a la que llamaremos ejemplos y un usuario de nombre pepecon contrasea pepa que coinciden con el usuario creado por nuestro autoinstalador y por el referido en los procesos de instalacin autnoma y configuracin tanto del servidor MariaDB como de MySQL.

La tabla user
Activemos nuestro servidor MySQL de la forma que se indica aqu si tu sistema operativo es Linux Ubuntu. Si se trata de Windowspuedes ver aqu la forma de gestionarlo. Una vez activos el servidor MySQL y Apache ya podemos utilizar phpMyAdmin. Lo habamos instalado en un subdirectorio de htdocs llamado phpmyadmin. As que accedamos a travs de la direccin: http://localhost/phpmyadmin/ y se nos abrir una pgina como la que sigue: phpMyAdmin

Elegiremos la base de datos mysql. Al seleccionar mysql en el men de la izquierda y pulsar sobre mysql (en negro en la parte superior de la lista de tablas) aparecer la lista que est a la derecha de esta imagen.

All vemos la tabla user y un enlace activo que dice Examinar. Si pulsamos sobre l, podremos ver un contenido similar a este que vemos aqu debajo.

Como ves, hay cuatro usuarios y dos de ellos como nombre root y ninguna contrasea han sido creados automticamente durante la instalacin. El cuarto de ellos el usuario pepe es el que hemos creado durante el proceso de instalacin Esta configuracin es insegura ya que con los nombres de usuario por defecto root y sin contrasea cualquiera podra acceder y manipular las bases de datos. Ms adelante podremos borrar esos usuarios pero, por el momento, dejmoslos as y aadamos un nuevo usuario. Si pulsamos la opcin editar (el icono en forma de lpiz que hay a la derecha de la casilla de verificacin del usuario sin nombre se nos abrir una pgina como esta:.

Escribamos localhost en el campo Host, jose en el campo User, josefa en el campo Password y marquemos todas las opciones una lista bastante larga por cierto como YES (Y) y muy importante seleccionemos la funcin PASSWORD para el campo del mismo nombre. Una vez realizado el proceso anterior deber quedarnos como aparece en la imagen. Pulsaremos en el botn Contine que hay al final de la pgina y habremos dado de alta al usuario jose con todos los privilegios para gestionar las bases de datos. Si regresamos de nuevo a Examinar veremos que ya ha sido incluido el nuevo usuario y que el campo contrasea aparece encriptado como consecuencia de haber aplicado la funcin PASSWORD para garantizar la privacidad del usuario. MySQL requiere esta encriptacin. Respecto a los YES, la explicacin es sencilla. Esas opciones permiten habilitar permisos para determinadas operaciones dentro de las bases de datos y lo nico que hemos hecho ha sido conceder todas la facultades de gestin al usuario pepe.

Creacin de un fichero INCLUDE


En los scripts PHP, con los que manejemos las bases de datos, vamos a necesitar insertar continuamente: nombre del servidor, nombre de usuario y contrasea. Tanto la comodidad como la privacidad que hemos mencionado en pginas anteriores aconsejan guardar los datos de usuario en lugar seguro. As pues lo aconsejable ser crear un fichero llammosle mysql.inc.php idntico al que tenemos aqu debajo,(podemoscopiar y pegar) y que podramos guardar en un directorio seguro tal como habamos comentado aqu.

<?php $mysql_server="localhost"; $mysql_login="pepe"; $mysql_pass="pepa"; ?>

Campos y conexiones Conexin con el servidor de bases de datos


Antes de empezar a trabajar con bases de datos es imprescindible que ambos servidores Apache y MySQL estn activos. Como paso inicial hemos de interconexionar ambos servidores de forma que sea posible tranferir informacin de uno a otro. Para ello es necesario utilizar siempre una funcin PHP con la siguiente sintaxis: $conexion=mysql_connect(servidor, usuario, contrasea)

donde $conexion es la variable que recoge el identificador del enlace, servidor es la direccin del servidor de bases de datos, ("127.0.0.1" o 'localhost') , usuario es el nombre de uno de los usuarios registrados en la tabla user ("pepe" o "root") y contrasea la contrasea (en nuestro caso "pepa" "") . Estos tres valores cadenas de texto deben ir escritos entre comillas. Para cerrar la conexin utilizaremos la funcin: mysql_close ($conexion)

donde $conexion es el nombre de la variable en la que se recogi el indentificador del enlace en el momento de la apertura. Aqu tienes el cdigo fuente de un script que realiza la apertura de una conexin y despus la cierra y desde aqu puedes comprobar su funcionamiento. Si realizramos una segunda conexin (con los mismos argumentos) sin haber cerrado la anterior no se efectuar un nuevo enlacesino que nos devolver el anterior.

Sintaxis alternativa
Otra forma de efectuar la conexin es utilizar los valores registrados en el fichero mysql.inc.php lo hemos creado en la pgina anterior y eso requiere que insertemos en los scripts un include("C:/ServidoresLocales/Apache/seguridad/mysql.inc.php")(include("/var/seguridad/mysql.inc.php") en el caso de Ubuntu) o, si has elegido otra ubicacin, la ruta completa hasta el fichero en el que hemos guardado las claves de conexin y para el que te hemos sugerido el nombre de mysql.inc.php. En este supuesto como valores de los parmetros servidor, usuario y contrasea pondremos los nombres de las variables:$mysql_server, $mysql_login y $mysql_pass sin encerrarlas entre comillas. Aqu tienes el cdigo de un script que realiza la apertura de una conexin y despus la cierra y desde este enlace puedes comprobar el funcionamiento de esta sintaxis alternativa.

La instruccin OR DIE
Es esta una buena ocasin para hablar de una instruccin PHP que no hemos mencionado hasta el momento. Se trata de una opcin alternativa a exit() que, como acabamos de ver en un ejemplo, interrumpe la ejecucin de un script en el momento de ser ejecutada. Cuando se produce un error en la ejecucin de un script no poder establecer conexin con MySQL, por ejemplo no tiene sentido seguir ejecutndolo. Lo razonable ser interrumpir el proceso y advertir del error. Si aadimos or die ('mensaje') a la instruccin$conexion=mysql_conect('servidor','usuario','contrasea') (sin parntesis, ni comas, ni punto y coma, slo separado por un espacio) y ponemos el punto y coma de fin de instruccin despus de cerrar este ltimo parntesis $conexion=mysql_conect('servidor','usuario','contrasea') or die ('mensaje')

en el caso de que se produzca un error se interrumpir la ejecucin del script y aparecer en la ventana del navegador el texto incluido en mensaje. Este es el cdigo fuente de un script que produce un error la contrasea es incorrecta y que utiliza esta nueva sintaxis. Pero si lo ejecutas vers que aparece un mensaje de error generado por PHP. Este tipo de mensajes pueden deshabilitarse de la forma descrita aqu. Pero hay una tcnica mucho ms fcil. Bastar con insertar delante de la funcin una arroba (@) para evitar que aparezcan. En este otro script lo hemos incorporado y puedes comprobarlo aqui.

Informacin sobre bases de datos existentes


Antes de crear y/o borrar una base de datos puede ser conveniente y til comprobar si ya existe. PHP dispone de herramientas para conocer el nmero de bases de datos existentes en el servidor, as como sus nombres.Como es lgico siempre necesitaremos tener establecida una conexin con el servidor de bases de datos. $identificador=mysql_list_dbs($conexion)

dnde la variable $identificacor es un nuevo identificador imprescindible y previo a la determinacin del nmero y los nombres de las bases de datos existentes en el enlace abierto (identificado por $conexion). $numero=mysql_num_rows($identificador)

devuelve en la variable $numero el nmero de bases de datos existentes en el servidor y utiliza como parmetro ($identificador) el resultado obtenido mediante la funcin anterior. mysql_db_name($identificador, indice)

devuelve el nombre de la bases de datos identificada por el nmero indice que debe pertenecer al intervalo [0,$n). Fjate que i tiene que ser i<$n porque si, por ejemplo, $n=5 los cinco valores posibles de i seran: 0,1,2,3 y 4. Una lista completa de todas las bases de datos existentes en el servidor podra hacerse mediante el siguiente proceso: Abrir la conexin.

Invocar a mysql_list_dbs. Contar el nmero de bases de datos con mysql_num_rows Insertar un bucle: for ($i=0;$i<$num,$i++) Presentar la lista de nombres mediante un bucle que lea los diferentes valores de $i en mysql_db_name($identificador,$indice) Aqu tienes el cdigo fuente de un ejemplo completo y desde aqu puedes ejecutarlo

Crear una base de datos


La creacin de una base de datos tambin requiere una conexin previa y utiliza la siguiente sintaxis: mysql_query ("CREATE DATABASE nombre") O mysql_query ("CREATE DATABASE IF NOT EXISTSnombre")

dnde nombre es el nombre de la nueva base de datos. Esta funcin devuelve TRUE si la base de datos es creada, y FALSE si no es posible hacerlo. Si intentamos crear una base de datos con un nombre ya existente la funcin nos devolver FALSE. Aqu tienes el cdigo de un ejemplo de creacin de una base de datos. Si lo ejecutas dos veces podrs comprobar que en la segunda oportunidad te aparece el mensaje diciendo que no ha sido posible crearla. Para evitar esa incomodidad se suele usar la segunda de las sentencia. Cuando se incluye IF NOT EXISTS la base de datos se crea nicamente en el caso de no existir pero, a diferencia de la otra opcin, en caso de que ya existiera no produce ningn mensaje de error.

Borrar una base de datos


Para borrar una base de datos se requiere el uso de la siguiente funcin PHP: mysql_query ("DROP DATABASE nombre")

donde nombre es el nombre de la base de datos y debiendo ponerse toda la cadena del parntesis entre comillas. Esta funcin devuelve TRUE cuando se ejecuta con xito, y FALSE en el caso contrario. Este es el cdigo de un script que puede borrar la base creada anteriormente. Igual que ocurra al tratar de crearla, si intentamos borrar una base de datos inexistente nos devolver FALSE.

Automatizar la conexin
Con nuestros conocimientos sobre PHP ya estamos en condiciones de hacer ms cmoda la conexin. Creemos una funcin que realice de forma automtica la conexin con MySQL y guardmosla en nuestro fichero mysql.inc.php .

<?php # estas son las variables anteriores $mysql_server="localhost"; $mysql_login="pepe"; $mysql_pass="pepa"; # creemos una nueva variable $c sin asignarle ningn valor # para que pueda recoger el identificador de conexin # una vez que se haya establecido esta $c; # escribamos la funcin que hace la conexin # como pretendemos que el valor del identificador # sea usado fuera de la funcin, para recuperar su valor # pasaremos ese valor por referencia anteponiendo & al # nombre de la variable

function conecta1(&$c){ # para usar las variables anteriores en la funcion # hemos de definirlas como globales global $mysql_server, $mysql_login, $mysql_pass; if($c=mysql_connect($mysql_server,$mysql_login,$mysql_pass)){ print "<br>Conexin establecida<br>"; }else{ print "<br>No ha podido realizarse la conexin<br>"; # el exit lo incluimos para que deje de ejecutarse # el script si no se establece la conexin exit(); } } # esta funcin asignar a $c el valor del identificador # # # # repetimos la misma funcin con otro nombre ahora quitaremos el mensaje de conexin establecida consideraremos que si no hay mensaje se ha establecido asi quedar limpia nuestra pgina

function conecta2(&$c){ global $mysql_server, $mysql_login, $mysql_pass; if($c=mysql_connect($mysql_server,$mysql_login,$mysql_pass)){ }else{ print "<br>No ha podido realizarse la conexin<br>"; exit(); } } ?>
Si sustituyes el contenido de tu mysql.inc.php por el que tienes aqu arriba puedes eliminar la lneas de comentario al hacerlo estaremos en disposicin de ejecutar scripts como este. Estos ejemplos utilizan cada una de las dos funciones.
Ver cdigo fuente Ver cdigo fuente

Depurando los procesos de creacin y borrado de bases de datos


Cuando intentamos crear una base de datos ya existente o borrar una inexistente las funciones mysql_query nos devuelven FALSE pero esa respuesta no nos dice la causa por la que no ha sido posible la ejecucin de la instruccin. Sera mucho ms interesante comprobar la existencia o inexistencia de una base de datos antes de ejecutar esas instrucciones y que despus de la comprobacin se nos presentara un mensaje informativo. MySQL dispone de una sentencia para este fin, pero aunque la vamos ver ms adelante olvidmosnos de su existencia e intentemos crear nuestro propio script de comprobacin. Combinando las instrucciones anteriores no resulta difcil hacerlo. Aqu tienes un ejemplo de cdigo para efectuar esa comprobacin al crear una base de datos y este otro cdigo es para el caso de borrado. Puedes experimentar con estos scripts, sustituirlos por otros propios en los que utilices tus propias funciones. Nada es absoluto.

Las bases de datos de nuestros ejemplos


En las pginas siguientes vas encontrarte con una serie de ejemplos. Por razones obvias no vamos a incluir aqu el acceso a los scripts que permiten la creacin, modificacin y borrado de tablas. Lo que si haremos ser incluir enlaces que permitan visualizar el cdigo fuente utilizado en esos procesos. Aqu tienes el script mediante el se crea la base de datos que utilizaremos en nuestros ejemplos.

Cdigo fuente creacin de base de datos

este otro cdigo Pulsa en este enlace para que cree automticamente la base de datos que va a contener los sucesivos ejemplos que hemos incluido en estos materiales.

Pasos previos a la creacin de tablas


Conocidos los procesos de creacin, listado y borrado de bases de datos ya estamos en disposicin en empezar a tratar lo relativo a las tablas. Es muy necesario conocer los diferentes tipos de campos que pueden contener las tablas de MySQL. Saber las posibilidades que ofrece cada uno de ellos ser fundamental a la hora de disear una tabla. En ese momento tendremos que decidir qu campos son necesarios, cul es tipo requerido, cules han de ser sus dimensiones y tambin cules de ellos requerirn ser tratados como ndices. Tipos de campo bien elegidos y un tamao adecuado a las necesidades reales de nuestro proyecto son las mejores garantas para optimizar el tamao de la tabla y para hacerla realmente eficaz. El grado de eficiencia de una base de datos suele ser directamenteproporcional al tiempo invertido en el anlisis de la estructura de sus tablas.

Tipos campos en MySQL


MySQL tiene habilitados diversos tipos de campos que en una primera aproximacin podran clasificarse en tres grupos: Campos numricos Campos de fecha Campos de cadenas de caracteres

Campos numricos
MySQL soporta los tipos numricos exactos (INTEGER, NUMERIC, DECIMAL, y SMALLINT) y los tipos numricos aproximados(FLOAT, DOUBLE precision y REAL). Los campos que contienen nmeros enteros admiten el parmetro UNSIGNED, que implica que no admita signos, por lo que solo aceptara enteros positivos. Todos los campos numricos admiten el parmetro ZEROFILL cuya funcin es completar el campo con ceros a la izquierda hasta su longitud mxima. Tipos de campos numricos enteros Estos son los distintos tipos de campos numricos enteros que admite MySQL. Los parmetros sealados entre corchetes son opcionales. TINYINT [(M)] [UNSIGNED] [ZEROFILL]
Nmero entero muy pequeo. Con la opcin UNSIGNED puede tomar valores entre 0 y 255. En caso contrario, puede estar comprendido entre -128 y 127. El parmetro ZEROFILL slo tiene sentido junto con la opcin UNSIGNED ya que no es habitual rellenar los nmeros negativos con ceros a la izquierda del signo. El valor por defecto de parmetro M (nmero de cifras) es 4 si no est activada la opcin UNSIGNED. Si esta opcin estuviera activada el valor por defecto seraM=3. Para valores de M >valor por defecto reajusta el tamao al valor por defecto. Si se asigna a M un valor menor que cuatro limita el nmero de caracteres al tamao especificado considerando el signo slo en los nmeros negativos. Por ejemplo, si M=3 admitira 148, pero si intentamos insertar -148 recortara por la izquierda y solo insertara -14. Si intentamos insertar un valor fuera de rango registrara el valor dentro del rango ms prximo a l. P. ej.: Si tratamos de insertar el valor 437 escribira 127 255, este ltimo en el caso de tener la opcin UNSIGNED. Si pretendiramos insertar -837 con la opcin UNSIGNED escribira 0 y sin ella pondra -128. El tamao de un campo TINYINT es de 1 byte.

SMALLINT [(M)] [UNSIGNED] [ZEROFILL]


Nmero entero pequeo. Con la opcin UNSIGNED puede tomar valores entre 0 y 65 535. En caso contrario, puede estar comprendido entre -32 768 y 32 767. Son vlidos los comentarios hechos para TINYINT, excepto los relativos a los valores por defecto de M que en este caso seran 6 5. Su tamao es de 2 bytes.

MEDIUMINT [(M)] [UNSIGNED] [ZEROFILL]


Nmero entero mediano. Con la opcin UNSIGNED puede tomar valores entre 0 y 16 777 215. En caso contrario, puede estar comprendido entre -8 388 608 y 8 388 607.

Tambin son vlidos los comentarios hechos para TINYINT, excepto los relativos al valor por defecto de M que en este caso seran 8. Su tamao es de 3 bytes.

INT [(M)] [UNSIGNED] [ZEROFILL]


Nmero entero. Con la opcin UNSIGNED puede tomar valores entre 0 y 4 294 967 295. En caso contrario, puede estar comprendido entre -2 147 483 648 y 2 147 483 647. Son vlidos todos los comentarios de los casos anteriores. Su tamao es de 4 bytes.

INTEGER [(M)] [UNSIGNED] [ZEROFILL]


Es un sinnimo de INT

BIGINT [(M)] [UNSIGNED] [ZEROFILL]


Nmero entero grande. Con la opcin UNSIGNED puede tomar valores entre 0 y 18 446 744 073 709 551 615. En caso contrario, puede estar comprendido entre -9 223 372 036 854 775 808 y 21 474 839 223 372 036 854 775 807 647, pero al usarlo desde PHP estar sujeto a las limitaciones mximas de los valores numricos de este. Son vlidos todos los comentarios de los casos anteriores. Su tamao es de 8 bytes.

Nmeros de coma flotante


Por la estructura binaria de los microprocesadores y habida cuenta de que algunos nmeros no enteros sin ir ms lejos, el 0.1 requeriran infinitos caracteres binarios para su representacin exacta, se hace necesario introducir un redondeo en su tratamiento informtico y como consecuencia de ello asumir que se generan errores de medida. Esta circunstancia oblig al tratamiento de los nmeros decimales mediante el llamado Standar de Aritmtica de Punto Flotante, un algoritmo definido por la IEEE (Institute of Electrical and Electronics Engineers) que unific los procesos de representacin de nmeros en ordenadores con lo que son uniformemente controlables los errores introducidos. El Standar de Aritmtica de Punto Flotante estableci dos niveles de precisin: Precisin Simple, en la que todo nmero debe ser almacenado en 32 bits (4 bytes). Doble precisin, en la que los nmeros se almacenan en 64 bits (8 bytes). Campos nmericos de coma flotante Estos son los distintos tipos de campos numricos de coma flotante que admite MySQL. Los parmetros sealados entre corchetes son opcionales.

FLOAT(x) [ZEROFILL]
Nmero de coma flotante. Ignora la opcin UNSIGNED, pero s acepta ZEROFILL, por lo que debe prestarse atencin a estas opciones ya que no sera demasiado habitual una presentacin como esta: 000-3.47 El valor de x especifica la precisin. Si x<=24 ser de precisin simple. cuando 24 <x <=53 lo convertir automticamente a doble precisin. Cuando no se especifica el valor de x considera el campo como de precisin simple. Su tamao es de 4 bytes si x<=24 y de 8 bytes cuando 24 <x <=53

FLOAT [(M,D)] [ZEROFILL]


Nmero de coma flotante de precisin simple. Son vlidos los comentarios relativos a las opciones UNSIGNED y ZEROFILL del caso anterior. Toma valores en los intervalos siguientes: -3.402823466E+38 a -1.175494351E-38 0y 1.175494351E-38 a 3.402823466E+38. M es la anchura mxima de visualizacin y D es el nmero de decimales. Si M > 24 se convierte automaticamente a doble precisin FLOAT sin argumentos representa un nmero de coma flotante y precisin simple.

DOUBLE [(M,D)] [ZEROFILL]


Nmero de coma flotante de doble precisin. Siguen siendo vlidos los comentarios relativos a las opciones UNSIGNED y ZEROFILL del caso anterior. Toma valores en los intervalos siguientes:

-1.7976931348623157E+308 a -2.2250738585072014E-308 0y 2.2250738585072014E-308 a 1.7976931348623157E+308 M es la anchura mxima de visualizacin y D es el nmero de decimales. DOUBLE sin argumentos representa un nmero de coma flotante y precisin doble.

REAL [(M,D)] [ZEROFILL]


Es sinnimo de DOUBLE.

DECIMAL [(M[,D])] [ZEROFILL]


Es un nmero de coma flotante y doble precisin que se almacena como un campo de tipo CHAR. El valor es guardado como una cadena donde cada carcter representa una cifra. La coma y el signo menos de los nmeros negativos no son tenidos en cuenta en el valor de M -anchura mxima de visualizacin- aunque si se reserva -automticamente- espacio para ellos en campo. Si D vale 0 no tendr parte decimal. Los nmeros toman valores en el mismo intervalo especificado para DOUBLE. Los valores por defecto de M y D son respectivamente 10 y 0. Ocupan M+2 bytes si D > 0; M+1 bytes si D = 0 D+2 bytes si M < D

NUMERIC(M,D) [ZEROFILL]
Se comporta de forma idntica a DECIMAL

Campos de fecha
MySQL dispone de campos especficos para el almacenamiento de fechas. Son los siguientes: DATE
Recoge una fecha dentro del intervalo 01-01-1000 a 31-12-9999. MySQL guarda los valores DATE con formato AAAA-MM-DD (ao-mes-da) . Su tamao es de 3 bytes.

DATETIME
Recoge una combinacin de fecha y hora dentro del intervalo 00:00:00 del da 01-01-1000 y las23:59:59 del da 31-12-9999. MySQL guarda los valores DATETIME con formato AAAA-MM-DD HH:MM:SS (ao-mes-da hora:minutos:segundos) . Su tamao es de 8 bytes.

TIME
Recoge una hora dentro del intervalo -838:59:59 a 838:59:59. MySQL guarda los valores TIME con formato HH:MM:SS (horas:minutos:segundos) . Su tamao es de3 bytes.

YEAR 0 YEAR(2) o YEAR(4)


Recoge un ao en formato de cuatro cifras (YEAR o YEAR(4)) o en formato de dos cifras (YEAR(2))dentro del intervalo 1901 a 2155 en el caso de cuatro cifras o de1970 a 2069 si se trata de dos cifras. Su tamao es de 1 byte.

TIMESTAMP [(M)]
Recoge un tiempo UNIX. El intervalo vlido va desde 01-01-1970 00:00:00 a cualquier fecha del ao 2037. El parmetro M puede tomar los valores: 14 (valor por defecto), 12, 8, o 6 que se corresponden con los formatos AAAAMMDDHHMMSS, AAMMDDHHMMSS,AAAAMMDD, o AAMMDD. Si se le asigna la opcin NUL guardar la hora actual. Cuando se asigna 8 o 14 como parmetros es considerado como un nmero y para las dems opciones comouna cadena. Independientemente del valor del parmetro, un campo TIMESTAMP siempre ocupa 4 bytes.

Campos tipo cadena de caracteres


MySQL dispone de campos especficos para el almacenamiento de datos alfanumricos. Son los siguientes:

CHAR (M) [BINARY]


Es una cadena de tamao fijo que se completa a la derecha por espacios si es necesario. El parmetro M puede valer de 1 a 255 caracteres. Los espacios finales son suprimidos cuando la cadena es insertada en el registro. Los valores de tipo CHAR son elegidos y comparados sin tener en cuenta Maysculas / Minsculas y utilizan el juego de carcteres por defecto. Se puede utilizar el operador BINARY para hacer la cadena sensible a Maysculas / Minsculas. Se puede utilizar un campo tipo CHAR(0) con el atributo NULL para almacenar una valor booleano. En este caso ocupar un solo byte y podr tener nicamente dos valores: NUL "". Su tamao es de M bytes siendo 1 <= M <= 255 .

VARCHAR(M) [BINARY]
Es una cadena de caracteres de longitud variable. Su tamao mximo -especificado en el parmetro M- puede estar comprendido entre 1 y 255 caracteres. Con la opcin BINARY es capaz de discriminar entre Maysculas / minsculas.

TINYBLOB o TINYTEXT
TINYBLOB y TINYTEXT son cadenas de caracteres de longitud variable con un tamao mximo de 255 (28 - 1) caracteres. La diferencia entre ambas es que TINYBLOB discrimina entre Maysculas / minsculas, mientras que TINYTEXT no lo hace. Ninguno de los campos BLOB y TEXT admite valores por DEFECTO Las versiones de MySQL anteriores a 3.23.2 permiten utilizar estos campos para indexar. Si se intenta guardar en un campo de este tipo una cadena de mayor longitud que la especificada solamente se guardarn los M primeros caracteres de la cadena.

BLOB o TEXT
BLOB y TEXT son cadenas de caracteres de longitud variable con un tamao mximo de 65535 (216 - 1) caracteres. La diferencia entre ambas es que BLOB si discrimina entre Maysculas / minsculas, mientras que TEXT no lo hace. Ninguno de los campos: BLOB y TEXT admite valores por DEFECTO

MEDIUMBLOB o MEDIUMTEXT
MEDIUMBLOB y MEDIUMTEXT son cadenas de caracteres de longitud variable con una longitud mxima de 16.777.215 (224 - 1) caracteres. Son vlidas las especificaciones hechas en el apartado anterior. El tamao mximo de los campos de este tipo est sujeto a limitaciones externas tales como la memoria disponible y el tamao del buffer de comunicacin servidor/cliente.

LONGBLOB o LONGTEXT
Su nica diferencia con la anterior es el tamao mximo de la cadena, que en este caso es 4.294.967.295 (232 - 1) caracteres.

ENUM('valor1','valor2',...)
Es una cadena de caracteres que contiene uno solo de los valores de la lista (valor1, valor2, etc. etc.). A la hora de insertar un nuevo registro en una tabla, el valor a especificar para un campo de este tipo ha de ser una cadena que contenga uno de los valoresespecificados en la tabla. Si se tratara de insertar un valor distinto de ellos insertara una cadena vaca.

SET('valor1','valor2','valor3'...)
Es una cadena de caracteres formados por la unin de ninguno, uno o varios de los valores de una lista. El mximo de elementos es 64. Los valores que deben escribirse en los campos de este tipo han de ser numricos, expresados en forma binaria o en forma decimal. En el supuesto de que contuviera tres valores los posibles valores a insertar en un campo de este tipo a la hora de aadir un registro seran los siguientes.

Incluir valores Cdigo valor

Cadena Equiv. val1 val2 val3 val1 val2 val3 binaria decimal

Si Si Si

S S

1 1 0 0

1 1 0 1 0 1

1 0 1 1 1 0

111 011 101 110 100 010

7 3 5 6 4 2

No 1 S

No S

No S No S

No No S

NO 0

Si

No No 1

0 0

0 0

001 000

1 0

No No No 0

Creacin de tablas Tipos de tablas


MySQL permite usar diferentes tipos de tablas tales como: ISAM, MyISAM o InnoDB. Las tablas ISAM (Indexed Sequential Access Method) son las de formato ms antiguo. Estn limitadas a tamaos que no superen los 4 gigas y no permite copiar tablas entre mquinas con distinto sistema operativo. Las tablas MyISAM son el resultado de la evolucin de las anteriores adaptadas por MySQL durante mucho tiempo como el formato por defecto para sus servidores de bases de datos. En las versiones ms recientes de MySQL est cambiando es criterio y empiezan a verse versiones que incluyen InnoDB como formato por defecto. Las tablas del tipo InnoDB (desarrolladas por la compaa finlandesa InnoBase a la que deben su nombre) tienen una estructura distinta a la de MyISAM, ya que utilizan un slo archivo por tabla en ver de los tres habituales en los tipos anteriores. Incorporan dos de ventajas muy importantes: permiten realizar transacciones y definir reglas de integridad referencial. Hablaremos ms adelante de ello. La definicin de uno u otro formato (MyISAM o InnoDB) debe hacerse en el momento de la creacin de tabla y solo reguiere agregarType=MyISAM Type=InnoDB a la sentencia MySQL encargada de crearla.

Creacin de tablas
Las tablas son elementos de las base de datos. Por esa razn nos resultar imposible crear una tabla sin tener creada yseleccionada una base de datos. Es por eso que para la creacin de una tabla se necesitan los siguientes requisitos: Tener abierta una conexin con el servidor MySQL. Tener seleccionada una base de datos.

Conexin con el servidor


La hemos comentado en la pgina anterior. Recuerda que requera la funcin: $conexion = mysql_connect ( servidor, usuario, contrasea ) y que esa conexin ha de ser establecida antes de cualquier otra intervencin relacionada con accesos a bases de datos y tablas.

Seleccin de la base de datos


Dado que podemos manejar bases de datos distintas en estos materiales usaremos ejemplos y practicas es preciso decir a MySQL con qu base queremos trabajar. mysql_select_db(nombre_base_datos, $conexion)

donde nombre_base_datos es el nombre de la base de datos (puede ser una cadena entrecomillada o el nombre de una variable previa que contenga ese nombre). En este ltimo caso, como es habitual, el nombre de la variable no llevara comillas. El segundo parmetro$conexion es el identificador de conexin. Es decir, la variable creada al establecer la conexin con MySQL. Este valor debe insertarse siempre. La razn es que MySQL permite mantener abiertas varias, de forma simultnea, varias conexiones (podramos manejar ms de un servidor de bases de datos) y en esas condiciones no pueden darse ambigedades respecto a la base que pretendemos usar.

Creacin de una tabla


En todas las transacciones PHP MySQL habremos de utilizar instrucciones de ambos lenguajes. La forma habitual hay algunas excepciones en la que PHP se comunica con MySQL es por medio de la funcin genrica:

mysql_query("sentencia", $conexion);

donde la cadena sentencia contiene las instrucciones propias de MySQL y $conexion sigue siendo la variable que contiene el identificador de conexin. La creacin de tablas MySQL requiere una de estas dos sentencias: CREATE TABLE IF NOT EXISTS tabla (campo1, campo2,... ) Type=tipo o CREATE TABLE tabla (campo1, campo2,... )) Type=tipo

donde tabla es una cadena que contiene el nombre de la tabla que pretendemos crear, dnde campo1, campo2, etc. son las definiciones de los campos que pretendemos que contenga la tabla y tipo puede ser MyISAM o InnoDB segn el tipo de tabla que queramos crear. La nica diferencia entre ambas opciones es que la segunda dara un error si tratramos de crear una tabla preexistente (deberamos recurrir al procedimiento que hemos visto cuando crebamos bases de datos) mientras que la primera no da ese mensaje de error.

Definicin de campos en una tabla MySQL


Cada uno de los campos que vayamos a crear en una tabla requiere una definicin que debe contener lo siguiente: nombre del campo

Es una palabra cualquiera distinta para campo de la tabla y que normalmente suele elegirse aludiendo al contenido. Por ejemplo,fecha_nacimiento, nombre_del_perro, etctera. No va entre comillas nunca y MySQL diferencia maysculas/minsculas. Para utilizar como nombres de campo palabras reservadas del lenguaje MySQL por ejemplo, create debemos escribirlas entre ` `. Observa que no son comillas sino acentos graves. Lo ms aconsejable es evitar esta situacin. tipo y dimensiones

Los tipos de campos los hemos visto en la pgina anterior tienen que ajustarse a uno de los soportados por MYSQL. El tipo de campo se escribe a continuacin del nombre sin otra separacin que un espacio y requieren la sintaxis estricta correspondiente a cada tipo. Cuando se establezca una dimensin como parmetro opcional de un campo deben tenerse en cuenta algunos detalles: Su valor se escribe entre parntesis y se incluye despus del nombre del campo. Si en un campo numrico introdujramos valores que exceden los lmites, su valor no se registrara en la tabla sino el valor dellmite ms prximo correspondiente a ese tipo de campo. Supongamos un campo tipo TINYINT que permite valores comprendidos entre -128 y 127. Si asignramos en uno de sus registros un valor igual a 234 se escribira en la tabla 127 (el lmite superior) y si ponemos -834 escribira el lmite inferior, es decir, -128. En caso de cadenas, si el valor introducido sobrepasara la longitud mxima permitida, la cadena sera recortada y nicamente se registrara el nmero mximo de caracteres permitidos. flags del campo ( son opcionales) Puede utilizarse cualquiera de los permitidos para cada tipo de campo. Puedes verlos encerrados, entre corchetes, al lado de cada tipo de campo. Cuando sea necesario incluirlo han de escribirse inmediatamente despus del nombre del campo o de la dimesin (en los casos en que se incluya).

Ejemplo de creacin de una tabla

<?php /* nos conectamos con el servidor recogiendo en $c el identificador de conexin */ $c=mysql_connect ("localhost","pepe","pepa") or die ("Imposible conectar"); # seleccionamos una base de datos existente # de lo contrario nos dara un error # pondremos como nombre ejemplos nuestra base de datos # creada en la pgina anterior y usaremos $c # importante no olvidarlo mysql_select_db ("ejemplos", $c); /* ahora ya estamos en condiciones de crear la tabla podramos escribir ya la instruccin mysql_query y meter detro la sentencia MySQL pero, por razones de comodidad crearemos antes una variable que recoja toda la sentencia y ser luego cuando la ejecutemos. Definiremos una varable llamada $crear e iremos aadiendo cosas */ # la primera parte de la instruccin es esta (espacio final incluido $crear="CREATE TABLE IF NOT EXISTS "; # aadiremos el nombre de la tabla que ser ejemplo1 # fijate en el punto (concatenador de cadenas) que permite # ir aadiendo a la cadena anterior $crear .="ejemplo1 "; #ahora pongamos el parntesis (con un espacio delante) #aunque el espacio tambin podra detrs de ejemplo1 $crear .="( "; # insertemos el primer campo y llamemoslo num1 # hagamoslo de tipo TINYINT sin otras especificamos # sabiendo que solo permitira valores numricos # comprendidos entre -128 y 127 $crear .="num1 TINYINT , "; # LOS CAMPOS SE SEPARAN CON COMAS por eso # la hemos incluido al final de la instruccin anterior # ahora num2 del mismo tipo con dimensin 3 y el flag UNSIGNED # Y ZEROFILL que: cambiar los lmites de valores # al intervalo 0 - 255, y rellenar con ceros por la izquierda # en el caso de que el nmero de cifras significativas # sea menor de 3. # Fijate que los flags van separado unicamente por espacios $crear .="num2 TINYINT (3) UNSIGNED ZEROFILL, "; # en num3 identico al anterior aadiremos un valor por defecto # de manera que cuando se aadan registros a la tabla # se escriba automaticamente ese valor 13 en el caso # de que no le asignemos ninguno a ese campo # por ser numrico 13 no va entre comillas $crear .="num3 TINYINT (7) UNSIGNED ZEROFILL DEFAULT 13, "; # ahora un nmero decimal num4 tipo REAL con 8 digitos en total # de los cuales tres sern decimales y tambin rellenaremos con ceros # Pondremos como valor por defecto 3.14 $crear .="num4 REAL (8,3) ZEROFILL DEFAULT 3.14, "; # aadamos una fecha $crear .="fecha DATE, "; /* una cadena con un limite de 32 carcter con BINARY para que diferencie Pepe de PEPE */ $crear .="cadena VARCHAR(32) BINARY, "; /* un ultimo campo opcion del tipo ENUM que solo admita como valores SI, NO, QUIZA fijate en las comillas y en el parentesis cuidado...!! aqui no ponemos coma al final es el ltimo campo que vamos a insertar y no necesita ser separado. Si la pones dar un ERROR */ $crear .="opcion ENUM('Si','No','Quiza') ";

# solo nos falta aadir el parntesis conteniendo toda la instruccin $crear .=")Type=MyISAM"; /* tenemos completa la sentencia MYSQL solo falta ejecutarla mediante mysql_query ya que la conexin est abierta y la base de datos ya est seleccionada */ /* pongamos un condicional de comprobacin */ if(mysql_query($crear,$c)){ print "Se ha creado la base de datos<br>"; print "La sentencia MySQL podramos haberla escrito asi:<br>"; print "mysql_query("."\"".$crear."\" , $c);"; }else{ print "Se ha producido un error al crear la tabla"; } ?>

Consideraciones sobre IF NOT EXISTS


Esta variante de CREATE aplicable tanto en tablas como en bases de datos tiene la ventaja de no dar mensajes de error en caso de intentar crear una tabla o base ya existente, pero puede darnos algn sobresalto porque no advierte que la tabla no ha sido creada y puede darnos la sensacin de que puede haber reescrito una tabla anterior. Si se ejecuta reiteradamente el script no aparece ningn mensaje de error.
Cdigo fuente creacin de base de datos

Ver y modificar estructuras Visualizar la estructura de una tabla


Ver la estructura de una tabla utilizando MySQL
La sentencia MySQL que permiten visualizar la estructura de una tabla es la siguiente: SHOW FIELDS from nombre de la tabla

Lectura de resultados de sentencias MySQL


La sentencia SHOW FIELDS como prcticamente ocurre con todas las sentencias MySQL no devuelve los resultados en un formatolegible. Los valores devueltos requieren ser convertidos a un formato que sea interpretable por PHP. Esa traduccin se realiza de la siguiente forma: El resultado devuelto por MySQL a travs de una llamada mysql_query() es recogido en una variable, de la forma siguiente:$resultado=mysql_query(sentencia, $conexion) El resultado recogido en la variable $resultado, est estructurado en lneas. Por medio de la funcin: $linea =mysql_fetch_row ($resultado) se recoge en una variable ($linea) el contenido de la primera lnea situndose el puntero interno al comienzo de la lnea siguiente. Por esta razn la lectura completa del contenido de la variable $linea requiere llamadas sucesivas a mysql_fetch_rowhasta que haya sido leda la ltima de las lneas del resultado de la llamada a MySQL. La variable $linea tiene estructura de array escalar siendo cero el primero de sus ndices. Cuando el puntero interno demysql_fetch_row() alcance el final de la ltima lnea del resultado devolver como resultado FALSE. Por esa razn, la visualizacin de los resultados de una sentencia MySQL suele requerir dos bucles. Este es el esquema de la lectura:

$resultado=mysql_query(sentencia,$conexion); while($linea=mysql_fech_row($resultado){ foreach ($linea as $valor){ print $valor; } } tambin cabra usar una sintaxis alternativa similar a esta: $resultado=mysql_query(sentencia,$conexion); while($linea=mysql_fech_row($resultado)){ $matriz[]=$linea; } con lo que estaramos creando un array bidimensional con el contenido de los resultados de cada lnea. En este caso el primer ndicedel array $matriz sera un escalar que empezara en cero y se ira autoincrementando en una unidad en cada uno de los ciclos del buclewhile. El ejemplo tiene desarrollados ambos procedimientos.

<?php # asignamos a una variable el nombre de la base de datos $base="ejemplos"; # esta otra recoge el nombre de la tabla $tabla="ejemplo1"; # establecemos la conexin con el servidor $conexion=mysql_connect ("localhost","pepe","pepa"); # seleccionamos la base de datos mysql_select_db ($base, $conexion); #ejecutamos mysql_query llamando a la sentencia SHOW FIELDS $resultado=mysql_query( "SHOW FIELDS from $tabla",$conexion); # ejecutamos los bucles que comentamos mas arriba while($linea=mysql_fetch_row ($resultado)){ foreach($linea as $valor) { print $valor."<br>"; } } #tenemos que VOLVER a EJECUTAR LA SENTENCIA MySQL porque el puntero est # AL FINAL de la ultima lnea de los resultados print("<BR> Los nuevos resultados son <br>"); $resultado=mysql_query( "SHOW FIELDS from $tabla",$conexion); while($linea=mysql_fetch_row ($resultado)){ $matriz[]=$linea; } # leemos ahora el array bidimensional foreach ($matriz as $indice=>$mi_linea){ foreach ($mi_linea as $indice2=>$valor){ print "<i>Indice</i>: ".$indice." <i>Indice2</i>: ".$indice2." <i>Valor</i>: ".$valor."<br>"; } } # cerramos la conexion con el servidor mysql_close($conexion); ?>
ejemplo373.php

El procedimiento anterior nos facilita informacin sobre la estructura de la tabla pero quiz no lo haga con toda la claridad que fuera de desear. Para mejorar las prestaciones de la anterior existe una funcin alternativa que es:

$matriz =mysql_fetch_array($resultado) idntica en cuanto a requerimientos pero recogiendo en un array los resultados de la sentencia. Ese array tiene adems la peculiaridad de incluye cada uno de los valores en dos ndices distintos. Uno de los ndices es de tipo escalar. El otro es de tipo asociativo y sus ndices son los valores del campo de la tabla del que se han extraido los resultadosativos. En este ltimo caso incorporan como ndice el nombre del campo de la tabla del que se han extrado los resultados. $matriz =mysql_fetch_array($resultado, MYSQL_NUM) idntica a la anterior.La inclusin del parmetro MYSQL_NUM (sin comillas )limita sus resultado a los elementos del array de ndice escalar. $matriz =mysql_fetch_array($resultado, MYSQL_ASSOC) Tambin idntica a las anteriores. La inclusin del parmetro MYSQL_ASSOC (sin comillas )limita ahora los resultado a los elementos del array asociativo.

<?php # asignamos a una variable el nombre de la base de datos $base="ejemplos"; # esta otra recoge el nombre de la tabla $tabla="ejemplo1"; # establecemos la conexin con el servidor $conexion=mysql_connect ("localhost","pepe","pepa"); # seleccionamos la base de datos mysql_select_db ($base, $conexion); #ejecutamos mysql_query llamando a la sentencia SHOW FIELDS $resultado=mysql_query( "SHOW FIELDS from $tabla",$conexion); print("<br> Los resultados con mysql_fech_array<br><br>"); while ($linea=mysql_fetch_array($resultado)){ # leemos el array de resultados de cada una de las lineas extraidas del resultado foreach($linea as $indice=>$valor) { print ("El indice es: ".$indice." y el valor es: ".$valor."<br>"); } } /* vamos a separar los elementos escalares de los asociativos comprobando si es numrico el indice de cada array */ print "<br>Los elementos de array con indice numrico son estos<br>"; $resultado=mysql_query( "SHOW FIELDS from $tabla",$conexion); while ($linea=mysql_fetch_array($resultado,MYSQL_NUM)){ /* leemos el array de resultados de cada una de las lineas extraidas del resultado e insertamos un texto que nos ayude a ver lo contenidos de cada linea en la pantalla */ print "<br>Nueva lnea<br>"; foreach($linea as $indice=>$valor) { print ("El indice es: ".$indice." y el valor es: ".$valor."<br>"); } } /* visualizamos los resultados cuando el indice es NO NUMRICO */ print "<br>Los elementos de array con indice no numrico son estos<br>"; $resultado=mysql_query( "SHOW FIELDS from $tabla",$conexion); while ($linea=mysql_fetch_array($resultado, MYSQL_ASSOC)){ /* leemos el array de resultados de cada una de las lineas extraidas del resultado e insertamos un texto que nos ayude a ver lo contenidos de cada linea en la pantalla */ print "<br>Nueva lnea<br>"; foreach($linea as $indice=>$valor) {

print ("El indice es: ".$indice." y el valor es: ".$valor."<br>"); } } mysql_close($conexion); ?>
ejemplo374.php

Como habrs podido observar al ejecutar el ejemplo SHOW FIELDS nos permite conocer los propiedades de cada uno de los campos de la tabla: Field (nombre del campo), Type (incluye el tipo, el tamao y los flags), Null (especificara si el campo permite o no permite valores nulos), Key (especificara si ese campo es o es un ndice de la tabla) y Default (que incluira los eventuales valores asignados por defecto al campo).

Otras funciones informativas


Adems de la informacin extraida mediante mysql_fetch_array y mysql_fetch_row el resultado de la ejecucin de la sentencia SHOW FIELDS puede proporcionarnos informacin incluyendo con parmetro $resultado a travs de las siguientes funciones: mysql_num_fields ($resultado) Est funcin en la que $resultado es el identificador de resultado devuelve el nmero de campos de la tabla. mysql_num_rows ($resultado) Devuelve el nmero de filas del resultado. mysql_field_table($resultado, 0) Devuelve el nombre de la tabla. Observa que se pasa con ndice 0 ya que esta informacin parece ser la primera que aparece en la tabla. mysql_field_type($resultado, $indice) Nos devuelve el tipo de campo correspondiente a la posicin en la tabla sealada por el ndice $indice. Dado que la informacin deprimer campo est en el ndice 0, el ltimo valor vlido de $indice ser igual al nmero de campos menos uno. mysql_field_flags($resultado, $indice) Nos devuelve los flags del campo correspondientes a la posicin en la tabla sealada por el ndice $indice. Se comporta igual que la anterior en lo relativo a los ndices. mysql_field_len($resultado, $indice) Nos devuelve la longitud del campo correspondiente a la posicin en la tabla sealada por el ndice $indice. Igual que las anteriores en lo relativo a los ndices. mysql_field_name($resultado, $indice) Nos devuelve el nombre del campo correspondiente a la posicin en la tabla sealada por el ndice $indice. En lo relativo a los ndices su comportamiento es idntico a las anteriores.

Liberando memoria
Si queremos liberar la parte de la memoria que contiene un identificador de resultado, bastar con que insertemos la siguiente instruccin: mysql_free_result($resultado)

Este proceso debe ser posterior a la visualizacin de los resultados.


ejemplo375.php Ver cdigo fuente

Manipulacin de tablas
Borrar tablas
Las sentencias MySQL que permiten borrar una tabla son las siguientes: DROP TABLE IF EXISTS from nombre_de_la_tabla o DROP TABLE from nombre_de_la_tabla la diferencia entre ambas radica en que usando la primera no se generara ningn error en el caso de que tratramos de borrar una tabla inexistente. Aqu tienes el cdigo fuente de un ejemplo:
Ver cdigo fuente

Borrar uno de los campos de una tabla


La sentencia MySQL que permite borrar uno de los campos de una tabla es la siguiente: ALTER TABLE nombre_de_la_tabla DROP nombre_del_campo Es posible modificar la estructura de una tabla -en este caso borrar un campo- siguiendo un procedimiento similar a los anteriores. La nica diferencia estriba en utilizar la sentencia MySQL adecuada. Resulta obvio que el campo debe existir para que pueda ser borrado y si no existiera, es obvio tambin que se producira un error. Aqu tienes el cdigo fuente de un script que borra uno de los campos de una tabla.
Ver cdigo fuente

Aadir un nuevo campo a una tabla


Las sentencia MySQL que permite aadir un nuevo campo a una tabla es la siguiente: ALTER TABLE nombre_de_la_tabla ADD nombre del campo tipo [flags] La sintaxis es similar a la de la creacin de tablas: el nombre del campo debe ir seguido del tipo sin otra separacin que el espacio. Aqu tienes el cdigo fuente de un script que aade uno de los campos de una tabla.
Ver cdigo fuente

Aadir registros e ndices Manejando ndices


Es muy frecuente la utilizacin de ndices en las bases de datos. Pero... qu son los ndices? para qu sirven?. Si nos planteamos cul es la utilidad del ndice de un libro la respuesta podra ser:

Facilitar la bsqueda de datos Agilizar esa bsqueda La utilidad de los ndices en la bases de datos es bastante similar. Si seguimos con el ejemplo del libro veremos que caben las posibilidades de que tenga: Un solo ndice Varios ndices Algunos libros slo contienen un indice de contenidos. Sin embargo, es frecuente que tambin dispongan de otros, tales como:ndices analticos, ndices onomsticos, etctera. Cuando existe un solo ndice es obvio que puede decirse de l que es nico y cuando existen varios podemos decir que el ndice de contenidos es el ndice principal y los dems son ndices sin ms o ndices auxiliares. Coincidirs con nosotros en que en el ndice de contenidos de un libro de texto slo existe una referencia al Tema XIII en la que puede decir: Tema XIII pgina 314. Tambin coincidirs en que si en ese ndice, adems de lo anterior, dijera: Tema XIII pgina 714 nos encontraramos en una situacin confusa que nos obligara a preguntarnos: donde est el Tema XIII? En la pgina 314? En la 714? En ambas?. Es por eso que las tablas de las bases de datos no admiten nunca valores duplicados ni en los ndices nicos ni tampoco en losndices principales. Los ndices auxiliares tienen un comportamiento distinto. El ndice onomstico de un libro puede hacer referencia a varias pginas y puede tener duplicados. Por ejemplo: en un manual de Word puede existir un ndice onomstico en el que se asocie la palabramacros con las pginas 37, 234 y 832 siempre que en esas pginas existan contenidos que aludan a la palabra macro. Es por eso que las tablas de las bases de datos tambin admiten duplicados cuando se trata de ndices auxiliares.

Sintaxis de la definicin de ndices MySQL


Tanto al crear una tabla como al modificarla pueden aadirse ndices de la misma forma que se pueden insertar campos. La sintaxis (dentro de la sentencia MySQL que crea o modifica una tabla) es la siguiente: PRIMARY KEY(campo) donde campo es el nombre del campo que se establece como ndice principal de la tabla. El parmetro campo no va entrecomillado y PRIMARY KEY campo se incluye dentro de la sentencia CREATE como si se tratara de un campo ms, delimitado por comas, salvo que estuviera al final de la sentencia CREATE, en cuyo caso se omitira la coma final. Solo puede definirse un ndice primario por tabla y el campo utilizado ha de ser un campo no nulo. UNIQUE nombre (campo) Similar a PRIMARY KEY en cuanto a que no admite valores duplicados, pero con dos diferencias importantes. UNIQUE permite la creacin de ms de un ndice de este tipo por tabla y adems no requiere que los campos sobre los que se define sean no nulos. INDEX nombre (campo) Con esta sintaxis se crea un ndice secundario que debe tener un nombre (la posibilidad de que existan varios obliga resolver la posible ambigedad por medio del nombre) y como en los casos anteriores el campo que ser utilizado como ndice. INDEX nombre (campo(n)) Es un caso particular del anterior utilizable slo en el caso de que el campo ndice sea tipo CHAR o VARCHAR. Al tratarse de cadenas alfanumricas, mediante esta opcin es posible indexar por sus n primeros caracteres. El valor de n ha de ser menor o igual que 256 dado que el tamao mximo de un ndice est limitado en MySQL a 256 bytes. Otra limitacin de MySQL es el nmero mximo de ndices de una tabla que no puede superar de diecisis.

Los errores MySQL


PHP dispone de dos funciones que nos permiten detectar si una sentencia MySQL se ha ejecutado correctamente o si se ha producido algn error. Son las siguientes: mysql_errno($conexion) Indica el nmero de error que se ha producido en la transaccin MySQL realizada a travs del identificador de $conexion. Cuando elnmero de error es CERO significa que no se ha producido error. Otros valores bastante usuales son los siguientes: Error nmero 1050 Indica que hemos tratado de crear una tabla ya existente. Error nmero 1062 Indica que hemos tratado de introducir un valor con clave duplicada. Aparecer cuando tratemos de introducir un valor ya existente en un campo con ndice nico o principal. mysql_error($conexion) Devuelve la descripcin del error. Cuando el nmero de error es CERO devuelve una cadena vaca. Resulta de muchsima utilidad para depurar scripts.

Aadir registros a una tabla


La sentencia MySQL que permite aadir registros a una tabla es la siguiente: INSERT tabla (campo1,campo2,..) VALUES (valor1,valor2,..) Vamos a desarrollar un ejemplo completo de creacin de una tabla e insercin de registros utilizando diversos mtodos. Para ello seguiremos el siguiente proceso:

Creacin de la tabla
Empezaremos creando una tabla a la que llamaremos demo4 y que contendr los siguientes campos: Contador, que ser de tipo TINYINT(8) (nmero entero con un mximo de 8 dgitos) que contenga solo valores positivos, que se rellene automticamente con ceros por la izquierda y que se autoincremente cada vez que aadimos un registro. DNI, destinado a recoger valores de nmeros de DNI y que debe poder contener un mximo de ocho caracteres. Lo definiremos de tipo CHAR porque sus valores, pese a ser numricos, nunca van a requerir ningn tratamiento aritmtico. Nombre, Apellido1 y Apellido2 sern tres campos tipo VHAR de tamaos mximos respectivos de 20, 15 y 15 caracteres. Su finalidad la evidencian los nombres de campo. Les asignaremos el flag NOT NULL aunque no sea totalmente correcto dado que existen pases en los que se utiliza un solo apellido. Nacimiento ser un campo tipo DATE al que asignaremos como valor por defecto el de 1970-12-21. Recuerda que MySQL trata las fechas en ese orden (ao-mes-dia) y que admite como separadores tanto - como / por lo que son vlidas entradas con cualquiera de estos formatos: 1970-12-21 1970/12/21, aunque esta segunda es convertida automaticamente al primer formato por MySQL. Hora ser un campo tipo TIME al que asignaremos como valor por defecto el de 00:00:00. Recuerda que MySQL trata las horas en ese orden (hh:mm:ss) y que slo admite como separador :. Este campo est destinado a recoger la hora de nacimiento que aunque no tiene demasiado sentido es una buena excusa para introducir este tipo de campo. Sexo ser un campo tipo ENUM que tendr dos opciones: M (masculino) y F(femenino) y al que asignaremos M como valor por defecto. Fumador ser un campo tipo CHAR(0) que por su estructura -cadena de longitud cero- tendr dos nicas opciones de valor: NULL "", que, como veremos, son valores distintos para MySQL.

Idiomas ser un campo tipo SET definido para los valores: Castellano, Francs, Ingls, Alemn, Blgaro y Chino y que podr contener, como ocurre con los campos de este tipo, ninguno, uno o varios de los valores de la lista. ndice primario ser tratado como tal el campo DNI ya que se trata de un valor nico para cada persona y que, como tal, no puede tener duplicados. ndices auxiliares. Para ejemplificar su tratamiento consideraremos el campo Contador como ndice secundario. El cdigo fuente del fichero que genera esta tabla puedes verlo aqu debajo
Ver cdigo fuente

Aadir un registro
Cuando se aade un registro en una tabla los valores pueden aadirse en la propia sentencia MySQL o ser recogidos de los valores de variables PHP previamente definidas. En este ejemplo tienes el cdigo fuente del primero de los casos, en el que se aade a la tabla anterior un registro cuyos valores son:
DNI Nombre Apellido1 Apellido2 Nacimiento Sexo Hora Fumador Idiomas

1234 Lupicinio Servidor Servido 1954-11-23 M


Ver cdigo fuente

16:24:52 NULL

Presta atencin a los siguientes aspectos: En la sentencia no se alude al campo Contador. La razn es que se trata un campo AUTOINCREMENTAL y en ese tipo de campos los valores de los registros se escriben automticamente cada vez que se aade uno nuevo. El registro no se aadira si el valor de DNI coincidiera con otra ya existente en la tabla. Recuerda que habamos definido ese campo como ndice primario. Si no hubiramos incluido el aviso de error no tendramos ninguna referencia sobre el xito de la insercin y no detectaramos el problema de duplicidad. Sencillamente ocurrira que el registro no se aadira pero no nos enteraramos de tal circunstancia. Si en los valores de nombre y apellidos hubiramos insertado textos ms largos del tamao establecido para ellos al crear la tabla, las cadenas se recortaran y slo se aadiran -de izquierda a derecha- los n primeros caracteres de la cadena. Si en la fecha de nacimiento hubiramos introducido una cadena vaca nos habra puesto el valor por defecto, pero si hubiramos introducido un valor no vlido nos habra escrito 0000-00-00. Seran valores no vlidos en este caso: Los que tuvieran como valor de mes alguno no perteneciente al intervalo [1,12]. Los que tuvieran como valor de da un valor no vlido en concordancia con el mes y el ao. Admitira 29 en un mes defebrero slo en el caso de que el ao fuera bisiesto. Cuando la secuencia no coincidiera con esta AAAA-MM-DD. Cuando los separadores no fueran (-) o (/). En el campo Sexo si hubiramos introducido una cadena vaca nos habra puesto M (valor por defecto) pero si hubiramos intentado introducir un valor que no fuera M ni F nos habra insertado una cadena vaca. El campo hora se comportara de idntica forma al de fecha salvo que aqu la secuencia es: hh:mm:ss, que la hora debe pertenecer al intervalo [0,23], los minutos y los segundos a [0,59] y que el nico separador vlido en este caso es (:). El campo Fumador requiere particular atencin ya que se trata de un campo CHAR(0) que slo admite dos valores: NULL ocadena vaca, que como recordars son distintos para MySQL. Para introducir el valor NULL utilizando el procedimiento de insercin de este ejemplo tienes que escribir NULL, sin ponerlo entre comillas, tal como lo he hecho en el ejemplo . Para introducir una cadena vaca en este campo bastara con que pusieramos '' (ojo no es una comilla doble es la comilla sencilla (') repetida dos veces! Date cuenta de que si pusiramos comillas dobles tendramos un error ya que hay unas comillas dobles delante delINSERT que

se cierran al final de la sentencia MySQL y que no podemos volver a escribirlas entre ambas para evitar unfalso cierre de la cadena que contienen. En este caso el valor del campo Idiomas puede contener valores decimales comprendidos entre 0 y 64 o entre sus equivalentes binarios que son 0 y 111111. El valor 64 lo justifica el hecho de que son seis los elementos que puede contener el campo (hemos definido: Castellano, Francs, Ingls, Alemn, Blgaro y Chino que son seis y que el caso de insertarlos todos requerira el nmero binario 111111, cuyo valor decimal es precisamente 64. El valor 3 significa lo mismo que su equivalente binario (11) o mejor (000011) lo cual quiere decir que, como el primer carcter de la derecha es uno el campo toma el primer elemento de la lista (Castellano), como el segundo (de derecha a izquierda) tambin esuno tomar tambin el segundo elemento de la lista (Francs) y por ser cero todos los dems no tomar ningn otro valor de la lista, con lo que la cadena resultante sera en este caso Castellano, Francs. Fjate tambin en que el valor 3 no lo hemos puesto entre comillas porque se trata de una expresin decimal. Qu ocurra si hubiera puesto 11? Lo habra interpretado como once (decimal) o como tres (binario)?. La solucin es simple: '11' (entre comillas) sera interpretado como binario, sin comillas como decimal. No es necesario introducir valores en todos los campos, es decir, que la lista de campos de la sentencia INSERT puede no contenerlos a todos. No es necesario escribir el nombre de los campos en el mismo orden en el que fueron creados pero si es imprescindible quecampos y valores estn escritos en la sentencia INSERT exactamente en el mismo orden y tambin que en esa sentencia elnmero de campos y el nmero de valores sea el mismo. Recuerda que los values tipo numricono se incluyen entre comillas, mientras que los no numricos tienen que estar contenidos entre comillas incluso en el caso de no se inserten directamente sino a travs de una variable PHP.

Aadir un registro a partir de datos contenidos en variables


Tambin es posible aadir registros a partir de valores contenidos en variables PHP. Esta opcin es, sin ninguna duda, la ms utilizada, ya que lo habitual ser escribir el contenido a aadir en un form y despus -a travs del method (POST o GET)pasar al script de insercin esos valores como variables PHP. Aqu tienes el cdigo fuente de un ejemplo con la tabla anterior.
Ver cdigo fuente

Quiz te resulten de alguna utilidad estos comentarios: Observa en el cdigo fuente que al insertar las variables en los VALUES de la sentencia MySQL ponemos cuando se trata de valores tipo cadena '$variable' (el nombre de la variable entre comillas) y cuando se trata de valores nmericos sin comillas. Si quieres introducir el valor NULL en un campo tipo VAR(0) define la variable as: $variable="NULL" y si quieres introducir unacadena vaca defnela de este otro modo:$var="''" -comillas dobles (") seguidas de dos comillas sencillas (') y para terminar otras comillas dobles (") y cuando hagas alusin a esa esta variable como un VALUE en la sentencia de insercin no la pongas entre comillas.

Variantes de la sentencia INSERT


La sentencia INSERT cuya sintaxis se indica ms arriba como: INSERT tabla (campo1,campo2,..) VALUES (valor1,valor2,..) permite algunos modificadores opciones tales como: INSERT [LOW_PRIORITY | DELAYED] [IGNORE] tabla (campo1,campo2,..) VALUES (valor1,valor2,..) de ellos LOW_PRIORITY y DELAYED son incompatibles por lo que solo cabe uno u otro pero no ambos. Veamos su utilidad. La insercin de registros y la lectura de una tabla son procesos incompatibles, pero cabe la posibilidad de que se intenten ejecutar simultneamente. No olvides que estamos en Internet y es perfectamente posible que desde

dos ordenadores distintos, dos personas distintas estn accediendo a la misma tabla simultneamente y que uno de los accesos sea de escritura, es decir: aadir,modificar o borrar campos en la tabla. Quin tiene preferencia de paso? Quien tiene que esperar?. Si la opcin LOW_PRIORITY est activada, el proceso de escritura esperar a que terminen los procesos de lectura activos, pero si est activa la opcin DELAYED el proceso de lectura se interrumpir automticamente para ceder el paso al de escritura. Respecto a la opcin IGNORE tiene utilidad cuando se trata de realizar una secuencia de inserciones. Si no est activa en el momento en el que aparezca una clave duplicada se interrumpir el proceso de insercin, por el contrario, si estuviera activa el proceso de insercin continuar con los siguientes registros de la secuencia, aunque -como es lgico- seguirn sin insertarse los registros con clave duplicada.

Tablas para pruebas


Aqu tienes comentado un script que permite agregar aleatoriamente y de forma automtica registros a la tabla demo4. Dado que en las pginas siguientes trataremos de consultas, va a resultarnos muy cmodo poder rellenarlas de forma automtica.
Ver cdigo fuente

Aadir a travs de formularios Los valores de SELECT MULTIPLE


La opcin SELECT MULTIPLE dentro de un form tpico de HTML permite elegir ninguno, uno o varios de los elementos de la lista. Basta con pulsar con el ratn sobre cada uno de los valores elegidos manteniendo pulsada la tecla Ctrl, es decir, puro Windows. Para recoger los valores de esa opcin se define -dentro de la etiqueta SELECT- un name tipo array. Bastara con escribir: SELECT MULTIPLE name=variable[ ] SIZE=6> Como ves, variable es el nombre de la variable (esta vez sin $ delante, recuerda que no estamos en PHP sino en HTML) y va seguidode [ ] precisamente para indicar que es un array. Lo que respecta a SIZE=6 no es otra cosa que el parmetro que indica cuntos elementos de la lista de opciones queremos que se visualicen simultneamente en la pgina. El elemento ms importante son los values de cada option dentro de ese select. Los hemos escrito as: <option value=1>Castellano <option value=2>Francs <option value=4>Ingls <option value=8>Alemn <option value=16>Blgaro <option value=32>Chino Fjate que hemos mantenido exactamente el mismo orden en el que han sido definidos en el campo SET de la tabla. Observa tambin los valores: 1, 2, 4, 8, 16 y 32 que son precisamente las potencias de 2: 2 ,2 ,2 ,2 ,2 ,2 ,y2
0 1 2 3 4 5 6

Al ir seleccionando valores, van aadindose al array. Por ejemplo. Si seleccionamos Francs y Blgaro el array sera este: var[0]=2,var[1]=16 Si sumamos esos valores (2 + 16) el resultado sera 18, y al convertir a binario este valor, resultar: 010010 que es como decirle a MySQL (mirando la cadena de derecha a izquierda, lo recuerdas?) que incluya los valores segundo (Francs) y quinto (Blgaro) del SELECT MULTIPLE que corresponden a las posiciones en las que la cadena binaria contiene un uno.

Creacin del formulario


El caso ms frecuente -casi el nico- es que los registros de una tabla se aadan utilizando un formulario y enviando desde l los datos a un script PHP que ejecute la opcin de aadir. Si no recuerdas el funcionamiento de este mtodo, pulsa aqu En el ejemplo hemos desarrollado un formulario para aadir registros a la tabla demo4 con las siguientes peculiaridades: Para los campos DNI, nombre y apellidos hemos utilizado input tipo texto y hemos recogido mediante la opcin name cada uno de los campos en una variable independiente. Para los campos Fecha de nacimiento y hora de nacimiento hemos utilizado tres opciones select en cada una de ellas. La finalidad de estas opciones no es otra que impedir la introduccin de fechas no vlidas (en realidad no lo impedimos totalmente ya que, tal como est confeccionado, podra introducirse 31 de febrero, o 31 de abril). Ese aspecto es mejorable, pero para hacerlo desde el propio formulario tendramos de recurrir a un lenguaje del lado del cliente (JavaScrpt por ejemplo). Los valores de esos tres campos (tanto en fecha como en hora) los recogemos en variables que son elementos de dos array escalares. El campo sexo la recogemos en input tipo radio y les asignamos valores M F que coinciden con los valores del campo ENUM de la tabla. Con el campo Fumador -opcin Fumador/No fumador - hacemos exactamente lo mismo, pero asignndoles valores 1 o 0 ya que el formulario no permite la opcin NULL cadena vacia. En el script posterior ser cuando modifiquemos los valores de esas variables. Para el campo Idiomas utilizamos una opcin select de tipo mltiple y para los values un pequeo truco que describimos aqu la izquierda. Pues bien, aqu tienes, cdigo fuente del formulario que hemos diseado
Ver cdigo fuente

Aadir nuevo registro con datos del formulario


Como recordars, cuando se enva el contenido de un formulario mediante el method=POST y se indica como action un fichero PHPlos valores enviados son recogidos en este ltimo fichero en variables de PHP que tienen como nombre $_POST['var'] o$HTTP_POST_VARS['var'] donde cada una de los ndices asociativos de los array (var) coinciden con los name de los diferentes campos del formulario. A partir de ah, bastara con depurar los valores recibos, recoger en variables los valores depurados e incluirlos en la sentencia MySQL INSERT -la hemos visto en la pgina anterior- para aadirlos a la tabla correspondiente. Aqu tienes comentado el script:
Aadir registros Cdigo fuente del script

En realidad, tal como habrs podido ver en el cdigo fuente, la depuracin ha sido la siguiente: Hemos creado un valor de fecha y hora en formatos MySQL vlidos de la forma que describimos un poco ms arriba. Hemos sumado todos los valores numricos recibidos en el array obtenido del SELECT MULTIPLE y hemos asignado el resultado a la variable depurada que recoge el valor a escribir en el campo Idiomas. La justificacin de esa suma la tienes al margen. La variable Fumador es la que tiene un poquito ms de complicacin. Vemosla con calma: Los valores que recibimos desde formulario son 1 o 0 y hemos de transformarlos en una cadena vaca o en NULL. Hemos insertado un operador condicional (un if... else) para convertir eso valores en: $var="'\N'" (comilla doble, comilla simple, barra invertida, N, comilla simple y comilla doble) $var="''" (comillas dobles, dos comillas simples y unas comillas dobles) Asignados los nuevos valores tenemos que recurrir a un pequeo truco. Venimos repitiendo que en la sentencia INSERT losnombres de las variables no numricas que contienen los values hay que escribirlos dentro de comillas simples, pero en el caso de un campo tipo CHAR(0) hemos de hacer una excepcin que sera no poner esas comillas al nombre de la variable. Al hacerlo as, se escribiran como valores en la sentencia de insercin uno de estos: ='\N' o =' ' (los valores de la variable) que al contenercomillas ya son interpretados por MySQL como una cadena.

Consultas en tablas Sintaxis MySQL de seleccin de registros


Las sentencias de seleccin de registros requieren utilizar entre otras palabras clave como las que enumeramos a continuacin. Observa que las hay dos tipos: obligatorias y opcionales. Observa tambin que algunas de las palabras clave son alternativas y por lo tanto, incompatibles en una misma sentencia. La insercin ha de hacerse respetando un orden tal y como se enumera aqu debajo. Si alterramos ese orden (p. ejemplo: colocando GROUP BY antes de WHERE) se producira un error y dejara de ejecutarse la sentencia. Los prrafos siguientes estn organizados a dos niveles. Las intrucciones del primero de ellas tienen carcter obligatorio en la sentencia de consulta. Las del segundo, sealadas con letra cursiva, son opcionales. SELECT Es la primera palabra de la sentencia de bsqueda y tiene carcter obligatorio. SQL_BIG_RESULT Es una clusula opcional que se usa para indicar al optimizador que el resultado va a tener una gran cantidad de registros. En ese caso, MySQL utilizar tablas temporales cuando sea necesario para optimizar la velocidad de gestin de la informacin. Esta clusula tambin puede ser utilizada dentro de GROUP BY. SQL_BUFFER_RESULT Es opcional y su finalidad es la de forzar a MySQL a tratar el resultado en un fichero temporal. Ese tratamiento ayuda a MySQL a liberar recursos ms rpidamente y es de gran utilidad (siempre desde el punto de vista de la rapidez) cuando es necesario un largo proceso de clculo antes de enviar los resultados al cliente. HIGH_PRIORITY Esta clusula, opcional da prioridad al comando SELECT sobre otros comandos que simultneamente pudieran estar intentando acceder a la tabla para escribir en ella (aadir o modificar registros). Si esta opcin est activa, los intentos de escritura que pudieran producirse de forma simultnea deberan esperar al final de este proceso para ejecutarse. campo1, campo2, ... Tienen carcter obligatorio y sealan los campos de la tabla que deben incluirse en la consulta. La consulta slo devolver informacin de aquellos campos que estn enumerados aqu. Si se desea incluir a todos campos bastar con excribir * en esta posicin. En este caso *tiene la condicin de carcter comodn cuyo significado es todos los campos. Los campos numricos pueden llevar asociadas funciones MySQL que devuelven informacin estadstica. La sintaxis de algunas de esas funciones es la siguientes: MAX(campo) Devuelve el mayor de los valores de ese campo de entre todos los registros de la la consulta. Los registros comparados puedes ser todos o una parte de ellos. Si la sentencia incluye la condicin GROUP BY, en cuyo caso devolver el mximo de cada grupo y si incluye la opcin WHERE solo sern comparados los registros que cumplan tal condicin. MIN(campo) Idntica a la anterior en cuanto a criterios de seleccin, esta funcin devuelve el manorde los valores del campo en el mbito establecido por las evuntuales condiciones que pueda incluir la sentencia. AVG(campo) Devuelve el valor promedio de todos los registros numricos seleccionados con los mismos criterios del caso anterior. SUM(campo) Devuelve la suma de todos los valores del campo seleccionado y en el mbito establecido por los parmetros de la consulta. STDDEV(campo) Devuelve la estimacin de la desviacin tpica de la poblacin formada por los valores del campo. COUNT(campo) Cuenta los valores no nulos del campo indicado. Cuando se aplica una de estas funciones el resultado de la consulta contiene una sola lnea, salvo que se incluya opcinGROUP BY, en cuyo caso devolver tantas lneas como grupos resulten. FROM tabla Esta expresin indica a MySQL el nombre de la tabla en la que debe efectuarse la consulta. WHERE definicion Esta instruccin tiene carcter opcional y su utilidad es la de filtrar la consulta estableciendo los criterios de seleccin de losregistros que debe devolver. Si se omite WHERE, la consulta devolver todos los registros de la tabla. En la tabla de ejemplos tienes informacin sobre las formas de definir los criterios de seleccin de esta opcin.

GROUP BY definicion Tiene carcter opcional y su finalidad es la de presentar los resultados de la consulta agrupados segn el criterio establecido en su definicin. Resulta de gran utilidad cuando se pretende obtener valores estadsticos de los registros quecumplen determinadas condiciones (las condiciones del agrupamiento). ORDER BY definicion Tambin tiene carcter opcional y su utilidad es la de presentar la informacin de la consulta ordenada por los contenidos de uno o varios campos. Siempre tiene como opcin complementaria de que en cada campo utilizado para la ordenacinpuede establecerse uno de estos criterios ASC (ascendente, es el valor por defecto) o DESC (descendente). Si no se establece ningn orden los resultados de la consulta aparecern en el mismo orden en el que fueron aadidos los registros. LIMIT m, n Esta clusula es opcional y permite establecer cuntos y cules registros han de presentarse en la salida de la consulta. Por ejemplo: LIMIT 4, 8 indicara a MySQL que la consulta debera mostrar OCHO registros contados a partir del quinto (s, el quinto porque LIMIT considera el primer registro como CERO). El criterio lmite se aplica sobre los resultados de la salida, es decir, sobre los resultados seleccionados, ordenados yfiltrados siguiendo los criterios establecidos por las clusulas anteriores. Si se escribe como un solo parmetro (LIMIT k), MySQL lo interpretar como que k es el segundo de ellos y que el primero es CERO, es decir: LIMIT 0, k

Algunos ejemplos de consultas


Las consultas de los datos y registros contenidos en una tabla ofrecen un amplsimo abanico de posibilidades a partir de las opciones descritas anteriormente. Veamos algunas de las posibilidades.

La consulta ms simple
Si utilizamos la sentencia SELECT * FROM tabla obtendremos informacin sobre todos los campos (*) y la salida estar en el mismo orden en el que fueron aadidos los datos. Si visualizas este ejemplo, vers que aparecen ordenados por el valor autonumrico del campo Contador lo cual, como ves, resulta coherente con la afirmacin anterior.
Ejecutar consulta Ver cdigo fuente

Consultando slo algunos campos


Ahora utilizaremos la sentencia SELECT campo1,campo2, ... FROM tabla y tendremos como resultado una lista completa, por el mismo orden que la anterior, pero slo mostrando los campos indicados.
Ejecutar consulta Ver cdigo fuente

Cuidado! En los comentarios contenidos en estos ejemplos puedes ver la forma en la que mysql_fetch_row ymysql_fetch_array tratan los ndices escalares de los resultados que producen los SELECT de MySQL. Los valores de los ndices se asignan a los contenidos de los campos por el mismo orden en el que estos se escriben en la sentencia SELECT. El campo1 (primero que se escribe) ser recogido por el elemento de ndice cero del array, el campo2 ser recogido con ndice uno y as sucesivamente

Consultando slo algunos campos y limitando la salida a n registros

Ahora utilizaremos la sentencia SELECT campo1,campo2, ... FROM tabla LIMIT (n, m) y tendremos como resultado una lista que contendr m registros a partir del n+1, por el mismo orden que la anterior, y mostrando los campos indicados.
Ejecutar consulta Ver cdigo fuente

Consultando slo algunos campos y ordenando la salida


Utilizaremos la sentencia MySQL de esta forma SELECT campo1,campo2, ... FROM tabla ORDER BY campo_n [ASC|DESC], campo_m [ASC|DESC] y tendremos como resultado una lista ordenada por el primero de los campos indicados en ORDER BY, y en caso de coincidencia de valores en ese campo, utilizaramos el criterio de ordenacin sealado en segundo lugar.
Ejecutar consulta Ver cdigo fuente

Consulta seleccionando registros


Utilizaremos la sentencia MySQL de esta forma SELECT campo1, ... FROM tabla WHERE condicin que nos devolver la lista de registros que cumplen la condicin indicada. Aqu tienes un ejemplo muy sencillo.
Ejecutar consulta Ver cdigo fuente

Consultas condicionadas
La clasula WHERE permite un variado abanico de condiciones, que trataremos de resumir aqu. Algunos de ellas son los siguientes:
Tipo Sintaxis de campo Numrico WHEREcampo=num Cadena WHEREcampo="cadena" Cdigo Ver fuente ejemplo Ver Ver Ver Ver Ver Probar Probar Probar Probar Probar

Operador

Descripcin Selecciona los registros que contienen en el campo un valor igual a num Selecciona los registros que contienen en el campo una cadena idntica a cadena (*) Selecciona los registros que contienen en el campo un valor menor a num Selecciona los registros que contienen en el campo una cadena cuyos n primeros caracteres sonmenores que los de la cadena, siendo n el nmero de caracteres que contiene cadena. (**) Selecciona los registros que contienen en el campo un valor menor O igual a num Selecciona los registros que contienen en el campo una cadena cuyos n primeros caracteres sonmenores que los de la cadena, siendo n el nmero de caracteres que contiene cadena y aade respecto al caso anterior la opcin de que en caso de que ambos valores fueran iguales tambin los presentara (**) Selecciona los registros que contienen en el campo un valor mayor a num Selecciona los registros que contienen en el campo una cadena cuyos n primeros caracteres sonmayores que los de la cadena, siendo n el nmero de caracteres que contiene cadena. (**)

= = < < <=

Numrico WHEREcampo<num Cadena WHEREcampo<"cadena"

Numrico WHEREcampo<=num

<= > >

Cadena

WHEREcampo<="cadena"

Ver

Probar

Numrico WHEREcampo>num Cadena WHEREcampo>"cadena"

Ver Ver

Probar Probar

>= >=

Numrico WHEREcampo>=num

Selecciona los registros que contienen en el campo un valor mayor o igual a num Ver Selecciona los registros que contienen en el campo una cadena cuyos n primeros caracteres sonmayores que los de la cadena, siendo n el nmero de caracteres que contiene cadena y aade respecto al caso anterior la opcin de que en caso de que ambos valores fueran iguales tambin los presentara (**) Selecciona los registros que contienen en el campo valores que coinciden con alguno de los especificados dentro del parntesis. Cuando se trata de valores no numricoz han de ir entre comillas

Probar

Cadena

WHEREcampo>="cadena"

Ver

Probar

IN

Numrico WHERE campoIN o (valor1,valor2..) Cadena

Ver

Probar

Numrico WHERE campoBETWEEN BETWEEN o valor1 AND valor2 Cadena

Selecciona los registros en los que los valores contenidos en el campo seleccionado estn comprendidos en el intervalo valor1 (mnimo) valor2 (mximo) incluyendo en la seleccin ambos extremos. Ver Cuando los contenidos de los campos son cadenas sigue los mismos criterios que se indican para los dems operadores de comparacin Selecciona los registros en los que los valores contenidos en el campo seleccionado son NULOS Selecciona los registros en los que los valores contenidos en el campo seleccionado son NO NULOS Ver Ver

Probar

IS NULL IS NOT NULL

Cadena Cadena

WHERE campo IS NULL WHERE campo IS NOT NULL

Probar Probar

(*) Cuando se trata de cadenas de caracteres, el concepto menor que significa anterior en la ordenacin de los caracteres segn su cdigo ASCII y mayor quesignifica posterior en esa misma ordenacin. (**) La discriminacin de Maysculas/Minsculas depender del tipo de campo. Recuerda que los tipo BLOB hacen esa discriminacin, mientras que los de tipo TEXT son insensibles a Maysculas/Minsculas.

Cuando se trata de comparar cadenas MySQL dispone de una potente instruccin (LIKE) que permite establecer los criterios de seleccin a toda o parte de la cadena. Su sintaxis contempla distintas posibilidades utilizando dos comodines>: % (que se comporta de forma similar al (*) en las bsquedas de Windows) y _ (de comportamiento similar a (?) en Windows). Aqu tienes algunas de sus posibilidades:
Cdigo Ver fuente ejemplo Ver Ver Ver Ver Probar Probar Probar Probar

Sintaxis WHERE campoLIKE '%cadena%' WHERE campoLIKE 'cadena%' WHERE campoLIKE '%cadena' WHERE campoLIKE '_cadena%'

Descripcin Selecciona todos los registros que contengan la cadena en el campo indicado sea cual fuere su posicin Selecciona todos los registros en los que el campo indicado que contengan la cadena exactamente al principio del campo Selecciona todos los registros en los que el campo indicado que contengan la cadena exactamente al final del campo Selecciona todos los registros en los que el primer caracter del campo puede ser cualquiera pero los siguientes han de serexactamente los indicados en cadena pudiendo ir seguidos de cualesquiera otros caracteres

El comodn (_) puede ir tanto al principio como al final y puede repetirse tantas veces como sea necesario. Por tanto sera correctoLIKE '___es%' y tambin LIKE 'a___es%' as como: LIKE '%a___es'. La clasula WHERE aun tiene ms opciones. Acepta mltiples condiciones vinculadas por los operadores lgicos AND, OR, NOT o sus sintaxis equivalentes: &&, || y !. El comportamiento de estos operadores es idntico al descrito para sus homnimos de PHP en esta pgina

Utilizando funciones sobre campos


Por medio de la sintaxis SELECT MAX(campo1), MIN (campo2), ... FROM tabla obtendramos UNA SOLA FILA cuyos valores seran los resultados de la aplicacin de las funciones a todos los registros del campo indicado. Aqu tienes un ejemplo que determina todos los valores de esos estadsticos aplicados al campo Contador de nuestra tabla demo4.
Ejecutar consulta Ver cdigo fuente

Aplicando la opcin GROUP BY


Tal como sealamos al margen, las funciones anteriores pueden aplicarse a grupos de registros seleccionados mediante un criterioGROUP BY (nombre del campo) En este ejemplo obtendremos los mismos parmetros estadsticos que en el anterior, pero ahora agrupados por sexo, lo que significara que obtendremos dos filas de resultados. Aqu tienes el ejemplo
Ejecutar consulta Ver cdigo fuente

Recuento de resultados
PHP dispone de dos funciones que permiten conocer el nmero de registros de la tabla afectados por una sentencia MySQL. mysql_num_rows ($c ) Esta funcin devuelve un valor numrico que recoge el nmero de registros que cumplen las condiciones establecidas en unaconsulta. Slo es vlido para sentencia tipo SELECT mysql_affected_rows($c ) En este caso la funcin devuelve tambin el nmero de registros afectados, pero slo en el caso de que la sentencia MySQL haya producido modificaciones en los contenidos de la tabla. Es decir, slo recoge resultados de sentencias que: aaden, modifican o borranregistros. mysql_result($resultado,num, campo) Esta funcin PHP permite obtener un solo campo de uno solo de los registros obtenidos como resultado de una consulta MySQL. El parmetro $resultado es la variable que recoge el resultado obtenido de la ejecucin de mysql_query de forma idntica a como lo hacamos en otras consultas. El valor num es un nmero entero que indica el nmero de fila de la que queremos extraer el valor contenido en uno de sus campos. El valor campo indica el nmero del campo que tratamos de extraer. Este nmero (la primera posicin siempre es cero) indica el nmero de orden del campo tal como est especificado en la sentencia SELECT. Si en esta sentencia se incluyera * (extraer todos los campos) considerara el orden en el que est creada la estructura de la tabla que los contiene. Este es el cdigo fuente de un ejemplo comentado y este un enlace de prueba del script.

Manejo de fechas en las consultas


MySQL dispone de algunas clusulas de gestin de fechas que pueden tener una gran utilidad a la hora de gestionar consultas. Son las siguientes: DATE_FORMAT( campo,formato) Las diferentes opciones de formato las tienes en la tabla. Es importante tener en cuenta que la sintaxis correcta es %Y (sin espacio) ya que si hubiera un espacio % Y interpretara la letra Y como un texto a incluir. CURDATE() Dentro de DATE_FORMAT se puede incluir -en vez del nombre del campo- una cadena en la que se indique una fecha en formatoYYYY-MM-DD hh:mm:ss. Puedes verlo en los ejemplos. De igual modo es posible sustituir el nombre del campo -o la cadena- por la funcinCURDATE() que recoge la fecha actual del sistema (nicamente da, mes y ao). A efectos de horas, minutos y segundos CURDATE() va a tomar el medioda de la fecha actual. CURTIME() Se comporta de forma similar a CURDATE(). Devuelve la hora actual del sistema que alberga el servidor MySQL en formato hh:mm:ss

CURRENT_TIMESTAMP() Se comporta de forma similar a CURDATE(). Devuelve la fecha y hora actual del sistema en formato YYYY-MM-DD hh:mm:ss NOW() Es un alias de CURRENT_TIMESTAMP(). Aqu tienes una tabla resumen y algunos ejemplos
Ver cdigo Ver ejemplo Probar Probar Probar Probar Probar Probar Probar Probar Probar Probar Probar Probar Probar Probar Probar

Formato Descripcin %d %e %D %m %c %M %b %y %Y %w %W %W %j %U %u Da del mes en formato de dos dgitos Da del mes en formato de uno dos dgitos Nmero de da seguido del sufijo en ingls Nmero del mes en formato de dos dgitos Nmero del mes en formato de uno o dos dgitos Nombre del mes (en ingls) Nombre del mes abreviado (en ingls) Nmero del ao en formato de dos dgitos Nmero del ao en formato de cuatro dgitos Nmero de da de la semana 0=Domingo ... 6=Sbado Nombre del da de la semana (en ingls) Nombre abreviado del da de la semana (en ingls) Nmero de da del ao en formato de 3 dgitos Nmero de semana del ao considerando el DOMINGO como primer da de la semana (en formato de dos dgitos) Nmero de semana del ao considerando el LUNES como primer da de la semana (en formato de dos dgitos)

Sintaxis

DATE_FORMAT(Nacimiento,'%d') Ver DATE_FORMAT(Nacimiento,'%e') Ver DATE_FORMAT(Nacimiento,'%D') Ver DATE_FORMAT(Nacimiento,'%m') Ver DATE_FORMAT(Nacimiento,'%c') Ver DATE_FORMAT(Nacimiento,'%M') Ver DATE_FORMAT(Nacimiento,'%b') Ver DATE_FORMAT(Nacimiento,'%y') Ver DATE_FORMAT(Nacimiento,'%Y') Ver DATE_FORMAT(Nacimiento,'%w') Ver DATE_FORMAT(Nacimiento,'%W') Ver DATE_FORMAT(Nacimiento,'%W') Ver DATE_FORMAT(Nacimiento,'%j') Ver

DATE_FORMAT(Nacimiento,'%U') Ver DATE_FORMAT(Nacimiento,'%u') Ver

La fecha para los ejemplos siguientes la extraemos de una variable del tipo:

$fecha="2005-10-12 14:23:42"
ya que la tabla no contiene campos de fecha que incluyan horas, minutos y segundos %H %k %h %I %i %s %r %T %p Hora con dos dgitos (formato 0 a 24 horas) Hora con uno dos dgitos (formato 0 a 24 horas) Hora con dos dgitos (formato 0 a 12 horas) Hora con uno dos dgitos (formato 0 a 12 horas) Minutos con dos dgitos Segundos con dos dgitos Hora completa (HH:mm:ss) en formato de 12 horas indicando AM PM Hora completa (HH:mm:ss) en formato de 24 horas Aade AM PM dependiendo de la Hora DATE_FORMAT($fecha,'%H') DATE_FORMAT($fecha,'%k') DATE_FORMAT($fecha,'%h') DATE_FORMAT($fecha,'%I') DATE_FORMAT($fecha,'%i') DATE_FORMAT($fecha,'%s') DATE_FORMAT($fecha,'%r') DATE_FORMAT($fecha,'%T') DATE_FORMAT($fecha,'% texto') DATE_FORMAT($fecha,'%p') Ver Probar

% texto Incluye el texto que se indica detrs del %

Se pueden combinar a voluntad varias opciones utilizando una sintaxis de este tipo: '% Hoy es: %d - %m - %Y % es %W % estamos en el mes de %M % <br>y van transcurridos %j % dias de este ao.<br>Son las %r'

Creacin de tablas a partir de la consulta de otra tabla


Es frecuente -podra decirse que es lo habitual- relacionar tablas mediante campos con idntico contenido. Supongamos que entre los individuos de nuestra tabla demo4 se pretende establecer un proceso de seleccin para elegir entre ellos un nmero determinado deastronautas, pongamos por caso. Supongamos tambin, que la seleccin va a constar de tres pruebas que sern juzgadas y calificadas por tres tribunales distintos.

Una primera opcin sera crear tres tablas una para cada tribunal e incluir en ellas todos los datos de cada uno de los individuos. Esa opcin es factible pero no es ni la ms cmoda, ni tampoco es la ms rpida ni la que menos espacio de almacenamiento necesita. No debemos olvidar que una tabla puede tener una enorme cantidad de registros. Una opcin alternativa sera crear tres nuevas tablas que slo contuvieran dos campos cada una. Por ejemplo el campo DNI y el campo Calificacin. Como quiera que el campo DNI ha de contener los mismos valores en las cuatro tablas y adems es un campo nicopodran crearse las nuevas tablas y luego copiar en cada una de ellas todos los DNI de la tabla original. Nos garantizara que no habra errores en los DNI y adems nos garantizara que se incluyeran todos los aspirantes en esas nuevas tablas. Aqu tienes el cdigo fuente de un script que crea esas tres tablas (a las que hemos llamado demodat1, demodat2 y demodat3.
Ver cdigo fuente

Una consulta conjunta de varias tablas


MySQL permite realizar consultas simultneas en registros situados en varias tablas. Para ese menester se usa la siguiente sintaxis:

SELECT tabla1.campo1, tabla2.campo2, ... FROM tabla1, tabla2

en la que, como ves, modificamos ligeramente la sintaxis ya que anteponemos el nombre de la tabla al del campo correspondiente separando ambos nombres por un punto, con lo cual no hay posibilidad de error de identificacin del campo incluso cuando campos de distinta tabla tengan el mismo nombre. Otra innovacin -respecto a los ejemplos anteriores- es que detrs de la clusula FROM escribimos los nombres de todas las tablas que est usando SELECT. A partir de ah se pueden establecer todo tipo de relaciones para las sentencias WHERE, ORDER BY y GROUP BY utilizando para ellocampos de cualquiera de las tablas sin otra particularidad ms que poner cuidado al aludir a los campos utilizando siempre la sintaxisnombre_tabla.nombre_campo. A modo de ejemplo hemos procurado comentarlo lnea a lnea aqu tienes un script PHP que hace una consulta conjunta de las tablasdemo4, demodat1, demodat2 y demodat3 y nos presenta una tabla con los datos personales y las puntuaciones de las tres pruebas as como las suma de puntos de las tres y, adems, ordena los resultados -de mayor a menor- segn la suma de las tres puntuaciones.
Ejecutar consulta Ver cdigo fuente

Los arrays de la sentencia SELECT


Aunque estn comentados en los cdigos fuente de los scripts queremos hacer algunas precisiones sobre los resultados de las consultas de tablas. Se trata de los ndices de los arrays que se obtienen mediante las funciones: mysql_fetch_array() y mysql_fetch_row(). Los ndices escalares, en ambos casos, cuanto tratan informacin obtenida mediante una sentencia SELECT coinciden con el orden en el que han sido establecidos los campos en esa instruccin concreta. De modo que el primer de esos nombres de campos sera asociado con el ndice cero de estos array, el segundo con el ndice 1 y as sucesivamente. En el caso del array asociativo devuelto por la primera de estas funciones, los ndices coinciden siempre con los nombres de los campos de los que han sido extrados los datos. En el caso de que la consulta afecte a varias tablas (recuerda que los campos se asignan poniendo tabla.campo (nombre de la tabla y nombre del campo) el ndice del array asociativo sera esa expresin con el punto incluido.

Modificar registros Sintaxis MySQL de modificacin de registros


Las sentencias MySQL que permiten la modificacin de registros en las tablas pueden incluir algunas de las siguientes clusulas que, al igual que ocurra en casos anteriores, pueden tener categora de obligatorias u opcionales. El orden en que deben estar indicadas ha de seguir la misma secuencia en la que estn descritas aqu. UPDATE Tiene carcter obligatorio, debe ser la primera palabra de la sentencia e indica a MySQL que vamos realizar una modificacin. LOW_PRIORITY Es opcional e indica a MySQL espere a que se terminen de hacer las consultas que en ese momento pudiera haber en proceso antes realizar la actualizacin. IGNORE Es opcional. Cuando se incluye en una sentencia el proceso de actualizacin no se interrumpe si aparece un conflicto de clave duplicada en uno de los registros en proceso. Simplemente ignora ese registro y contina con los siguientes Si no se incluye, el proceso de modificacin se interrumpe en el momento en que encuentre un conflicto de clave duplicada. Tanto con ignore como sin esa clusula, en el caso de duplicidad de clave NUNCA se efectan las modificaciones. tabla Es obligatoria y contiene el nombre de la tabla que pretendemos modificar. SET Tiene carcter obligatorio y debe estar delante de las definiciones de campo y valor. campo1 = valor1 Es obligatoria al menos una definicin. Indica el nombre del campo a modificar (campo1) y el valor que se asignar a ese campo. Si se pretende modificar ms de un campo se repetir esta definicin tantas veces como sea necesario, separando cada una de ellas por una coma. WHERE Es un campo opcional y su comportamiento es idntico al sealado al mencionar el proceso de consultas. ORDER BY Tiene idntica funcionalidad a la descrita al referirnos a consultas

Modificar un campo en todos los registros de una tabla


La sentencia MySQL, que permite modificar uno o varios campos en todos los registros de una tabla, es la siguiente: UPDATE tabla SET campo1=valor1, campo2=valor2

Cuidado! Hay que tener muy presente que con esta sentencia en la que no aparece WHERE se modificarn TODOS LOS REGISTROS DE LA TABLA y por lo tanto los campos modificados tendrn el mismo valor en todos los registros.

Algunas consideraciones sobre la sintaxis


Siempre que manejes PHP y MySQL debes tener muy presente lo siguiente: MySQL requiere SIEMPRE que los valores tipo cadena que incluyen campos de fecha vayan entre comillas. Por el contrario, losnumricos no deben llevar comillas. Presta mucha atencin a esto cuando escribas los valores directamente en la sentencia MySQL. Cuando pases valores desde una variable PHP debes tener muy en cuenta las consideraciones anteriores y si el contenido de la variable es una cadena que va a ser tratada como tal por MySQL tienes dos opciones para evitar el error:

Definir la variable as: $variable ="'valor'" (comillas dobles, comilla simple al principio y comilla simple, comilla doble al final) y poner en la sentencia MySQL el nombre de la variable sin entrecomillar, o Definir la variable PHP as: $variable ="valor" y al escribir el nombre de esa variable en la sentencia MySQL escribirlo entre comillas sencillas, es decir, as: '$variable' No pienses que es caprichoso el orden que hemos puesto en las comillas. Recuerda que al llamar a la sentencia MySQL, el contenido de la sentencia va entre comillas (que por costumbre son comillas dobles, por esa razn todo entrecomillado que vaya dentro de esa sentencia ha de usar comillas simples para evitar un error seguro). De ah que al definir una variable PHP en la forma $variable ="'valor'" las comillas dobles exteriores indican a PHP que se trata de una cadena, por lo que, al pasar la variable a MySQL ste recibir el contenido de la cadena que es, logicamente: 'valor' y en este caso las comillas forman parte del valor, razn por el que no es necesario escribir -en la sentencia MySQL- el nombre de la variable entrecomillado. En este primer ejemplo, hemos incluido una actualizacin de tablas que pondr puntuacin 7 en la primera de las pruebas a todos losaspirantes a astronautas de nuestro ejemplo. Es un caso de actualizacin sin la condicin WHERE y tiene el cdigo comentado.
Ejecutar la modificacin Ver cdigo fuente

Seleccin y modificacin de un solo registro


Es una de las opciones ms habituales. Es el caso en el que mediante un formulario asignamos una condicin a WHERE y simultneamente asignamos los nuevos valor del campo o campos elegidos. Requiere la siguiente sintaxis: UPDATE tabla SET campo1=valor1, campo2=valor2 WHERE condicin

La condicin es fundamental en esta opcin y normalmente aludir a un campo ndice (clave principal o nica), de modo que sea un solo registro el que cumpla la condicin. Podra ser el caso, en nuestro ejemplo, del campo DNI que por su unicidad garantizara que la modificacin solamente va a afectar a uno solo de los registros. El ejemplo siguiente nos permitir hacer modificaciones de este tipo en la tabla deomodat2. Observa el cdigo fuente y vers que mediante un simple recurso JavaScript, el script que realiza la modificacin nos reenva al formulario con un mensaje de confirmacin de la modificacin.
Ejecutar la modificaccin Ver cdigo formulario Ver cdigo script

Modificacin simltanea de un campo en cualquiera de los registros


Aqu tienes un ejemplo que permite visualizar el valor actual de todas las puntuaciones de la prueba 2 de los astronautas as como sus nombres y apellidos y DNI y en la cual se pueden modificar ninguno, uno, varios o todos los valores y posteriormente actualizarlos todos con los nuevos valores.
Ejecutar la modificaccin Ver cdigo formulario Ver cdigo script

Borrar registros y salvar datos Sintaxis MySQL para borrado de registros


La sintaxis MySQL para las sentencia de borrado de registros de una tabla puede contener las siguientes clusulas que, al igual que ocurra en casos anteriores, pueden tener categora de obligatorias u opcionales. La secuencia en la que deben estar indicadas en la sentencia es idntica al orden en que estn descritas aqu. DELETE Tiene carcter obligatorio. Debe ser la primera palabra de la sentencia e indica a MySQL que tratamos de borrar uno o msregistros. LOW_PRIORITY

Es opcional e indica a MySQL que espere para realizar la actualizacin a que terminen las consultas del fichero (en el caso de haber alguna en proceso). FROM Tiene carcter obligatorio y debe preceder a la definicin de la tabla en la que se pretende eliminar registros. tabla Es obligatoria e indica el nombre de la tabla en la que pretendemos efectuar el borrado o eliminacin de los registros. WHERE Es un campo opcional y su comportamiento es idntico al sealado en al mencionar el proceso de consultas. LIMIT n La opcin LIMIT es opcional y propia de MySQL. Su finalidad es limitar el tiempo de ejecucin del comando DELETE ya que cuando est activada devuelve el control al potencial cliente despus de borrar n registros, con lo que en procesos de borrados muy largos (ficheros de gran tamao) no obliga a esperar a borrado total para proceder a la consulta de la tabla. Cuando se utiliza esta opcin, la sentencia DELETE debe repetirse hasta que el nmero de registros pendientes de borrado sea inferior al valor de n.

Borrar todos los registros de una tabla


La sentencia MySQL que permite borrar todos los registros de una tabla es la siguiente: DELETE FROM tabla

Ten muy presente que con esta sentencia -en la que no aparece WHERE- se BORRARN TODOS LOS REGISTROS DE LA TABLA. Respecto a otras posibles opciones, no difiere en nada de lo indicado en la pgina anterior. Simplemente habra que sustituir en aquellos script UPDATE por DELETE. Borrar un registro no es otra cosa que un caso particular de modificacin.

Integridad referencial tras el borrado de una tabla


Recuerdas el ejemplo de las pruebas de seleccin de astronautas? Recuerdas que las tres tablas de puntuaciones haban sido creadas a partir de la tabla de datos de los aspirantes? Qu ocurrira si borrsemos uno o varios registros de una de ellas? Qu ocurrira se despus de crear esas tablas aadisemos nuevos aspirantes a la lista de candidatos? Es obvio que si no hacemos algo para evitarlo se perdera la integridad referencial la relacin uno a uno entre los registros de esas tablas. Ocurrira que no todos los individuos que estn incluidos en una de esas tablas lo estaran en las dems y por tanto, al ejecutar consultas o modificaciones posteriores correramos el riesgo de que se produjeran errores. Esa situacin es fcilmente evitable modificando ligeramente los scripts con los que se realizan los procesos de altas y bajas. Bastara con aadirles algunas sentencias que cada vez que se efecta un alta o baja en el fichero de datos personales efecten el mismo proceso en todos los dems ficheros relacionados con aquel. Aqu tienes comentado el cdigo fuente de la modificacin aadida al script que registra los nuevos aspirantes en el fichero de altas de la tabla demo4. Con esta modificacin se actualizaran automticamente los ficheros demodat1, demodat2 y demodat3 cada vez que se aadiera un nuevo aspirante. El formulario no requiere ninguna modificacin, Slo es necesario realizar los cambios en el script que realiza la insercin.
Aadir nuevo aspirante Ver cdigo fuente

Hecho este pequeo inciso -creemos que importante y necesario - continuaremos con la referencia al borrado de registros. En este ejemplo, tienes el cdigo fuente de un script que realiza el borrado de un registo mediante un formulario en el que se inserta el DNI tanto en la tabla demo4 como demodat1, demodat2 y demodat3 manteniendo la integridad referencial entre los cuatro ficheros.
Ver cdigo fuente

Borrar registros seleccionndolos de una lista


En el ejemplo siguiente tienes el cdigo para utilizar la clusula WHERE en un proceso de borrado de registros que presenta un formulario que contiene una lista con todos los registros actuales y una casilla de verificacin por cada uno. Al marcar las casillas y enviar el formulario el script que recibe los datos procede al borrado de todos los registros marcados en todas la tablas afectadas.
Ver formulario Ver script Ejecutar ejemplo

Guardar y recuperar bases de datos y o tablas


Aunque es perfectamente factible desarrollar scripts propios que permitan guardar y recuperar tanto las estructuras como los datos de una tabla de la base de datos completa, mencionaremos aqu una de las posibilidades ms cmodas de hacerlos. PhpMyAdmin es una magnifica herramienta para hacer y recuperar copias de seguridad. Si abrimos la utilidad http://localhost/phpmyadmin/ podremos ver los dos enlaces que ves en la imagen SQL y Exportar que permiten importar y exportar tanto estructuras como datos y estructuras.

Al pulsar sobre Exportar nos aparecer una pgina como esta:

donde podremos elegir una, varias o todas la tablas y que segn la opciones elegidas nos permite exportar estructuras y/o datos, segn las casillas de verificacin que tengamos marcadas. Adems nos permite elegir el formato en el que queremos guardar la copia en nuestro caso elegiramos SQL y tambin segn est o no activada la casilla de verificacin Enviar visualizar el fichero generado o guardarlo con el nombre que hayamos consignado en la caja de texto Plantilla del nombre del archivo.

Para restaurar datos y/o estructuras desde un fichero de seguridad creado mediante el proceso anterior usaramos la opcin SQL de la primera imagen. A travs de ella accederamos a una pgina cuyo contenido estamos visualizando en esta ltima imagen. Bastara pulsar en examinar, buscar el fichero de seguridad y pulsar contine. MySQL se encargara de restaurar en la base de datos a la que pertenezcan todas las tablas contenidas en esa copia.

Optimizacin de tablas
Cuando se ejecuta la sentencia DELETE -pese a que son eliminados los valores de los camposse conservan las posiciones de los registros borrados, con lo cual no se reduce el tamao de la tabla. Esas posiciones de registro sern utilizadas por MySQL para escribir los registros que se vayan aadiendo despus del proceso de borrado. Para eliminar esos registros vacos y reducir el tamao de una tabla, MySQL dispone de una sentencia que es la siguiente: OPTIMIZE TABLE tabla

Esta sentencia -que debe usarse despus de un proceso de borrado amplio- depura la tabla eliminando los registros inutilizados por el proceso DELETE, con lo que logra una reduccin del tamao de la tabla a su dimensin ptima.

Imgenes en tablas Imgenes en tablas


Peculiaridades de las tablas
Las tablas que han de contener imgenes deben tener campos del tipo BLOB, MEDIUMBLOB o LONGBLOB, (recuerda sus tipos) pudiendo elegir aquel de ellos que ms se adecue al tamao, en bytes, de las imgenes que se desean guardar en la tabla. En el ejemplo hemos incluido un campo BLOB para incluir la imagen, insertando tambin campos para recoger su nombre, su tamao (en bytes), su formato (el tipo de fichero transferido) as como un campo autoincremental.

<?php #el nombre de la tabla $base="ejemplos"; #definimos otra variable con el NOMBRE QUE QUEREMOS DAR A LA TABLA $tabla="fotos"; # establecemos la conexin con el servidor $conexion=mysql_connect ("localhost","pepe","pepa"); #Seleccionamos la BASE DE DATOS en la que PRETENDEMOS CREAR LA TABLA mysql_select_db ($base, $conexion);

$crear="CREATE TABLE IF NOT EXISTS $tabla ("; $crear.="num_ident INT(10) unsigned NOT NULL AUTO_INCREMENT,"; $crear.="imagen BLOB NOT NULL, "; $crear.="nombre VARCHAR(255) NOT NULL DEFAULT '',"; $crear.="tamano VARCHAR(15) NOT NULL DEFAULT '',"; $crear.="formato VARCHAR(10) NOT NULL DEFAULT '',"; $crear.="PRIMARY KEY (num_ident))type=MyISAM"; #Creamos la cadena, comprobamos si esa instruccin devuelve # VERDADERO o FALSO # y dependiendo de ellos insertamos el mensaje de exito o fracaso if(mysql_db_query ($base,$crear ,$conexion)) { echo "<h2> Tabla $tabla creada con EXITO </h2><br>"; }else{ echo "<h2> La tabla $tabla NO HA PODIDO CREARSE</h2><br>"; }; # cerramos la conexin... y listo... mysql_close($conexion); ?>
Aqu tiene el cdigo fuente que te permitira crear la tabla fotos e insertar automticamente algunas imgenes de ejemplo.
Ejemplo de transferencia de imagen

Transferencia de la imagen
El formulario para realizar la transferencia de la imagen no tiene particularidades. Es un formulario habitual para transferencia de ficheros. Lo nico reseable sera incluir un campo oculto en el que pudiera especificarse una restriccin en cuanto al tamao mximo permitido para cada imagen y que debe estar acorde con el tipo de campo utilizado en la tabla.

<FORM ENCTYPE="multipart/form-data" ACTION="ejemplo211.php" METHOD="post"> <INPUT type="hidden" name="lim_tamano" value="65000"> <p><b>Selecciona la imagen a transferir<b><br> <INPUT type="file" name="foto"><br> <p><b>Ttulo la imagen<b><br> <INPUT type="text" name="titulo"><br></p> <p><INPUT type="submit" name="enviar" value="Aceptar"></p> </FORM>
Ejemplo de transferencia de imagen

Comprobacin del tipo de imagen


Al transferir imgenes jpg png el type MIME que reciba el servidor es distinto segn el navegador que se utilice para hacer la transferencia. Aqu debajo, en el cdigo fuente del script que actualiza la base de datos, tienes los nombres de esos tipos asociados a los navegadores ms usuales.

<?php $foto_name= $_FILES['foto']['name']; $foto_size= $_FILES['foto']['size']; $foto_type= $_FILES['foto']['type']; $foto_temporal= $_FILES['foto']['tmp_name'];

$lim_tamano= $_POST['lim_tamano']; $foto_titulo= $_POST['titulo']; /* limitamos los formatos de imagen admitidos a: png que segun del navegador que ulicemos puede ser: en IE image/x-png en Firefox y Mozilla image/png jpg que puede tener como tipo en IE image/pjpeg en Firefox y Mozilla image/jpeg gif que tiene como tipo image/gif en todos los navegadores Mira los comentarios al margen sobre la variable $extensin */ if ($foto_type=="image/x-png" OR $foto_type=="image/png"){ $extension="image/png"; } if ($foto_type=="image/pjpeg" OR $foto_type=="image/jpeg"){ $extension="image/jpeg"; } if ($foto_type=="image/gif" OR $foto_type=="image/gif"){ $extension="image/gif"; } # condicionamos la insercin a que la foto tenga nombre, # un tamao distinto de cero y menor de lmite establecido # en el formulario y que la variable extensin sea no nula if ($foto_name != "" AND $foto_size != 0 AND $foto_titulo !='' AND $foto_size<=$lim_tamano AND $extension !=''){ /*reconversion de la imagen para meter en la tabla abrimos el fichero temporal en modo lectura "r" binaria"b"*/ $f1= fopen($foto_temporal,"rb"); #leemos el fichero completo limitando # la lectura al tamao de fichero $foto_reconvertida = fread($f1, $foto_size); #anteponemos \ a las comillas que pudiera contener el fichero # para evitar que sean interpretadas como final de cadena $foto_reconvertida=addslashes($foto_reconvertida); # abrimos la base de datos y escribimos las intrucciones de insercin # en el campo BLOB insertaremos la foto_reconvertida $base="ejemplos"; $tabla="fotos"; $conexion=mysql_connect ("localhost","pepe","pepa"); mysql_select_db ($base, $conexion); $meter="INSERT INTO ".$tabla; $meter .=" (num_ident, imagen, nombre, tamano, formato) "; $meter .=" VALUES('','$foto_reconvertida','$foto_titulo',"; $meter .= "$foto_size, '$extension')"; if (@mysql_query($meter,$conexion)){ print "Foto guardada en la tabla"; }else{ print "Ha habido un error al guardar la foto"; } }else{ echo "<h2>No ha podido transferirse el fichero</h2>"; } mysql_close(); ?>
Hay otro aspecto a tener en cuenta. Esa discriminacin de tipos se plantea nicamente cuando Apache recibe una transferencia. Cuando se visualiza un contenido las cabeceras tipo de contenido (header("content-type: xx")) pueden ser las mismas para todos los navegadores. Esa es la razn por la que a la hora de incluir el formato en la tabla utilizamos image/jpg, image/gif o image/png.

Cmo guardamos la imagen?

La informacin recibida a travs del formulario requiere un ligero retoque antes de incluirla en le campo BLOB de la tabla. Esa reconversin requiere abrir la imagen en modo binario (rb) -parece que solo en el caso de Windows leer el fichero completo y aadirle \ antes de las comillas mediante addslashes. Una vez hecho el retoque ya puede guardarse sin ms problema.

PNG con transparencias en Internet Explorer


Internet Explorer no permite visualizar de forma automtica las transparencias de las imgenes con formato png. Existen en la redalgunos recursos que permiten solventar ese problema. Hemos elegido uno de ellos pngfix.js- que puedes ver en este enlace. Se trata de un fichero JavaScript que basta incluir en la cabecera HMTL de la pgina de la forma que ves en el ejemplo de la parte derecha. Cuando un navegador IE es detectado se ejecuta una funcin contenida en ese fichero que analiza la pgina, busca imgenes con extensin png y les aplica la transparencia adecuada. Por esa razn, es probable que inicialmente (al cargar la pgina) se visualice la imagen opaca y que, posteriormente, adquiera la transparencia.

Visualizacin de imgenes
La lectura de una imagen utiliza solo dos instrucciones. Incluir la cabecera Header en el que se indica el tipo de contenido (el famoso nombre MIME de la imagen) y luego imprimir el contenido del campo. Pero (por aquello de que header debe ir incluida en el script antes que cualquier otra salida) si pretendemos incluir en una pgina algo ms que una imagen tendremos que invocar esas dos funciones, de forma independiente, para cada una de ellas. Por esa razn, en el ejemplo que tienes al margen, al desarrollar el ejemplo que permite visualizar todas las imgenes de la tabla hemos tenido que incluir un script que va leyendo la tabla que contiene las imgenes para extraer los campos informativos y a la hora de ver la imagen hemos de recurrir a la misma tcnica que se utilizaba para ver las imgenes dinmicas. Es decir, poner una etiqueta de imagen de las de HTML pero -en vez de escribir el nombre de la imagen- poniendo incluyendo como nombre el del script que las visualiza y pasndole elnmero (valor del campo autoincremental) de la imagen que pretend visualizar. Script para leer imgenes de la base datos

<? $numero=$_REQUEST['n']; $base="ejemplos"; $tabla="fotos"; $conexion=mysql_connect ("localhost","pepe","pepa"); mysql_select_db ($base, $conexion); $sacar = "SELECT * FROM ".$tabla." WHERE (num_ident=$numero)" ; $resultado = mysql_query($sacar,$conexion); while ($registro = mysql_fetch_array($resultado)){ $tipo_foto=$registro['formato']; header("Content-type: $tipo_foto"); echo $registro['imagen']; } mysql_close(); ?>
Ver imgenes guardadas

El problema de los PNG en IE


El JavaScript que asigna la transparencia a las imgenes en formato png las identifica buscando la coincidencia de los tres ltimos caracteres del nombre de la imagen con la extensin png. Cuando se trata de imgenes dinmicas el nombre de la imagen coinciden con el nombre de la llamada al script que se utiliza para su visualizacin. Por eso, para advertir a JavaScript de que se trata de una imagen png hemos incluido el condicional que puedes ver en el ejemplo. De esa forma, cuando se trata de una imagen en este formato incluimos en la peticin una variable con el valor png de forma que pueda ser reconocida por pngfix.js y aplicada la transparencia requerida. Script para leer la base de datos

<html>

<head> <!-- al margen te comentamos la razn por la que --> <!-- se incluyen estas lneas en rojo --> <!--[if IE ]> <script type="text/javascript" src="pngfix.js"></script> <![endif]--> </head> <body> <? $base="ejemplos"; $tabla="fotos"; $conexion=mysql_connect ("localhost","pepe","pepa"); mysql_select_db ($base, $conexion); $sacar = "SELECT * FROM ".$tabla; $resultado = mysql_query($sacar,$conexion); while ($registro = mysql_fetch_array($resultado)){ print "<center>Titulo de la imagen: ".$registro['nombre']."<br>"; /* la inclusin de este condicional obedece a los problemas que plantea la visualizacin de las transparencias de las imgenes png en Internet Explorer. Al margen justificamos las razones de su inclusin */ if($registro['formato']=="image/png"){ print "<img src='ver_foto.php?n=".$registro['num_ident']."&v=png'><br>"; }else{ print "<img src='ver_foto.php?n=".$registro['num_ident']."'><br>"; } print "Tamao de la imagen: ".$registro['tamano']." bytes </center>"; } mysql_close(); ?> </body> </html>

Tablas InnoDB Las tablas InnoDB


Creacin de una tabla InnoDB
La creacin de tablas de este tipo no presenta ninguna dificultad aadida. El proceso es idntico a las tablas habituales sin ms que aadir Type=InnoDB despus de cerrar el parntesis de la sentencia de creacin de la tabla. Este script crea una tabla InnoDB con idnticos campos a los utilizados en el caso de la tabla MyISAM que hemos visto en pginas anteriores. La sintaxis, muy similar a la utilizada all es esta:

<?php $base="ejemplos"; $tabla="demoinno"; $c=mysql_connect ("localhost","pepe","pepa"); mysql_select_db ($base, $c); $crear="CREATE TABLE $tabla ("; $crear.="Contador TINYINT(8) UNSIGNED ZEROFILL NOT NULL AUTO_INCREMENT,"; $crear.="DNI CHAR(8) NOT NULL, "; $crear.="Nombre VARCHAR (20) NOT NULL, "; $crear.="Apellido1 VARCHAR (15) not null, ";

$crear.="Apellido2 VARCHAR (15) not null, "; $crear.="Nacimiento DATE DEFAULT '1970-12-21', "; $crear.="Hora TIME DEFAULT '00:00:00', "; $crear.="Sexo Enum('M','F') DEFAULT 'M' not null, "; $crear.="Fumador CHAR(0) , "; $crear.="Idiomas SET(' Castellano',' Francs','Ingls', ' Alemn',' Blgaro',' Chino'), "; $crear.=" PRIMARY KEY(DNI), "; $crear.=" UNIQUE auto (Contador)"; $crear.=")"; # esta es la nica diferencia con el proceso de # creacin de tablas MyISAM $crear.=" Type=InnoDB"; if(mysql_query ($crear ,$c)) { echo "<h2> Tabla $tabla creada con EXITO </h2><br>"; }else{ echo "<h2> La tabla $tabla NO HA PODIDO CREARSE "; # echo mysql_error ($c)."<br>"; $numerror=mysql_errno ($c); if ($numerror==1050){echo "porque YA EXISTE</h2>";} }; mysql_close($c); ?>
Ver cdigo fuente

Cuidado! Bajo Windows, al crear una base de datos o tabla InnoDB el nombre de la misma aparecer en minsculas independientemente de la sintaxis que hayamos utilizado en su creacin. Para prever posibles conflictos al ejecutar los scripts en diferentes plataformas utilizaremos minsculas para los nombres de tablas.

Una vez creadas, las tablas InnoDB se comportan a efectos de uso exactamente igual que las que hemos venido utilizando en las pginas anteriores. No es preciso hacer ningn tipo de modificacin en la sintaxis. Por tanto, es totalmente vlido todo lo ya comentado respecto a: altas, modificaciones, consultas y bajas.

Las transacciones
Uno de los riesgos que se plantean en la gestin de bases de datos es que pueda producirse una interrupcin del proceso mientras se est actualizando una o varias tablas. Pongamos como ejemplo el cobro de nuestra nmina. Son necesarias dos anotaciones simultneas: El cargo en la cuenta del organismo pagador y el abono en nuestra cuenta bancaria. Si se interrumpiera fortuitamente el proceso en el intermedio de las dos operaciones podra darse la circunstancia de que apareciera registrado el pago sin que se llegaran a anotar los haberes en nuestra cuenta. Las transacciones evitan este tipo de situaciones ya que los datos se registran de manera provisional y no se consolidan hasta que una instruccin confirme que esas anotaciones tienen carcter definitivo. Para ello, MySQL dispone de tres sentencias: BEGIN, COMMIT yROLLBACK.

Sintaxis de las transacciones


Existen tres sentencias para gestionar las transacciones. Son las siguientes: mysql_query("BEGIN",$conexion) Su ejecucin requiere que est activa la conexin $c con el servidor de base de datos e indica a MySQL que en ese punto comienza una transaccin. Todas las sentencias que se ejecuten a partir de ella tendrn carcter provisional y no se ejecutarn de forma efectiva hasta que encuentre una sentencia de finalizacin.

mysql_query("ROLLBACK",$conexion) Mediante esta sentencia advertimos a MySQL que finaliza la transaccin pero que no debe hacerse efectiva ninguna de las modificaciones incluidas en ella. mysql_query("COMMIT",$conexion) Esta sentencia advierte a MySQL que ha finalizado la transaccin y que S debe hacer efectivos todos los cambios incluidos en ella.

Precauciones a tener en cuenta


Cuando se utilizan campos autoincrementales en tablas InnoDB los contadores se van incrementando al aadir registros (incluso de forma provisional) con lo cual si se aborta la inclusin con un ROLLBACK ese contador mantiene el incremento y en inserciones posteriores partir de ese valor acumulado. Por ejemplo. Si partimos de una tabla vaca y hacemos una transaccin de dos registros (nmero 1 y nmero 2 en el campo autoincremental) y la finalizamos con ROLLBACK, no se insertarn pero en una insercin posterior el contador autoincremental comenzar a partir del valor 2.

Las primeras transacciones


<?php $base="ejemplos"; # escribimos el nombre de la tabla en MINUSCULAS # para asegurar la compatibilidad entre plataformas $tabla="demoinno"; $conexion=mysql_connect("localhost","pepe","pepa"); mysql_select_db ($base, $conexion); # insertamos la sentencia BEGIN para indicar el comienzo # de una transaccin mysql_query("BEGIN",$conexion); /* hasta que no aparezca una sentencia que finalice la transaccin (ROLLBACK COMMIT) las modificaciones en la tabla sern registradas de forma "provisional") */ mysql_query("INSERT $tabla (DNI,Nombre,Apellido1,Apellido2, Nacimiento,Sexo,Hora,Fumador,Idiomas) VALUES ('111111','Alvaro','Alonso','Azcrate','1954-11-23', 'M','16:24:52',NULL,3)",$conexion); if (mysql_errno($conexion)==0){ echo "Registro AADIDO<br>"; }else{ if (mysql_errno($conexion)==1062){ echo "No ha podido aadirse el registro <br>"; echo "Ya existe un registro con este DNI<br>"; }else{ $numerror=mysql_errno($conexion); $descrerror=mysql_error($conexion); echo "Se ha producido un error n $numerror<br>"; echo "<br>que corresponde a: $descrerror<br>"; } } # indicamos el final de la transaccin, en este caso con ROLLBACK # por lo tanto el registro con DNI 111111 no ser insertado en la tabla mysql_query("ROLLBACK",$conexion); # incluyamos una nueva transaccin mysql_query("BEGIN",$conexion); mysql_query("INSERT $tabla (DNI,Nombre,Apellido1,Apellido2, Nacimiento,Sexo,Hora,Fumador,Idiomas) VALUES

('222222','Genoveva','Zarabozo','Zitrn','1964-01-14', 'F','16:18:20',NULL,2)",$conexion); if (mysql_errno($conexion)==0){ echo "Registro AADIDO"; }else{ if (mysql_errno($conexion)==1062){ echo "No ha podido aadirse el registro <br>"; echo "Ya existe un registro con este DNI"; }else{ $numerror=mysql_errno($conexion); $descrerror=mysql_error($conexion); echo "Se ha producido un error n $numerror"; echo "<br>que corresponde a: $descrerror"; } } # indicamos el final de la transaccin, en este caso con COMMIT # por lo tanto el registro con DNI 222222 si ser insertado en la tabla mysql_query("COMMIT",$conexion); # leamos el contenido de la tabla para ver el resultado $resultado= mysql_query("SELECT * FROM $tabla" ,$conexion); print "<br>Lectura de la tabla depus del commit<br>"; while ($registro = mysql_fetch_row($resultado)){ foreach($registro as $clave){ echo $clave,"<br>"; } } mysql_close(); ?>

La integridad referencial
Elementos necesarios para la integridad referencial
La integridad referencial ha de establecerse siempre entre dos tablas. Una de ellas ha de comportarse como tabla principal (suele llamarse tabla padre y la otra sera la tabla vinculada tabla hijo. Es imprescindible: Que la tabla principal tenga un ndice primario (PRIMARY KEY) Que la tabla vinculada tenga un ndice (no es necesario que sea ni nico ni primario) asociado a campos de tipo idntico a los que se usen para ndice de la tabla principal. Si observas el cdigo fuente del ejemplo que tienes a la derecha podrs observar que utilizamos el nmero del DNI (nico para alumno) como elemento de vinculacin de la tabla de datos personales con la que incluye las direcciones.

Integridad referencial en tablas InnoDB


Cuando se trabaja con varias tablas que tienen algn tipo de vnculo resulta interesante disponer de mecanismos que protejan o impidan acciones no deseadas. Supongamos, como veremos en los ejemplos posteriores que pretendemos utilizar una tabla con datos de alumnos y otra tabla distinta para las calificaciones de esos alumnos. Si no tomamos ninguna precaucin (bien sea mediante los script o mediante el diseo de las tablas) podra darse la circunstancia de que incluyramos calificaciones a alumnos inexistentes, en materias de las que no estn matriculados, etctera. Tambin podra darse la circunstancia de que diramos de baja a un alumno pero que se mantuvieran las calificaciones vinculadas a l. Todas estas circunstancias suelen producir efectos indeseados y las tablas InnoDB pueden ser diseadas para prever este tipo de situaciones.

Sintaxis para la vinculacin de tablas


Los vnculos entre tablas suelen establecer en el momento de la creacin de la tabla vinculada. CREATE TABLE tabla (campo1, campo2,... KEY nombre (campo de vinculacion ),

FOREIGN KEY (campo de vinculacion) REFERENCES nombre_de la tabla principal (Indice primario de la tabla principal) ) Type=InnoDB donde el campo de vinculacion ha de ser un ndice (no es necesario que sea PRIMARY KEY ni UNIQUE) y donde Indice primario de la tabla principal ha de ser un ndice primario (PRIMARY KEY) de la tabla principal. Debe haber plena coincidencia (tanto en tipos como contenidos) entre ambos ndices.

<?php $base="ejemplos"; $tabla1="principal"; $tabla2="vinculada"; $c=mysql_connect ("localhost","pepe","pepa"); mysql_select_db ($base, $c); # creacin de la tabla principal type InnoDB $crear="CREATE TABLE IF NOT EXISTS $tabla1 ("; $crear.="DNI CHAR(8) NOT NULL, "; $crear.="Nombre VARCHAR (20) NOT NULL, "; $crear.="Apellido1 VARCHAR (15) not null, "; $crear.="Apellido2 VARCHAR (15) not null, "; # el indice primario es imprescindible. Recuerda que debe # estar definido sobre campos NO NULOS $crear.=" PRIMARY KEY(DNI) "; $crear.=")"; $crear.=" Type=InnoDB"; # creamos la tabla principal comprobando el resultado if(@mysql_query ($crear ,$c)){ print "La tabla ".$tabla1." ha sido creada<br>"; }else{ print "No se ha creado ".$tabla1." ha habido un error<br>"; } # crearemos la tabla vinculada $crear="CREATE TABLE IF NOT EXISTS $tabla2 ("; $crear.="IDENTIDAD CHAR(8) NOT NULL, "; $crear.="calle VARCHAR (20), "; $crear.="poblacion VARCHAR (20), "; $crear.="distrito VARCHAR(5), "; # creamos el ndice (lo llamamos asociador) para la vinculacin # en este caso no ser ni primario ni nico # Observa que el campo IDENTIDAD de esta tabla CHAR(8) # es idntico al campo DNI de la tabla principal $crear.=" KEY asociador(IDENTIDAD), "; #establecemos la vinculacin de ambos ndices $crear.=" FOREIGN KEY (IDENTIDAD) REFERENCES $tabla1(DNI) "; $crear.=") TYPE = INNODB"; # creamos (y comprobamos la creacin) la tabla vinculada if(@mysql_query ($crear ,$c)){ print "La tabla ".$tabla2." ha sido creada<br>"; }else{ print "No se ha creado ".$tabla2." ha habido un error<br>"; } mysql_close(); ?>

Modificacin de estructuras
La modificacin de estructuras en tablas vinculadas puede hacerse de forma idntica a la estudiada para los casos generales de MySQL siempre que esas modificaciones no afecten a los campos mediante los que se establecen las vinculaciones entre tablas. Aqu tienes un ejemplo en se borran y aaden campos en ambas tablas. Como puedes ver la sintaxis es exactamente la misma que utilizamos en temas anteriores.

<?php $base="ejemplos"; $tabla="principal"; $tabla1="vinculada"; $c=mysql_connect ("localhost","pepe","pepa"); mysql_select_db ($base, $c); if(mysql_query("ALTER print "Sea ha } if(mysql_query("ALTER print "Sea ha } if(mysql_query("ALTER print "Sea ha } if(mysql_query("ALTER print "Sea ha } mysql_close(); ?> TABLE $tabla ADD Segundo_Apellido VARCHAR(40)",$c)){ creado el nuevo campo en ".$tabla."<br>"; TABLE $tabla DROP Apellido2",$c)){ borrado el campo Apellido 2 en ".$tabla."<br>"; TABLE $tabla1 ADD DP VARCHAR(5)",$c)){ creado el nuevo campo en ".$tabla1."<br>"; TABLE $tabla1 DROP distrito",$c)){ borrado el campo distrito en ".$tabla1."<br>";

Modificacin o borrado de campos vinculados


Las sentencias MySQL que deban modificar o eliminar campos utilizados para establecer vnculos entre tablas requieren de un parmetro especial (CONSTRAINT) puede ser distinto en cada una de las tablas que es necesario conocer previamente. La forma de visualizarlo es ejecutar la sentencia: SHOW CREATE TABLE nombre tabla que devuelve como resultado un array asociativo con dos ndices. Uno de ellos -llamado Table- que contiene el nombre de la tabla y el otro -Create Table- que contiene la estructura con la que ha sido creada la tabla, pero incluyendo el parmetro CONSTRAINT seguido de su valor. Ese valor es precisamente el que necesitamos para hacer modificaciones en los campos asociados de las tablas vinculadas. En ceste enlace podrs puedes ver el cdigo fuente del script que ejecuta esa sentencia ejecucin de esa sentencia. Conocido el valor de parmetro anterior el proceso de borrado del vnculo actual requiere la siguiente sintaxis: ALTER TABLE nombre de la tabla DROP FOREIGN KEY parametro Cuando se trata de aadir un nuevo vnculo con una tabla principal habremos de utilizar la siguiente sentencia: ALTER TABLE nombre de la tabla ADD [CONSTRAINT parametro] FOREIGN KEY parametro REFERENCES tabla principal(clave primaria) El parmetro CONSTRAIT (encerrado en corchetes en el prrafo anterior) es OPCIONAL y solo habra de utilzarse en el caso de que existiera ya una vinculacin previa de esa tabla. En este ejemplo determinaremos el valor de CONSTRAINT y modificaremos campos asociados de la tabla vinculada.

<?php $base="ejemplos"; $tabla="vinculada"; $tabla1="principal"; $c=mysql_connect ("localhost","pepe","pepa"); mysql_select_db ($base, $c); $resultado=mysql_query( "SHOW CREATE TABLE $tabla",$c); $v=mysql_fetch_array($resultado); # extreamos de Create Table la cadena que empiza por CONSTRAINT # y que acaba por FOREING KEY lo guardamos en el array $coin preg_match ('/CONSTRAINT.*FOREIGN KEY/', $v['Create Table'], $coin);

# extraemos el parametro quitando el CONSTRAINT que lleva delante # y el FOREIGN KEY que lleva al final $para=str_replace("FOREIGN KEY",'',str_replace("CONSTRAINT",'',$coin[0])); print "El valor de CONSTRAINT es: ".$para."<br>"; # eliminamos el vinculo con la clave externa incluyendo en la sentancia # el valor del parametro obtenido el proceso anterior if(mysql_query("ALTER TABLE $tabla DROP FOREIGN KEY $para",$c)){ print "Se ha realizado con xito el borrado del vnculo<br>"; } # aadimos el nuevo vnculo (en este caso rehacemos el anterior # pero el proceso es idntico) if(mysql_query("ALTER TABLE $tabla ADD CONSTRAINT $para FOREIGN KEY(IDENTIDAD) REFERENCES $tabla1(DNI)",$c)){ print "Se ha reestablecido con xito vnculo<br>"; } mysql_close(); ?>

La funcin preg_match
En el ejemplo hemos utilizamos esta la funcin (relacionada con el uso de expresiones regulares): preg_match( patron, cadena, coincidencias ) dnde patron es un patrn de bsqueda, cad es la cadena que la han de realizarse las bsquedas y coin es un array que recoge todas las coincidencias encontradas en la cadena. El patrn de bsqueda que hemos utilizado en el ejemplo /CONSTRAINT.*FOREIGN KEY/ debe interpretarse de la siguiente forma. Los caracteres / indican el comienzo y el final del patrn, el . indica que entre CONSTRAIT y FOREING se permite cualquier carcter y, adems,* indica que ese caracter cualquiera puede repetirse cero o ms veces.

Aadir registros a la tabla vinculada


Si ejecutas este ejemplo habiendo seguido la secuencia de estos materiales vers que se produce un error n 1452. Cannot add or update a child row: a foreign key constraint fails (`ejemplos`.`vinculada`, CONSTRAINT `vinculada_ibfk_1` FOREIGN KEY (`IDENTIDAD`) REFERENCES `principal` (`DNI`)). Es lgico que as sea porque estamos intentando aadir un registro a la tabla vinculada y ello requerira que en el campo DNI de la tabla principal existiera otro registro con un valor igual al que pretendemos introducir en la tabla vinculada.
Insercin en tabla vinculada Ver script

Aadiremos un registro a la tabla principal con el DNI anterior:


Insercin en tabla principal Ver script

y ahora ya podremos ejecutar -sin errores- el script que inserta datos en la tabla vinculada. Podremos ejecutar aquel script tantas veces como queramos ya que -el campo IDENTIDAD est definido como KEY y por tanto permite duplicados- no hemos establecido la condicin de ndice PRIMARIO UNICO.

Borrar o modificar registros en la tabla principal


Sin intentamos borrar un registro de la tabla principal mediante un script como el que tienes en este ejemplo vers que se produce unerror n 1451 que corresponde a: Cannot delete or update a parent row: a foreign key constraint fails (`ejemplos`.`vinculada`, CONSTRAINT `vinculada_ibfk_1` FOREIGN KEY (`IDENTIDAD`) REFERENCES `principal` (`DNI`)) advirtindonos de que no se realiza el borrado porque existen registros en la tabla vinculada con valores asociados al ndice del campo que pretendemos borrar y, de permitir hacerlo, se rompera la integridad referencial ya que quedaran registros hurfanos en la tabla vinculada.
Borrar tabla principal Ver script

Sin tratamos de modificar un registro de la tabla principal y la modificacin afecta al ndice que realiza la asociacin con la tabla (o tablas) vinculadas se producira -por las mismas razones y en las mismas circunstancias- un error 1451 que corresponde a: Cannot delete or update a parent row: a foreign key constraint fails (`ejemplos`.`vinculada`, CONSTRAINT `vinculada_ibfk_1` FOREIGN KEY (`IDENTIDAD`) REFERENCES `principal` (`DNI`)) que impedira la modificacin.
Modificar DNI en tabla principal Ver script

Si -al tratar de borrar o modificar un registro de la tabla principal no existieran en la tabla (o tablas vinculadas) registros asociados con l, el proceso de modificacin se realizara sin ningn problema y sin dar ningn mensaje de error o advertencia.

Borrado de tablas vinculadas


Si pretendemos eliminar una tabla principal sin haberlo hecho previamente con sus tablas vinculadas recibiremos un mensaje de error y no se producir el borrado. Las tablas vinculadas s permiten el borrado y una vez que stas ya han sido eliminadas (o quitada la vinculacin) ya podrn borrarse sin problemas las tablas principales. El orden de borrado (si ambas pretenden borrarse desde el mismo script)es important.e Primero se borra la vinculada y luego la principal. Este es el cdigo fuente del script que realiza es borrado segn el orden correcto.

Opciones adicionales de FOREIGN KEY


La clasula FOREIGN KEY permite aadirte -detrs de la definicin ya comentada y sin poner coma separndola de ellalos parmetros ON DELETE y ON UPDATE en las que se permite especificar una de las siguientes opciones: ON DELETE RESTRICT Esta condicin (es la condicin por defecto de MySQL y no es preciso escribirla) indica a MySQL que interrumpa el proceso de borrado y de un mensaje de error cuando se intente borrar un registro de la tabla principal cuando en la tabla vinculada existan registros asociados al valor que se pretende borrar. ON DELETE NO ACTION Es un sinnimo de la anterior. ON DELETE CASCADE Cuando se especifica esta opcin, al borrar un registro de la tabla principal se borrarn de forma automtica todos los de la tabla vinculada que estuvieran asociados al valor de la clave fornea que se trata de borrar. Con ello se conseguira una actualizacin automtica de la segunda tabla y se mantendra la identidad referencial. ON DELETE SET NULL Con esta opcin, al borrar el registro de la tabla principal no se borraran los que tuviera asociados la tabla secundaria pero tomaran valor NULL todos los ndices de ella coincidentes con la clave primaria de la tabla principal. Para el caso de ON UPDATE las opciones son estas: ON UPDATE RESTRICT ON UPDATE CASCADE ON UPDATE SET NULL Su comportamiento es idntico a sus homnimas del caso anterior.

Cuidado! El uso de la opcin SET NULL requiere que el campo indicado en FOREIGN KEY est permita valores nulos. Si est definido con flag NOT NULL (como ocurre en los ejemplos que tienes al margen) dara un mensaje de error.

Cuidado! Al incluir ON DELETE y ON UPTADE (si se incluyen ambas) han de hacerse por este mismo orden. Si se cambiara este orden dara un mensaje de error y no se ejecutaran.

Automatizacin de procesos
Creamos dos tablas idnticas a las anteriores incluyendo algunos datos en ellas.

<?php $base="ejemplos"; $tabla1="principal1"; $tabla2="vinculada1"; $c=mysql_connect ("localhost","pepe","pepa"); mysql_select_db ($base, $c); # creacin de la tabla principal type InnoDB $crear="CREATE TABLE IF NOT EXISTS $tabla1 ("; $crear.="DNI CHAR(8) NOT NULL, "; $crear.="Nombre VARCHAR (20) NOT NULL, "; $crear.="Apellido1 VARCHAR (15) not null, "; $crear.="Apellido2 VARCHAR (15) not null, "; $crear.=" PRIMARY KEY(DNI) "; $crear.=")"; $crear.=" Type=InnoDB"; # creamos la tabla principal comprobando el resultado if(@mysql_query ($crear ,$c)){ print "La tabla ".$tabla1." ha sido creada<br>"; }else{ print "No se ha creado ".$tabla1." ha habido un error<br>"; } # crearemos la tabla vinculada $crear="CREATE TABLE IF NOT EXISTS $tabla2 ("; $crear.="IDENTIDAD CHAR(8) NOT NULL, "; $crear.="calle VARCHAR (20), "; $crear.="poblacion VARCHAR (20), "; $crear.="distrito VARCHAR(5), "; #creamos la tabla vinculada las opciones de DELETE y UPDATE $crear.=" KEY asociador(IDENTIDAD), "; #establecemos la vinculacin de ambos ndices $crear.=" FOREIGN KEY (IDENTIDAD) REFERENCES $tabla1(DNI) "; $crear.=" ON DELETE CASCADE "; $crear.=" ON UPDATE CASCADE "; $crear.=") TYPE = INNODB"; # creamos (y comprobamos la creacin) la tabla vinculada if(@mysql_query ($crear ,$c)){ print "La tabla ".$tabla2." ha sido creada<br>"; }else{ print "No se ha creado ".$tabla2." ha habido un error<br>"; } # aadimos registros a la tabla principa1 mysql_query("INSERT $tabla1 (DNI,Nombre,Apellido1,Apellido2) VALUES ('111111','Robustiano','Iglesias','Prez')",$c); mysql_query("INSERT $tabla1 (DNI,Nombre,Apellido1,Apellido2) VALUES ('222222','Ambrosio','Morales','Gmez')",$c); # aadimos registros a la tabla vinculada1 mysql_query("INSERT $tabla2 (IDENTIDAD,calle,poblacion,distrito) VALUES ('111111','Calle Asturias,3','Oviedo','33001')",$c); mysql_query("INSERT $tabla2 (IDENTIDAD,calle,poblacion,distrito) VALUES ('111111','Calle Palencia,3','Logroo','78541')",$c); mysql_query("INSERT $tabla2 (IDENTIDAD,calle,poblacion,distrito)

VALUES ('222222','Calle Anunciacin,3','Algeciras','21541')",$c); mysql_close(); ?>


Ver contenidos de tablas Ver cdigo fuente

Modificar registros en cascada


<?php $base="ejemplos"; $tabla="principal1"; $conexion=mysql_connect("localhost","pepe","pepa"); mysql_select_db($base,$conexion); # modificamos un registro mysql_query("UPDATE $tabla SET DNI='123456' WHERE DNI='111111'",$conexion); # borramos un registro mysql_query("DELETE FROM $tabla WHERE (DNI='222222')",$conexion); if (mysql_errno($conexion)==0){echo "<h2>Tablas actualizadas</b></H2>"; }else{ print "Ha habido un error al actualizar"; } mysql_close(); ?>

Importacin / exportacin de datos Definicin de tablas


En este ejemplo de tablas vinculadas con integridad relacional vamos a proponer la situacin cuyo esquema puedes ver en el grfico y cuya descripcin es la siguiente:

Crearemos una primera tabla (alumnos) que va a contener datos personales de un grupo de personas. Para evitar duplicar un mismo alumno y alumnos sin DNI, vamos a utilizar como ndice primario (PRIMARY KEY) el campo DNI (que es nico para cada persona). La condicin de que el campo DNI sea PRIMARY KEY nos obliga a definirlo con el flag NOT NULL, dado que esta es una condicin necesaria para la definicin de ndices primarios. Crearemos una segunda tabla (domicilios) con los domicilios de cada uno de los alumnos, identificndolos tambin por su DNI. Para evitar que un mismo alumno pueda tener dos domicilios asignamos a al campo DNI de esta tabla la condicin de ndice nico (UNIQUE). El ndice UNIQUE podramos haberlo creado tambin como PRIMARY KEY ya que la nica diferencia de comportamiento entre ambos es el hecho que aquel admitira valores NULOS pero, dado que debemos evitar domicilios sin alumnos, insertaremos el flag NOT NULL en este campo. El hecho de utilizar dos tablas no tiene otro sentido que la ejemplificacin ya que lo habitual sera que todos los datos estuvieran en una misma tabla. Vincularemos ambas tablas de modo que no puedan crearse direcciones de alumnos inexistentes y les pondremos la opcin de actualizacin y borrado en cascada. De esta forma las acciones en la tabla de alumno se reflejaran automticamente en la tabla de domicilios. La tercera de las tablas (evaluaciones) tiene como finalidad definir las distintas evaluaciones que puede realizarse a cada alumno. Tendr dos campos. Uno descriptivo (el nombre de la evaluacin) y otro identificativo (no nulo y nico) que ser tratado como PRIMARY KEY para evitar duplicidades y porque, adems, va a ser utilizado como clave fornea en la tabla notas. La tabla notas va a tener tres campos: DNI, n de evaluacin y calificacin. Estableceremos restricciones para evitar que: Podamos calificar a un alumno inexistente. Podamos calificar una evaluacin no incluida entre las previstas. Podamos poner a cada alumno ms de una calificacin por evaluacin. Creando una ndice primario formado por los campos DNI y evaluacin evitaremos la ltima de las situaciones y aadiendo una vinculacin con las tablas alumnos y evaluaciones estaremos en condiciones de evitar las dos primeras.

Estructura de tablas y relaciones


Para desarrollar los ejemplos de este captulo vamos a crear las tablas, cuyas estructuras e interrelaciones que puedes ver en el cdigo fuente siguiente:

<?php $base="ejemplos"; $c=mysql_connect ("localhost","pepe","pepa"); mysql_select_db ($base, $c); ############################################### # Creacin de la tabla nombres con indice primario DNI # tabla de nombres con ndice primario en DNI ############################################### $crear="CREATE TABLE IF NOT EXISTS alumnos ("; $crear.="DNI CHAR(8) NOT NULL, "; $crear.="Nombre VARCHAR (20) NOT NULL, "; $crear.="Apellido1 VARCHAR (15) not null, "; $crear.="Apellido2 VARCHAR (15) not null, "; $crear.=" PRIMARY KEY(DNI) "; $crear.=")"; $crear.=" Type=InnoDB"; if(mysql_query ($crear ,$c)){ print "tabla <b>nombres</b> creada<BR>"; }else{ print "ha habido un error al crear la tabla <b>alumnos</b><BR>"; } ###############################################

# Creacin de la tabla direcciones # tabla de nombres con ndice nico en DNI # para evitar dos direcciones al mismo alumno # y clave fornea nombres(DNI) # para evitar direcciones no asociadas a un alumno # concreto. Se activa la opcin de actualizar # en cascada y de borrar en cascada ############################################### $crear="CREATE TABLE IF NOT EXISTS domicilios ("; $crear.="DNI CHAR(8) NOT NULL, "; $crear.="calle VARCHAR (20), "; $crear.="poblacion VARCHAR (20), "; $crear.="distrito VARCHAR(5), "; $crear.=" UNIQUE identidad (DNI), "; $crear.="FOREIGN KEY (DNI) REFERENCES alumnos(DNI) "; $crear.="ON DELETE CASCADE "; $crear.="ON UPDATE CASCADE "; $crear.=") TYPE = INNODB"; if(mysql_query ($crear ,$c)){ print "tabla <b>domicilios</b> creada<br>"; }else{ print "ha habido un error al crear la tabla <b>domicilios</b><BR>"; } ############################################### # Creacin de la tabla nombres con indice primario EVALUACIONES # tabla de nombres con ndice primario en NUMERO ############################################### $crear="CREATE TABLE IF NOT EXISTS evaluaciones ("; $crear.="NUMERO CHAR(1) NOT NULL, "; $crear.="nombre_evaluacion VARCHAR (20) NOT NULL, "; $crear.=" PRIMARY KEY(NUMERO)"; $crear.=")"; $crear.=" Type=InnoDB"; if(mysql_query ($crear ,$c)){ print "tabla <b>evaluaciones</b> creada<BR>"; }else{ print "ha habido un error al crear la tabla <b>evaluaciones</b><BR>"; } ############################################### # Creacin de la tabla notas # indice UNICO para los campos DNI y evaluacion # con ello se impide calificar dos veces al mismo # alumno en la misma evaluacion # claves forneas (DOS) # el DNI de nombres para evitar calificar a alumnos inexistentes # el NUMERO de la tabla evaluaciones para evitar calificar # DOS VECES en una evaluacin a un alumno ############################################### $crear="CREATE TABLE IF NOT EXISTS notas ("; $crear.="DNI CHAR(8) NOT NULL, "; $crear.="evaluacion CHAR (1) NOT NULL, "; $crear.="calificacion TINYINT (2), "; /* observa que este indice primario est formado por dos campos (DNI y evalucion) y que, como siempre en el caso de PRIMARY KEY ambos son de tipo NOT NULL */ $crear.=" PRIMARY KEY vemaos(DNI,evaluacion), "; /* Fijate en la secuencia siguiente: 1.- Creamos el ndice 2.- Establecemos la clave fornea 3.- Establecemo las condiciones ON DELETE 4.- Establecemos las condiciones ON UPDTE Es muy importe mantener esta secuencia para evitar

errores MySQL */ $crear.=" INDEX identico (DNI), "; $crear.="FOREIGN KEY (DNI) REFERENCES alumnos(DNI) "; $crear.="ON DELETE CASCADE "; $crear.="ON UPDATE CASCADE,"; /* Esta tabla tiene dos claves forneas asociadas a dos tablas la anterior definida sobre alumnos como tabla principal y esta que incluimos a continuacin asociada con evaluaciones Como ves repetimos la secuencia descrita anteriormente Es importante establecer estas definiciones de una en una (tal como ves en este ejemplo) y seguir la secuencia comentada anteriormente */ $crear.=" INDEX evalua (evaluacion),"; $crear.="FOREIGN KEY (evaluacion) REFERENCES evaluaciones(NUMERO) "; $crear.="ON DELETE CASCADE "; $crear.="ON UPDATE CASCADE"; $crear.=") TYPE = INNODB"; if(mysql_query ($crear ,$c)){ print "tabla <b>notas</b> creada <BR>"; }else{ print "ha habido un error al crear la tabla <b>notas</b><BR>"; echo mysql_error ($c)."<br>"; echo mysql_errno ($c); } mysql_close(); ?> Cuidado! Como puedes observar en la imagen, al definir la estructura de las tablas es muy importante prestar atencin a que los campos vinculados sean del mismo tipo y dimensin. Observa tambin que los campos de referencia de los vnculos que se establecen (en las tablas primarias) tienen que ser definidos como PRIMARY KEY y que, por tanto, han de establecerse como no nulos (NOT NULL).

Importacin y exportacin de datos


Es esta una opcin interesante por la posibilidad que ofrece de intercambiar datos entre diferentes fuentes y aplicaciones.

Importacin de ficheros
MySQL permite insertar en sus tablas los contenidos de ficheros de texto. Para ello utiliza la sentencia que tienes al margen y que detallaremos a continuacin. LOAD DATA INFILE Es un contenido obligatorio que defina la opcin de insertar datos desde un fichero externo. nombre del fichero Se incluye inmediatamente despus de la anterior, es obligatorio y debe contener (entre comillas) la ruta, el nombre y la extensin del fichero que contiene los datos a insertar. [REPLACE|IGNORE] Es opcional. Si se omite se producir un mensaje de error si el fichero contiene valores iguales a los contenidos en los campos de la tabla que no admiten duplicados. Con la opcin REPLACE sustituira los valores existentes en la tabla y con la opcin IGNORE INTO TABLE nombre Tiene carcter obligatorio y debe incluir como nombre el de la tabla a la que se pretenden agregar los registros. FIELDS Tiene carcter OPCIONAL y permite incluir especificaciones sobre cuales son los caracteres delimitadores de campos y los que indican el final del campo. Si se omite FIELDS no podrn incluirse los ENCLOSED BY ni TERMINATED BY de campo.

ENCLOSED BY Permite espeficar (encerrados entre comillas) los caracteres delimitadores de los campos. Estos caracteres debern encontrarse en el fichero original al principio y al final de los contenidos de cada uno de los campos (por ejemplo, si el carcter fueran comillas los campos deberan aparecer as en el fichero a importar algo como esto: "32.45"). Si se omite esta especificacin (o se omite FIELDS) se entender que los campos no tienen caracteres delimitadores. Cuando se incluyen como delimitadores de campo las comillas (dobles o sencillas) es necesario utilizar una sintaxis como esta: '\"' '\'' de forma que no quepa la ambigedad de si se trata de un carcter o de las comillas de cierre de una cadena previamente abierta. TERMINATED BY Se comporta de forma similar al anterior. Permite qu caracteres son usados en el fichero original como separadores de campos (indicador de final de campo). Si se omite, se interpretar con tal el carcter tabulador (\t). El uso de esta opcin no requiere que se especifique previamente ENCLOSED BY pero si necesita que se haya incluidoFIELDS. LINES Si el fichero de datos contiene caracteres (distintos de los valores por defecto) para sealar el comienzo de un registro, el final del mismo o ambos, debe incluirse este parmetro y, despus de l, las especificaciones de esos valores correspondientes a: STARTING BY Permite especificar una carcter como indicador de comienzo de un registro. Si se omite o se especifica como '' se interpretar que no hay ningn carcter que seale en comienzo de lnea. TERMINATED BY Es el indicador del final de un registro. Si se omite ser considerado como un salto de lnea (\n). Insercin de datos en tablas MySQL permite importar ficheros externos utilizando la siguiente sintaxis: LOAD DATA INFILE "nombre del fichero' [REPLACE | IGNORE] INTO TABLE nombre de la tabla FIELDS TERMINATED BY 'indicador de final de campo' ENCLOSED BY 'caracteres delimitadores de campos' LINES STARTING BY 'caracteres indicadores de comienzo de registro' TERMINATED BY 'caracteres indicadores del final de registro' En este ejemplo puedes ver un caso prctico de insercin de datos en las tablas creadas anteriormente.

<?php $base="ejemplos"; $c=mysql_connect ("localhost","pepe","pepa"); mysql_select_db ($base, $c); /* evitamos los conflictos de los saltos de linea segun el sistema operativo */ if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { $salto_linea="'\r\n'"; }else{ $salto_linea="'\n'"; } /* hemos creado un fichero de texto (datos_alumnos.txt) que contiene datos de algunos alumnos. Los diferentes campos estn entre comillas y separados unos de otros mediante un punto y coma. Cada uno de los registros comienza por un asterios y los registros estn separados por un salto de lnea (\r\n) en Windows o (\n) en Linux. Por esa razn de compatibilidad de sistemas hemos incluido estos valores en una variable $Salto_linea cuyo contenido difiere sengun sistema operativo que est ejecutando este script Incluimos ests especificaciones en la sentencia de insercin */ $query="LOAD DATA INFILE "; $query.="'".$_SERVER['DOCUMENT_ROOT'].'/php/datos_alumnos.txt'."'"; $query.= " REPLACE INTO TABLE alumnos"; $query.= " FIELDS ENCLOSED BY '\"' TERMINATED BY ';' "; $query.=" LINES STARTING BY '*' TERMINATED BY $salto_linea "; if(mysql_query($query,$c)){ print "Datos de alumnos cargados<br>";

}else{ print mysql_error ($c)."<br>".mysql_errno ($c); } /* Para esta tabla usaremos el fichero datos_evaluaciones.txt Los diferentes campos estn entre comillas y separados unos de otros mediante una coma. Cada uno de los registros comienza por un espacio y los registros estn separados por un salto de lnea (\r\n) en Windows o (\n) en Linux. Por esa razn de compatibilidad de sistemas hemos incluido estos valores en una variable $Salto_linea cuyo contenido difiere sengun sistema operativo que est ejecutando este script Incluimos ests especificaciones en la sentencia de insercin */ $query="LOAD DATA INFILE "; $query.="'".$_SERVER['DOCUMENT_ROOT'].'/php/datos_evaluaciones.txt'."'"; $query.= " REPLACE INTO TABLE evaluaciones"; $query.= " FIELDS ENCLOSED BY '\'' TERMINATED BY ',' "; $query.=" LINES STARTING BY ' ' TERMINATED BY $salto_linea "; if(mysql_query($query,$c)){ print "Datos de evaluaciones cargados<br>"; }else{ print mysql_error ($c)."<br>".mysql_errno ($c); } /* En este caso no incluimos especificacin alguna. Bajo este suspuesto MySQL interpreta los valores por defecto que son: los campos no van encerrados, las lneas no tienen ningn carcter indicador de comienzo, los campos estn separados mediante tabulaciones (carcter de escape \t) y el final de lnea est sealado por un caracter de nueva lnea (\n) */ $query="LOAD DATA INFILE "; $query.="'".$_SERVER['DOCUMENT_ROOT'].'/php/datos_notas.txt'."'"; $query.= " IGNORE INTO TABLE notas"; if(mysql_query($query,$c)){ print "Datos de notas cargados<br>"; }else{ print mysql_error ($c)."<br>".mysql_errno ($c); } /* Se comporta como los casos anteriores con distincos caracteres para los diferentes eventos, tal como puedes ver en el cdigo */ $query="LOAD DATA INFILE "; $query.="'".$_SERVER['DOCUMENT_ROOT'].'/php/datos_domicilios.txt'."'"; $query.= " IGNORE INTO TABLE domicilios"; $query.= " FIELDS ENCLOSED BY '|' TERMINATED BY '*' "; $query.=" LINES STARTING BY '#' TERMINATED BY '}' "; if(mysql_query($query,$c)){ print "Datos de domicilios cargados "; }else{ print mysql_error ($c)."<br>".mysql_errno ($c); } mysql_close(); ?>
Consultar tablas

Cuidado! Al importar ficheros habr de utilizarse el mismo formato con el que fueron creados tanto FIELDS como LINES.

Exportacin de ficheros
Se comporta de forma similar al supuesto anterior. Utiliza la sintaxis siguiente: SELECT * INTO OUTFILE Inicia la consulta de los campos especificados despus de SELECT (si se indica * realiza la consulta sobre todos los campos y por el

orden en el que fue creada la tabla) y redirige la salida a un fichero. nombre del fichero Es la ruta, nombre y extensin del fichero en el que sern almacenados los resultados de la consulta. FIELDS ENCLOSED BY TERMINATED BY LINES STARTING BY TERMINATED BY Igual que ocurra en el caso de importacin de datos, estos parmetros son opcionales. Si no se especifican se incluirn los valores por defecto. FROM nombre Su inclusin tiene carcter obligatorio. El valor de nombre ha de ser el de la tabla sobre la que se realiza la consulta. Guardar datos en ficheros MySQL permite los contenidos de sus tablas a ficheros de texto. Para ello utiliza la siguiente sintaxis: SELECT * INTO OUTFILE "nombre del fichero' FIELDS TERMINATED BY 'indicador de final de campo' ENCLOSED BY 'caracteres delimitadores de campos' LINES STARTING BY 'caracteres indicadores de comienzo de registro' TERMINATED BY 'caracteres indicadores del final de registro' FROM nombre de la tabla

<?php $base="ejemplos"; $c=mysql_connect ("localhost","pepe","pepa"); mysql_select_db ($base, $c); $query="SELECT * INTO OUTFILE "; $query.="'".$_SERVER['DOCUMENT_ROOT'].'/php/alumnos.txt'."'"; $query.= " FIELDS ENCLOSED BY '\"' TERMINATED BY ';' "; $query.=" LINES STARTING BY '*' TERMINATED BY '\r\n' "; $query.=" FROM alumnos"; if(mysql_query($query,$c)){ print "fichero alumnos.txt creado<br>"; }else{ print mysql_error ($c)."<br>". mysql_errno ($c); } $query="SELECT * INTO OUTFILE "; $query.="'".$_SERVER['DOCUMENT_ROOT'].'/php/domicilios.txt'."'"; $query.= " FIELDS ENCLOSED BY '|' TERMINATED BY '*;' "; $query.=" LINES STARTING BY '#' TERMINATED BY '}' "; $query.=" FROM domicilios"; if(mysql_query ($query,$c)){ print "fichero domicilios.txt creado<br>"; }else{ print mysql_error ($c)."<br>".mysql_errno ($c); } $query="SELECT * INTO OUTFILE "; $query.="'".$_SERVER['DOCUMENT_ROOT'].'/php/notas.txt'."'"; $query.=" FROM notas"; if(mysql_query ($query,$c)){ print "fichero notas.txt creado<br>"; }else{ print mysql_error ($c)."<br>".mysql_errno ($c); } $query="SELECT * INTO OUTFILE "; $query.="'".$_SERVER['DOCUMENT_ROOT'].'/php/evaluaciones.txt'."'"; $query.= " FIELDS ENCLOSED BY '\'' TERMINATED BY ',' ";

$query.=" LINES STARTING BY ' ' TERMINATED BY '\r\n' "; $query.=" FROM evaluaciones"; if(mysql_query ($query,$c)){ print "fichero evaluaciones.txt creado<br>"; }else{ print mysql_error ($c)."<r>".mysql_errno ($c); } mysql_close(); ?> Cuidado! Al exportar ficheros en entornos Windows, si se pretende que en el fichero de texto aparezca un salto de lnea no basta con utilizar la opcin por defecto de LINES TERMINATED BY '\n' sino LINES TERMINATED BY '\r\n' (salto de lnea y retorno) que son los caracteres que necesita Windows para producir ese efecto. Habr de seguirse este mismo criterio cuando se trata de importar datos desde un fichero de texto.

Consultas de unin Consultas usando JOIN


La clasula JOIN es opcin aplicable a consultas en tablas que tiene diversas opciones de uso. Iremos vindolas de una en una. Todas ellas han de ir incluidas como parmetros de una consulta. Por tanto han de ir precedidas de: SELECT * o de SELECT nombre_tabla.nombre_campo,..

donde nombre_tabla es un nombre de tabla y nombre_campo es el nombre del campo de esa tabla que pretendemos visualizar para esa consulta. Esta sintaxis es idntica a la ya comentada en pginas anteriores cuando tratbamos de consultas en varias tablas. Ahora veremos las diferentes posibilidades de uso de JOIN FROM tabla1 JOIN tabla2

Suele definirse como el producto cartesiano de los elementos de la primera tabla (tabla1) por lo de la segunda (tabla2). Dicho de una forma ms vulgar, esta consulta devuelve con resultado una lista de cada uno de los registros de la primera tabla asociados sucesivamente con todos los correspondientes a la segunda. Es decir, aparecer una lnea conteniendo el primer registro de la primera tabla seguido del primero de la segunda. A continuacin, ese mismo registro de la primera tabla acompaado del segundo de la segunda tabla, y as, sucesivamente hasta acabar los registros de esa segunda tabla. En ese momento, repite el proceso con el segundo registro de la primera tabla y, nuevamente, todos los de la segunda. As, sucesivamente, hasta llegar al ltimo registro de la primera tabla asociado con el ltimo de la segunda. En total, devolver un nmero de lneas igual al resultado de multiplicar el nmero de registros de la primera tabla por los de la segunda. FROM tabla2 JOIN tabla1

Si permutamos la posicin de las tablas, tal como indicamos aqu, obtendremos el mismo resultado que en el caso anterior pero, como es lgico pensar, con una ordenacin diferente de los resultados. FROM tabla2 JOIN tabla1 ON condicion

El parmetro ON permite aadir una condicin (condicion) a la consulta de unin. Su comportamiento es idntico al de WHERE en las consultas ya estudiadas y permite el uso de las mismas procedimientos de establecimiento de condiciones que aquel operador. FROM tabla1 LEFT JOIN tabla2 ON condicion

Cuando se incluye la clusula LEFT delante de JOIN el resultado de la consulta es el siguiente: Devolvera cada uno los registros de la tabla especificada a la izquierda de LEFT JOIN sin considerar las restricciones que puedan haberse establecido en las clasulas ON para los valores de esa tabla asocindolos con aquellos de la otra tabla que cumplan las condiciones establecidas en la clasula ON. Si ningn registro de la segunda tabla cumpliera la condicin devolvera valores nulos. FROM tabla1 RIGHT JOIN tabla2 ON condicion

Se comporta de forma similar al anterior. Ahora los posibles valores nulos sern asignados a la tabla indicada a la izquierde de RIGHT JOIN y se visualizaran todos los registros de la tabla indicada a la derecha.

JOIN mltiples
Tal como puedes observar en el ejemplo, es perfectamente factible utilizar conjuntamente varios JOIN, LEFT JOIN y RIGHT JOIN. Las diferentes uniones irn ejecutndose de izquierda a derecha (segn el orden en el que estn incluidos en la sentencia) y el resultado del primero ser utilizado para la segunda unin y as sucesivamente. En cualquier caso, es posible alterar ese orden de ejecucin estableciendo otras prioridades mediante parntesis.

UNION de consultas
MySQL permite juntar en una sola salida los resultados de varias consultas. La sintaxis es la siguiente: (SELECT ...) UNION ALL (SELECT ...) UNION ALL (SELECT ...) Cada uno de los SELECT ha de ir encerrado entre parntesis.

Ejemplo de consultas de unin (JOIN)


<?php $base="ejemplos"; $c=mysql_connect ("localhost","pepe","pepa"); mysql_select_db ($base, $c); # vamos a crear un array con las diferente consultas # posteriormente lo leeremos y la ejecutaremos secuencialmente /* Devuelve todos los campos de ambas tablas. Cada registro de alumnos es asociado con todos los de domicilios*/ $query[]="SELECT * FROM alumnos JOIN domicilios"; /* Devuelve todos los campos de ambas tablas. Cada registro de domicilios es asociado con todos los de alumnos */ $query[]="SELECT * FROM domicilios JOIN alumnos"; /* Devuelve todos los campos de los registros de ambas tablas en los que coinciden los numeros del DNI*/ $query[]="SELECT * FROM alumnos JOIN domicilios ON domicilios.DNI=alumnos.DNI"; /* Idntica a la anterior. Solo se diferencia en que ahora se visualizan antes los campos domicilios*/ $query[]="SELECT * FROM domicilios JOIN alumnos ON domicilios.DNI=alumnos.DNI";

/* devuelve cada uno de los registro de la tabla alumnos. Si existe un domicilio con igual DNI lo insertar. Si no existiera insertar valores nulos en esos campos $query[]="SELECT * FROM alumnos LEFT JOIN domicilios ON domicilios.DNI=alumnos.DNI"; /* Se comporta de forma idntica al anterior. Ahora insertar todos los registros de domicilios y los alumnos coincidentes o en su defecto campos nulos.*/ $query[]="SELECT * FROM domicilios LEFT JOIN alumnos ON domicilios.DNI=alumnos.DNI"; /* Al utilizar RIGHT ser todos los registros de la tabla de la derecha (domicilios) los que aparezcan junto con las coincidencias o junto a campos nulos. Aparecern primero los campos de alumnos y detr los de domicilios*/ $query[]="SELECT * FROM alumnos RIGHT JOIN domicilios ON (domicilios.DNI=alumnos.DNI AND alumnos.Nombre LIKE 'A%')"; /* Consulta de nombre, apellido y localidad de todos los alumnos cuyo nombre empieza por A */ $query[]="SELECT alumnos.Nombre, alumnos.Apellido1,alumnos.Apellido2, domicilios.poblacion FROM alumnos JOIN domicilios ON (domicilios.DNI=alumnos.DNI AND alumnos.Nombre LIKE 'A%')"; # una consulta resumen de nos permitir visualizar una lista con nombre # y apellidos de alumnos su direccin y localidad del domicilio # el nombre de la evaluacin y su calificacin. # Si no hay datos de poblacin insertar ---- en vez del valor nulo # y si no hay calificacin en una evaluacin aparecer N.P. # La consulta aparecer agrupada por evaluaciones /* iniciamos el select especificando los campos de las diferentes tablas que prentendemos visualizar */ $q="(SELECT alumnos.Nombre,alumnos.Apellido1,"; $q.=" alumnos.Apellido2,domicilios.calle,"; # al incluir IFNULL visualizaremos ---- en los campos cuyo resultado # sea nulo $q.=" IFNULL(domicilios.poblacion,''),"; $q.=" evaluaciones.nombre_evaluacion,"; # con este IFNULL aparecer N.P. en las evaluaciones no calificadas. $q.=" IFNULL(notas.calificacion,'N.P.')"; # especificamos el primer JOIN con el que tendremos como resultado una lista # de todos los alumnos con sus direcciones correspondientes # por efecto de la clausula ON. # Al poner LEFT se incluiran los alumnos que no tuvieran # su direccin registrada en la tabla de direccione $q.=" FROM (alumnos LEFT JOIN domicilios"; $q.=" ON alumnos.DNI=domicilios.DNI)"; # al unir por la izquierda con notas tendramos todos los resultados # del JOIN anterior asociados con con todas sus calificaciones # por efecto de la clasula ON $q.=" LEFT JOIN notas ON notas.DNI=alumnos.DNI"; # al aadir esta nueva unin por la DERECHA con la tabla evaluaciones # se asociara cada uno de los resultados de las uniones anteriores # con todos los campos de la tabla evaluaciones con lo que resultara # una lista de todos los alumnos con todas las calificaciones # incluyendo un campo en blanco (sera sustituido por N.P:) # en aquellas que no tuvieran calificacin registrada $q.=" RIGHT JOIN evaluaciones"; $q.=" ON evaluaciones.NUMERO=notas.evaluacion "; /* la clausula WHERE nos permite restringir los resultados a los valores correspondientes nicamente a la evaluacin nmero 1*/ $q.=" WHERE evaluaciones.NUMERO=1)"; # cerramos la consulta anterior con el parntesis. Observa que lo # hemos abierto delante del SELECT e insertamos UNION ALL

# para que el resultado de la consulta anterior aparezca # seguido del correspondiente a la incluida despus de UNION ALL $q.=" UNION ALL"; #iniciamos (tambin con parntesis) la segunda consulta # que ser identica a la anterior salvo el WHERE # ser modificado para extraer datos de la evaluacin n2 $q.="(SELECT alumnos.Nombre,alumnos.Apellido1,"; $q.=" alumnos.Apellido2,domicilios.calle,"; $q.=" IFNULL(domicilios.poblacion,''),"; $q.=" evaluaciones.nombre_evaluacion,"; $q.=" IFNULL(notas.calificacion,'N.P.')"; $q.=" FROM (alumnos LEFT JOIN domicilios"; $q.=" ON alumnos.DNI=domicilios.DNI)"; $q.=" LEFT JOIN notas ON notas.DNI=alumnos.DNI"; $q.=" RIGHT JOIN evaluaciones"; $q.=" ON evaluaciones.NUMERO=notas.evaluacion"; $q.=" WHERE evaluaciones.NUMERO=2)"; # hemos cerrado el parentesis de la consulta anterior # e incluimos un nuevo UNION ALL para consultar los datos # correspondientes a la tercera evaluacin $q.=" UNION ALL"; $q.="(SELECT alumnos.Nombre,alumnos.Apellido1,"; $q.=" alumnos.Apellido2,domicilios.calle,"; $q.=" IFNULL(domicilios.poblacion,''),"; $q.=" evaluaciones.nombre_evaluacion,"; $q.=" IFNULL(notas.calificacion,'N.P.')"; $q.=" FROM (alumnos LEFT JOIN domicilios"; $q.=" ON alumnos.DNI=domicilios.DNI)"; $q.=" LEFT JOIN notas ON notas.DNI=alumnos.DNI"; $q.=" RIGHT JOIN evaluaciones"; $q.=" ON evaluaciones.NUMERO=notas.evaluacion"; $q.=" WHERE evaluaciones.NUMERO=3)"; # incluimos la variable $q en el array de consultas $query[]=$q; # leemos el array y visualizamos el resultado # cada consulta a traves de la llamada a la funcion visualiza # a la que pasamos el resultado de la consulta # y la cadena que contiene las sentencias de dicha consulta foreach($query as $v){ visualiza(mysql_query($v,$c),$v); } function visualiza($resultado,$query){ PRINT "<BR><BR><i>Resultado de la sentencia:</i><br>"; print "<b><font color=#ff0000>"; print $query."</font></b><br><br>"; PRINT "<table align=center border=2>"; while ($registro = mysql_fetch_row($resultado)){ echo "<tr>"; foreach($registro as $valor){ echo "<td>",$valor,"</td>"; } } echo "</table><br>"; } ?>
Ejecutar script

Seguridad en MySQL Inyeccin de cdigo


Lo conocido como inyeccin de cdigo o inyeccin SQL no es otra cosa que una tcnica mediante la cual un intruso utiliza las vulnerabilidades de las sentencias MySQL para propsitos distintos a los previstos en la aplicacin. Veamos los siguientes ejemplos. Se trata de una consulta en nuestra tabla demo4 que debe extraer una lista de usuarios cuyo nombre coincida con el que se inserte en en un campo del formulario que se incluye en el documento.
Ver ejemplo Ver ejemplo Ver cdigo fuente

La ejecucin de primero de los ejemplos manteniendo el valor por defecto nos dar la respuesta esperada que es la lista de todas las personas de la tabla cuyo nombre coincide con Telesfora. Si hacemos lo mismo con el segundo ejemplo la respuesta ser totalmente inesperada. Hemos pedido una lista de personas cuyo nombre coincida con ' or '34=34 y, contra todo pronstico (no hay nadie que se llame as en nuestra tabla) nos aparece una lista de todos los registros de la tabla. La explicacin es la siguiente. La clasula WHERE de la consulta contiene lo siguiente: WHERE (Nombre='$nombre'). Al recibir el valor' or '34=34 sustituir $nombre por ' or '34=34 y se convertir en: WHERE (Nombre='' or '34=34'). Es evidente que 34 es siempre igual a 34 como lo sera 13=13 o 1=1. Por lo tanto la condicin se cumple sea cual sea el nombre y por esa razn nos aparece la lista de todos los registros. Puede que aqu no tenga demasiada importancia pero imagina que ese formulario se usa para comprobar un nombre de usuario y una contrasea en una tabla de usuarios. Estaramos accediendo sin dificultad alguna a un lugar al que no nos estara permitido. Para evitar la posibilidad de ese efecto indeseado (inyeccin de cdigo) PHP dispone de la funcin: mysql_real_escape_string(cadena) que hace una llamada a la librera MySQL del mismo nombre y para que escape los caracteres especiales contenidos en lacadena de forma que sea mucho ms seguro su uso a travs de mysql_query(). Los caracteres que son escapados son los siguientes:\x00, \n, \r, \, ', " y \x1a. Se convertiran en: \\x00, \\n, \\r, \\\, \', \" y \\x1a con lo cual la cadena ' or '34=34 se convertira en \' or \'34=34 y la clasula anteriormente comentada se convertira en WHERE (Nombre='\' or \'34=34') con lo cual ya no se producira el efecto indeseado y se evitara el riesgo de uso inadecuado.

Cuidado! Dado que la funcin mysql_real_escape_string() se utiliza para hacer una llamada a la librera MySQL del mismo nombre, para su uso es necesario que el servidor MySQL est activo. De lo contrario se producira un error. Si se van a insertar datos binarios es necesario utilizar mysql_real_escape_string() o addslashes() con preferencia de la primera.

Aunque los desarrolladores de PHP anuncian su prxima desaparicin, en la actualidad hay en el fichero php.ini una directiva llamadamagic_quotes_gpc cuyo valor por defecto es Off. Si cambiramos esa directiva a On (o si usramos un servicio externo que la tuviera configurada de esta forma) todos los datos recibidos por medio de los mtodos GET o POST seran tratados por la funcin: addslashes(cadena)

que devuelve la cadena despus de haber escapado los carcteres ',", \ y NUL (el byte NULL). La accin de addslashes puede deshacerse utilizando la funcin stripslashes(cadena_escapada)

que quita los carcteres de escape aadidos por addslashes devolviendo la cadena original. Para comprobar como est configurada la directiva magic_quotes_gpc disponemos de la funcin:

get_magic_quotes_gpc() que devuelve un valor booleano. True si est configurada como On y False en caso de estarlo como Off.

Filtrado de cdigo
Mediante un proceso como el que puedes ver en el cdigo fuente que se incluye a continuacin puede realizarse un filtrado de los eventuales intentos de inyeccin de cdigo. Su funcionamiento es el siguiente: Leemos toda la informacin que se recibe en las variables superglobales $_GET y $_POST. Recorremos los arrays que recogen esos resultados sustituyendo sus valores por los obtenidos de la aplicacin de una funcin que realiza el filtrado. La funcin que realiza el filtrado comprueba el estado de magic_quotes. Caso de estar configuradas con On revierte los caracteres escapados para impedir que se dupliquen los carcteres de escape. Comprueba si es numrico el valor recibido y en caso de serlo lo devuelve sin ninguna modificacin. Si el valor recibido no es numrico aplica la funcin mysql_real_escape_string y devuelve el resultado dentro de unas comillas simples. De esta forma podramos despreocuparnos de poner comillas al valor de la variable en la clasula WHERE. Si se trata de un nmero no las riquere y si se trata de una cadena el valor recibido ya las incluye.

<?php if(is_array($_GET)){ foreach ($_GET as $_GET_indice=>$_GET_valor){ $_GET[$_GET_indice]=filtro_seguridad($_GET_valor); } } if(is_array($_POST) ){ foreach ($_POST as $_POST_indice=>$_POST_valor){ $_POST[$_POST_indice]= filtro_seguridad($_POST_valor); } } function filtro_seguridad($valor){ /* comprueba si estn activas las magic_quotes y, en caso de estarlo revierte su accin mediante stripslashes */ if (get_magic_quotes_gpc()) $valor = stripslashes($valor); /* por compatibilidad entre versiones Windows - Ubuntu abrimos una conexin con MySQL antes de aplicar mysql_real_escape_string */ $c=mysql_connect("localhost","pepe","pepa"); /* con la certeza de que estamos ante la cadena original aplicamos la funcin mysql_real_escape_string a todas las cadenas no numricas */ if (!is_numeric($valor)) $valor = "'" .mysql_real_escape_string($valor) . "'"; /* cerramos la conexion y devolvemos el resultado*/ mysql_close($c); return $valor; } ?>
Hemos guardado este cdigo en un fichero llamado no_inyeccion.inc.php" y hemos hecho dos modificaciones en el ejemplo anterior. Por una parte hemos incluido este fichero mediante la opcin include y por otra hemos quitado las comillas a WHERE (Nombre='$nombre')dejndolo como WHERE (Nombre=$nombre). Este es el ejemplo resultante:
Ejecutar consulta Ver cdigo fuente

Borrado de usuarios MySQL


Hasta el momento no hemos modificado ni los usuarios de MySQL ni la configuracin de PHPMyAdmin. An tenemos los usuarios por defecto (root sin contrasea) y PHPMyAdmin sigue dndonos el mensaje de advertencia relativo al fallo de seguridad de la configuracin.

El primer paso para corregir esa vulnerabilidad ser borrar los usuarios dejando slo el usuario pepe que es el que hemos creado al instalar MySQL. Para ello, con el servidor MySQL activo, abriremos http://localhost/phpMyAdmin/ editaremos la tabla user correspondiente a la base de datos mysql y borraremos los usuarios, dejando nicamente al usuario pepe.

Una vez realizados estos cambios, deberamos cerrar el servidor MySQL y reiniciarlo con la nueva configuracin. A partir de aqu, cuando tratamos de acceder de nuevo a PHPMyAdmin nos aparecer un mensaje de error tal como el que vemos en la imagen.

PHPMyAdmin nos dar este mensaje de error porque su configuracin por defecto utiliza el usuario root que ya no existe. Acabamos de borrarlo!

Modificacin de la configuracin de PHPMyAdmin


Hemos de modificar el fichero config.inc.php que est en el sudirectorio libraires de MyAdmin. Durante el proceso de instalacin habamos hecho algunos cambios en este fichero (algunos de ellos para evitarnos tener que teclear continuamente nombres de usuario y contrasea) que ahora vamos a deshacer.
Fichero inicial Guardar como Lnea

config.inc.php config.inc.php
Cambios Donde dice:

Modificaciones en el fichero config.inc.php

168

$cfg['Servers'][$i]['auth_type'] = 'config';
cambiar por:

$cfg['Servers'][$i]['auth_type'] = 'http';
Donde dice:

218

$cfg['Servers'][$i]['nopassword'] = true;
cambiar por:

$cfg['Servers'][$i]['nopassword'] = false;
Donde dice:

345

$cfg['Servers'][$i]['AllowNoPasswordRoot'] = true;
cambiar por:

$cfg['Servers'][$i]['AllowNoPasswordRoot'] =false; Al cambiar config por http estaremos establecimiento este ltimo valor como mtodo de autentificacin de los usuarios. Los otros dos cambios (que ahora hacemos igual a false) significan que no vamos a permitir el acceso sin contrasea a ningn usuario, incluido un eventual usuario root sin contrasea que pudiera quedar registrado desde el proceso inicial de instalacin.

Acceso a PHPmyAdmin
A partir del momento que hayamos hecho los cambios anteriores, cada vez que tratemos de acceder a http://localhost/phpmyadmin/ va a aparecer una ventana como la que vemos en la imagen. Ser necesario introducir un nombre de usuario vlido (pepe en nuestro caso). Nos desaparecer el mensaje de advertencia y ya podremos gestionar nuestras bases de datos de forma un poco ms segura.

Empezando con XML XML


XML son las siglas de eXtensible Markup Language (lenguaje de marcas extensible) que es un metalenguaje que nos permite definirlenguajes de marcado acordes a nuestras necesidades. Se trata bsicamente de poder definir nuestras propias etiquetas (marcas) para establecer una estructura destinada al almacenamiento de datos. La libertad de establecimiento de nuestra estructura de marcas est nicamente limitada al cumplimiento de las normas del metalenguaje XML.

Los primeros pasos en XML


Los documentos XML deben tener como extensin xml y es muy aconsejable que estn codificados en en formato UNICODE. Nosotros, tal como detallamos en los ejemplos, vamos a guardar todos los documentos XML con codificacin UTF8. De esta forma estaremos evitando los problemas que nos han surgido en el primero de los ejemplos que incluimos un poco ms adelante. Todo documento XML debe comenzar con un prlogo de tipo: <?xml version="1.0" ?>

Como puedes ver se utiliza una sintaxis muy prxima a la de PHP (<?php y ?>) esta vez con un xml obligatorio y situado inmediatamente detrs de <?. Cuando usamos la configuracin short_open_tag=off (descrita aqu) estaremos diferenciando claramente las etiquetas php (<?php) de las XML que comienzan por <?xml.

Respecto al atributo version se le asigna el valor 1.0 ya que esta es la nica versin existente hasta el momento. Esta primera lnea de los documentos XML, conocida como prlogo, puede incluir otros atributos que comentaremos ms adelante. Si creramos un documento con esa nica lnea, la visualizacin sera la que puedes ver pulsando aqu. Como puedes observar el mensaje de error se produce porque un documento XML ha de tener obligatoriamente un cuerpo formado por un nico elemento (elemento raz definido por una etiqueta de apertura y otra de cierre) que ser que vaya a contener a todos los dems elementos que puedan incluirse en el documento. Dicho de otra forma, los documentos XML han de incluir, a continuacin de la lnea prlogo, una etiqueta del tipo <nombre_etiqueta> y han de acabar con </nombre_etiqueta> pudiendo ser nombre_etiqueta cualquier palabra que cumpla la especificacin XML 1.0 que establece que un nombre empieza con una letra o uno o ms signos de puntuacin, y contina con letras, dgitos, guiones, rayas, dos puntos o puntos, denominados de forma global como caracteres de nombre. Los nombres que empiezan con la cadena "xml" se reservan para la estandarizacin de esta o de futuras versiones de esta especificacin. Debemos tener muy presente que los nombres de las etiquetas o marcas son sensibles a maysculas y minsculas. La estructura de un documento XML recuerda mucho los bucles anidados (siempre uno dentro del otro) y/o la interpretacin matemtica de las estructuras delimitadas por parntesis, corchetes y/o llaves. Cada elemento XML delimitado por sus etiquetas de apertura y cierre puede tener como contenido ms elementos, cadenas de caracteres, ambas cosas, o carecer de contenido (elemento vaco). Lneas de comentario las lneas de comentario tienen una sintaxis idntica a la utilizada para el mismo fin en la edicin HTML. Todo comentario comienza con <!-- y acaba con --> Etiquetas con atributos De forma similar al HTML en las marcas (de apertura) XML pueden incluirse los atributos que se desee siempre que se utilice la siguiente sintaxis: <marca atributo="valor" > <marca atributo='valor' >

siendo en este caso obligatorio que los valores vayan entre comillas (simples o dobles). Dentro de una misma etiqueta podemos incluir tantos atributos como deseemos y, de igual forma que en aquellas, tambin a los atributos podemos asignarles el nombre que deseemos. Caracteres especiales Puede ocurrir que los textos que pretendamos introducir dentro de un elemento requieran el uso de caracteres especiales que puedieran provocar conflictos con los utilizados para delimitar etiquetas y/o valores de los atributos. En XML existen entidades que pueden utilizarse para que esos caracteres sean interpretados como texto y no como elementos de marcado. Son estos: Entidad &amp; &lt; &gt; &apos; &quot; Caracter & < > ' "

Otra forma de incluir informacin que contenga caracteres especiales puede ser esta: <![CDATA[ caracteres raros ]]>

donde pueden incluirse cualesquiera caracteres con la excepcin de la cadena ]]> que se confundira con el cierre del bloque CDATA.

Documentos XML bien formados


Los documentos denominados bien formados (well formed en ingls) son aquellos que cumplen con todas las definiciones bsicas de formato y pueden, por lo tanto, analizarse correctamente por cualquier parser (analizador sintctico) que cumpla con la norma. Por el momento nos bastar con comprobar que los documentos estn bien formados y saber que bien formado y vlido son cosas distintas y que un documento bien formado puede no ser vlido o viceversa. El sitio World Wide Web Consortium (W3C) dispone de un servicio que permite comprobar la buena formacin de un documento XML.

En las imgenes podemos ver los resultados de la comprobacin de un fichero. En la primera de la ventanas elegimos la opcinValidate by Direct Imput, pegamos el contenido de nuestro documento el rea del texto del formulario, pulsamos el botn check y obtenemos el resultado de la validacin y los eventuales mensajes de error o advertencia.

El documento XML ms simple


Este es el ejemplo ms simple de un documento bien formado en XML. Ambos ejemplos tienen el contenido que puedes ver en el cdigo fuente. Si los compruebas pulsando los enlaces podrs observar que se comportan de forma diferente. El primero nos da un error mientras que el segundo parece correcto.

<?xml version="1.0" ?> <!-- Aqu los comentarios se ponen as -->

<cuerpo> Lo minimo minimorum </cuerpo>


ejemplo471.xml ejemplo472.xml

El origen del problema, en este caso, son los caracteres con tilde. El primer documento ha sido elaborado utilizando el Notepad++ y guardando con el formato por defecto (ANSI) de este editor. El segundo documento es el resultado de abrir el documento anterior con el bloc de notas de Windows y guardarlo sin modificar su contenido utilizando la opcin de codificacin UTF8 tal como puedes ver en la imagen.

Habramos obtenido igual resultado si al crear un archivo nuevo en Notepad++ hubiramos elegido la opcin UTF-8 tal como puedes ver en esta imagen.

Otros ejemplos
<?xml version="1.0" ?> <!-- Todo el contenido ha de ir dentro de esta etiqueta --> <ContieneTodo> <!-- La parte1 contiene informacin en forma de texto --> <parte1> Estos son los datos de la parte1 </parte1> <!-- Dentro de la parte2 incluiremos dos nuevas etiquetas con sus datos --> <parte2> Aqui pueden ir datos y tambin nuevas etiquetas <parte2_1> Incluimos ms datos, ahora en la parte 2_1 </parte2_1> Fuera de la parte 2_1 podemos aadir datos <parte2_2> Una nueva etiqueta y nuevos datos </parte2_2> </parte2> <!-- Aqui incluimos apertura y cierre en la misma etiqueta es una etiqueta vaca --> <parte3 /> </ContieneTodo>
ejemplo473.xml

Cuidado! Recuerda que los nombres de las etiquetas son sensibles a maysculas/minsculas por lo tanto < /contieneTodo>no cerrara < ContieneTodo> Tampoco debes olvidarte de guardar los documentos xml con codificacin UTF-8.

Un ejemplo algo ms completo de XML


<?xml version="1.0" ?> <!-- Despus de prlogo incluimos la etiqueta de apertura del elemento raiz (cuerpo_del_XML) que ser el que contenga todo y que se cerrar al final del documento --> <cuerpo_del_XML> <!-- Establecemos un elemento (alumnos) que va a contener los datos de todos los alumnos (lo marcamos en magenta) --> <alumnos> <!-- dentro de la etiqueta alumno (podremos poner cuantas queramos) incluimos inforamcion relativa a el. En este caso ponemos su nmero de orden como caracter y, adems, dentro de etiquetas contenedoras los datos nombre, apellidos, sexo y comentarios relativos a cada uno de ellos --> <alumno> 1 <nombre>Juan</nombre> <apellidos>Fernndez Gmez</apellidos> <sexo>Varn</sexo> <comentarios/> </alumno> <!-- En este caso incluiremos una entidad para representar el smbolo menor que en la etiqueta de comentarios --> <alumno> 2 <nombre>Luisa</nombre> <apellidos>Garca Bermdez</apellidos>

<sexo>Hembra</sexo> <comentarios>Es la &lt; de 17 hermanos</comentarios> </alumno> </alumnos> <!-- Establecemos un elemento (profes) que va a contener los datos de los profesores (lo marcamos en magenta) --> <profes> <!-- El nmero de orden y el sexo de los profesores los insertamos ahora como atributos del elemento profe. Es una opcin alternativa a la usada en el caso de los alumnos --> <profe sexo="Varon" numero="1"> <nombre>Alejandro</nombre> <apellidos>Iglesias Fernndez</apellidos> <comentarios></comentarios> </profe> <!-- Los comentarios relativos a esta profesora los incluimos usando CDATA para evitar posibles conflictos con los caracteres especiales --> <profe sexo="Hembra" numero="2"> <nombre>Liliana</nombre> <apellidos>Fernndez de Arriba</apellidos> <comentarios> <![CDATA[ Es la < de los ^profes^ y "profas" ]]> </comentarios> </profe> </profes> <!-- incluimos un nuevo elemento padres que, por el momento, dejamos vaco --> <padres> </padres> </cuerpo_del_XML>
ejemplo474.xml

Exportacin de tablas MySQL a ficheros XML


No es infrecuente que se plantee la necesidad de intercambiar informacin entre dos formatos de almacenamiento. En los ejemplos siguientes hemos descrito el proceso de lectura de tablas MySQL y su transformacin en ficheros con formato XML. En este primer ejemplo hemos hecho la transformacin considerando que cada campo de la tabla fuera convertido en un elemento del fichero XML

<?php /* establecemos una conexin con la base de datos ejemplos de MySQL */ $base="ejemplos"; $tabla="demo4"; $conexion=mysql_connect("localhost","pepe","pepa"); mysql_select_db($base,$conexion); /*leemos todos los campos de la tabla y todos los registros */ $resultado= mysql_query("SELECT * FROM $tabla" ,$conexion); /* inicializamos una variable con la primera etiqueta obligatoria de los ficheros xml. Ponemos \n para incluir un salto de lnea */ $xml= "<?xml version=\"1.0\" ?>\n"; /* ponemos la etiqueta de apertura del elemento raiz. En este caso le asignamos el nombre de la tabla aunque podramos ponerle cualquier otro nombre y lo agregamos alla variable que recoger toda la informacin */ $xml.= "<".$tabla.">\n"; /* leemos todas la filas del resultado filtrando aquellos elementos de array asociativo sern precisamente esos indices los que utilizaremos para asignar nombre a los elementos hijos del array */ while ($registro = mysql_fetch_array($resultado,MYSQL_ASSOC)){

/* cada registro ser un elemento xml. Le pondremos como nombre usuario aunque podramos ponerles cualquier otro nombre y lo agregamos a la variable que recoger todo*/ $xml.= "<usuario>\n"; /* leemos el buche de los resultado y vamos aadiendo etiquetas de apertura con el mismo nombre que el ndice asociativo, con el valor contenido en el array (codificado utf8 para evitar problemas de lectura del xml y despus ponemos la etiqueta de cierre con el mismo nombre que la de apertura) */ foreach($registro as $indice=>$valor){ $xml.= "<".$indice.">".utf8_encode($valor)."</".$indice.">\n"; } /* leido el registro completo aadimos la etiqueta de cierre del usuario */ $xml.= "</usuario>\n"; } /* aadimos la etiqueta de cierre del elemento raiz */ $xml.= "</".$tabla.">\n"; /* cerramos la conexin con la base de datos */ mysql_close(); /* escribimos el contenido de la variable que recoge toda la informacin en un fichero xml y colocamos un enlace para poder visualizarlo en el navegador */ if (file_put_contents("demo4.xml",$xml)){ print '<a href="demo4.xml">Ver el fichero demo4.xml que acaba de crearse</a>'; }else{ print "El fichero demo4.xml no ha podido crearse. Ha habido un error"; } ?>
Crear fichero XML

Este otro ejemplo es una modificacin del anterior. En este caso hemos optado por convertir uno de los campos de la tabla en atributo de uno de los elementos del fichero XML.

<?php /* establecemos una conexin con la base de datos ejemplos de MySQL */ $base="ejemplos"; $tabla="demo4"; $conexion=mysql_connect("localhost","pepe","pepa"); mysql_select_db($base,$conexion); /*leemos todos los campos de la tabla y todos los registros */ $resultado= mysql_query("SELECT * FROM $tabla" ,$conexion); /* inicializamos una variable con la primera etiqueta obligatoria de los ficheros xml. Ponemos \n para incluir un salto de lnea */ $xml= "<?xml version=\"1.0\" ?>\n"; /* ponemos la etiqueta de apertura del elemento raiz. En este caso le asignamos el nombre de la tabla aunque podramos ponerle cualquier otro nombre y lo agregamos alla variable que recoger toda la informacin */ $xml.= "<".$tabla.">\n"; /* leemos todas la filas del resultado filtrando aquellos elementos de array asociativo sern precisamente esos indices los que utilizaremos para asignar nombre a los elementos hijos del array */ while ($registro = mysql_fetch_array($resultado,MYSQL_ASSOC)){ /* cada registro ser un elemento xml. Le pondremos como nombre usuario e incluiremos ahora el Sexo como atributo en la etiqueta usuario asignando como valor el contenido de el elemento del mismo nombre del array resultante de la lectura de la tabla*/ $xml.= "<usuario Sexo='".$registro['Sexo']. "' >\n";

/* leemos el buche de los resultado y vamos aadiendo etiquetas de apertura con el mismo nombre que el ndice asociativo, con el valor contenido en el array (codificado utf8 para evitar problemas de lectura del xml y despus ponemos la etiqueta de cierre con el mismo nombre que la de apertura Excluimos el de indice Sexo que ya ha sido incluido como atributo del usuario */ foreach($registro as $indice=>$valor){ if ($indice !='Sexo'){ $xml.= "<".$indice.">".utf8_encode($valor)."</".$indice.">\n"; } } /* leido el registro completo aadimos la etiqueta de cierre del usuario */ $xml.= "</usuario>\n"; } /* aadimos la etiqueta de cierre del elemento raiz */ $xml.= "</".$tabla.">\n"; /* cerramos la conexin con la base de datos */ mysql_close(); /* escribimos el contenido de la variable que recoge toda la informacin en un fichero xml y colocamos un enlace para poder visualizarlo en el navegador */ if (file_put_contents("demo4_1.xml",$xml)){ print '<a href="demo4_1.xml">Ver el fichero demo4_1.xml que acaba de crearse</a>'; }else{ print "El fichero demo4_1.xml no ha podido crearse. Ha habido un error"; } ?>
Crear fichero XML

Manipulando ficheros XML desde PHP La extensin DOM


La Extension DOM de PHP permite manipular documentos XML mediante las funciones y procedimientos DOM incluidos en una clase de PHP 5 llamada DOMDocument. Esta extensin viene incluida por defecto en PHP y no requiere ninguna modificacin del fichero php.ini para ser utilizada.

El DOM (Document Object Model) presenta un documento XML como una estructura de rbol.

Tipos de nodos
Cada uno de los elementos (nodos) que puede contener un documento corresponde a uno de los tipos siguientes:

1 2 3 4 5 6

ELEMENT NODE ATTRIBUTE NODE TEXT NODE CDATA SECTION NODE ENTITY REFERENCE NODE ENTITY NODE PROCESSING INSTRUCTION 7 NODE 8 COMMENT NODE 9 DOCUMENT NODE 10 DOCUMENT TYPE NODE DOCUMENT FRAGMENT 11 NODE 12 NOTATION NODE
siendo los verdaderamente tiles para nuestros fines los sealados en rojo en la tabla anterior. Se refieren a los componentes de los documentos XML descritos en la pgina anterior.

Organizacin de los nodos


En esta ventana ests visualizando el documento ejemplo474.xml que hemos creado en la pgina Los componentes de un documento XML estn organizados por niveles de dependencia y dentro de cada uno de esos niveles poritems numerados (siempre a partir de cero) segn el orden de creacin de cada uno de ellos. Como podrs observar el nivel superior del documento permite un nico elemanto con la nica excepcin de admitir tambin la inclusin de lneas de comentario. Por esa razn el comentario que dice: Despus de prlogo... se identifica como item cero item(0) mientras que el elemento raiz del documento se idenficara como item(1). Por otra parte, los elementos de cada nivel se pueden identificar como hijos (childNodes) de un nodo padre (parentNodes). De esta forma, del elemento que contiene el nombre Juan podramos decir que: es el hijo nmero uno item(1) del nodo llamado alumno que, a su vez, es el hijo nmero tres item(3)) de un padre llamado alumnos que es tambin el tercer hijo item(3))del elemento raz que es el item sealado con el nmero uno item(1)) entre los hijos del objeto XML. Indicada a modo de rbol geneolgico, la secuencia: objeto XML -> childNodes ->item(1) -> childNodes ->item(3) -> childNodes ->item(3) -> childNodes ->item(1) nos conducira hasta el elemento que contiene el valor Juan. Otra forma de identificar nodos utilizando sus nombres. objeto XML -> documentElement->getElementsByTagName('alumno')->item(0)->getElementsByTagName('nombre')->item(0) nos hara el siguiente recorrido. objeto XML->documentElement nos llevara al nodo raz del documento. Por medio degetElementsByTagName('alumno') obtendramos la lista de todos los alumnos contenidos en el documento. A travs de item(0) nos situaramos el el nodo del primero de los alumnos. Por medio de getElementsByTagName('nombre') buscaramos la lista de hijos del anterior cuyo nombre es nombre. De ellos tomaramos el primero (en este caso el nico) mediante item(0).

La clase DOMDocument
El constructor de la clase DOMDocument crear un objeto utilizando la sintaxis siguiente: $objeto= new DOMDocument('version','codificacion') donde $objeto es el identificador del nuevo objeto y donde version y codificacion son dos cadenas opcionales que incluiran respectivamente el nmero de la versin del nuevo documento XML (actualmente solo es posible la versin 1.0) y el formato de codificacin del documento con valores tales como 'utf-8' o ''.

Propiedades de DOMDocument
Los objetos creados por la clase DOMDocument poseen, entre otras, las siguientes propiedades: encoding Recoge en una cadena el tipo de codificacin del documento tal como se especifica en el prlogo del mismo. Si no hubiera sido establecida el valor de esta propiedad sera una cadena vaca. xmlVersion Recoge en una cadena la versin del documento tal como se especifica en el prlogo del mismo. Como ocurra en el caso anterior, si no hubiera sido establecida su valor sera una cadena vaca. formatOutput Da formato a la salida aplicando sangras y espacios extra. Permite valores booleanos (true false). Por defecto toma el valor false. preserveWhiteSpace Es un valor booleano (TRUE por defecto) que indica si deben mantenerse los espacios redundandes en los contenidos del documento. nodeType Esta propiedad no es modificable. Devuelve un nmero comprendido entre 1 y 12 (son los de la tabla de tipos de nodos incluida ms arriba) que se corresponde con el tipo de nodo al que pertenece el objeto actual. nodeName Esta propiedad, que tampoco es modificable, contiene el nombre del nodo actual. nodeValue En esta propiedad se recoge el valor del contenido del nodo actual. Es modificable de la siguiente forma: $objeto->nodeValue=nuevo_valor

Mtodos de DOMDocument
Algunas de las funciones (mtodos) de esta clase son las siguientes: $objeto->load('fichero'); este mtodo permite incluir en un objeto DOMDocument el contenido de un fichero cuyo nombre y path se especifican en el parmetrofichero.

$raiz=$objeto->documentElement este mtodo permite recoger en un objeto llamado $raiz el contenido del nodo raz del objeto XML. $hijos=$objeto->childNodes este mtodo permite recoger en un objeto llamado $hijos el conjunto de los nodos hijos del $objeto $un_hijo=$objeto->childNodes->item(indice) este mtodo permite recoger en un objeto llamado $un_hijo el nodo hijo del $objeto cuya posicion es sealada por el nmero indice. $otro_objeto=$objeto->getElementsByTagName('nombre') este mtodo crea un objeto $otro_objeto que contiene todos los nodos del objeto $objeto cuyo nombre coincide con nombre. $otro_elemento=$objeto->getElementsByTagName('nombre')->item(indice) es una ampliacin de caso anterior. Ahora $otro_elemento contiene nicamente el nodo que ocupa la posicin sealada por indice en el conjunto de nodos cuyo nombre coincide con nombre. $otro_elemento=$objeto->getElementsByTagName('nombre')->item(indice)->getElementsByTagName('otro_nombre')>item(otro_indice) Una nueva ampliacin de casos anteriores. Ahora $otro_elemento contiene nicamente el nodo que ocupa la posicin sealada porotro_indice en el conjunto de nodos cuyo nombre coincide con otro_nombre y que a la vez son hijos del elemento de ndice indice del conjunto formado por los nodos de nombre nombre contenidos en el $objeto. La cadena podra alargarse con nuevas inclusiones. En este ejemplo puedes ver la forma de acceder a los diferentes nodos de un documento XML.

<?php /* creamos un objeto DOM con nombre $mi_XML*/ $mi_XML = new DOMDocument(); /* incluimos el fichero ejemplo474.xml en ese objeto */ $mi_XML->load('ejemplo474.xml'); /* leamos algunas de las propiedades de este objeto */ print "La propiedad encoding vale: ".$mi_XML->encoding."<br>"; print "La propiedad xmlVersion vale: ".$mi_XML->xmlVersion."<br>"; print "La propiedad formatOutput vale: ".$mi_XML->formatOutput."<br>"; print "preserveWhiteSpace vale: ".$mi_XML->preserveWhiteSpace ."<br>"; print "Como llegar al valor Juan <br><b>"; print $mi_XML->childNodes->item(1)->childNodes->item(3)->childNodes->item(3)-> childNodes->item(1)->nodeValue; /* para mayor comodidad podramos haber creado un objeto de esta forma: */ $juanito=$mi_XML->childNodes->item(1)->childNodes->item(3)->childNodes->item(3)>childNodes->item(1); /* al imprimir el valor de la propiedad nodeValue del nuevo objeto dar el mismo resultado que en el caso anterior */ print "</b><br />tambin as se llega: ".$juanito->nodeValue; print "</b><br />Otra forma de llegar: "; print $mi_XML->documentElement->getElementsByTagName('alumno')->item(0)-> getElementsByTagName('nombre')->item(0)->nodeValue; /*$mi_XML->documentElement nos llevara al nodo raz. getElementByTagName('alumno') nos dara los nodos (contenidos en el raiz) que tienen por nombre alumno. El item(0) que le sigue indicara que vamos al primero de los nodos alumno y all mediante getElementsByTagName('nombre')

buscaramos el array que contiene los elementos nombre de ese alumno concreto. Como solo hay un nombre estar identificado por el ndice 0 (item(0)) y de este ya extraeramos el valor */ print "</b><br>Vamos a conocer el nombre del nodo padre de Juan:<br><b>"; print $juanito->parentNode->nodeName; print "</b><br>Vamos a conocer el nombre del nodo abuelo de Juan:<br><b>"; print $juanito->parentNode->parentNode->nodeName; print "</b><br />El bisabuelo de Juan se llama:<br><b>"; print $mi_XML->childNodes->item(1)->childNodes->item(3)->childNodes->item(3)>childNodes->item(1)-> parentNode->parentNode->parentNode->nodeName; print "</b><br />Tendr Juan tatarabuelo ?<br><b>"; print $juanito->parentNode->parentNode->parentNode->parentNode->nodeName."</b>"; /* creemos un nuevo objeto con nombre $hijuela */ $hijuela=$mi_XML->childNodes->item(1)->childNodes->item(3)->childNodes->item(7)>childNodes->item(7); /* visualizemos las propiedades del nuevo objeto */ print "<br><i>El nodo se llama </i> ".$hijuela->nodeName; print " <i>es del tipo:</i> ".$hijuela->nodeType; print " y <i>contiene esto</i>: ".$hijuela->nodeValue; ?>
Ejecutar el script

Crear documentos XML mediante la clase DOMDocument


La creacin de documentos XML por medio de la clase DOMDocument requiere la utilizacin de algunos mtodos an no descritos. Son los siguientes: $elemento = $objeto->createElement('nombre','contenido'); Recoge en $elemento un nuevo elemento del $objeto asignndole el nombre e incluyendo como contenido especificado en la cadenacontenido. Si no se especifica esta ltima tomar por defecto el valor de una cadena vaca. $comentario = $objeto->CreateComment('texto'); Recoge en $comentario un nuevo comentario del $objeto incluyendo como contenido especificado en la cadena texto. $cdata = $objeto->createCDATASection('texto'); Recoge en $cdata un nuevo elemento (del tipo CDATA) del $objeto incluyendo como contenido especificado en la cadena texto.

Cuidado! Los mtodos crean el elemento, el comentario o el CDATA pero no lo incluye en el documento XML. Para esto es necesario recurrir a los mtodos que se incluyen a continuacin.
$objeto->(.. nodos)->appendChild($elemento); $objeto->(.. nodos)->appendChild($comentario); $objeto->(.. nodos)->appendChild($cdata); Incluyen en el nivel indicado por $objeto->(.. nodos) un nuevo elemento, comentario o CDATA que han de ser creados mediante los mtodos Create... descritos anteriormente. $objeto->insertBefore($nuevo_elemento, $otro_elemento); Incluye un elemento $nuevo_elemento precediendo a $otro_elemento incluido como segundo parmetro.

$objeto->insertBefore($nuevo_elemento, $otro_elemento->nextSibling); Incluye $nuevo_elemento en el mismo nivel y a continuacin del del $otro_elemento que precede los caracteres obligatorios ->nextSibling. $objeto->(.. nodos)->AddAttribute(atributo, valor); Aade un nuevo atributo al elemento $objeto->(.. nodos) y le asigna el valor indicado por valor. $objeto->(.. nodos)->->setAttribute(atributo, valor); Modifica el valor del atributo correspondiente al elemento $objeto->(.. nodos). $lectura= $objeto->(.. nodos)->->getAttribute(atributo, valor); Recoge en la variable $lectura el valor del atributo correspondiente al elemento $objeto->(.. nodos). $objeto->saveXML(); Recoge en una cadena el rbol de contenidos XML del objeto $objeto. Resulta muy til para visualizar los contenidos y formatos de los documentos XML con los que estamos trabajando. $objeto->save('fichero'); Permite guardar en un fichero cuyo path, nombre y extensin se indica en el parmetro fichero el contenido del objeto $objeto. En este ejemplo incluimos las diferentes opciones de uso de estos mtodos para crear un documento XML.

<?php header("content-type: text/xml"); /* Empezamos incluyendo una cabecera que especifica el tipo de documento resultante de la ejecucin de este script. Ser text/xml. De esta forma los navegadores, IE, Firefox y Opera nos permitirn ver la estructura del documento. Creamos un nuevo objeto DOMDocument en cuyo prlogo incluiremos la versin de XML (1.0) y la forma de codificacin (utf8) dentificaremos el objeto mediante el nombre \$mi_XML */ $mi_XML = new DOMDocument('1.0','utf-8'); /* Las propiedades $mi_XML->encoding habr tomado el valor utf-8. y $mi_XML->xmlVersion tendr como valor 1.0 $mi_XML->formatOutput toma por defecto el valor false, podemos modificar esa propiedad (a true) con: */ $mi_XML->formatOutput=true; /* La propiedad $mi_XML->preserveWhiteSpace toma true por defecto. Podriamos cambiarla a false de la forma siguiente: */ $mi_XML->preserveWhiteSpace=false; /* Creado el prembulo del objeto $mi_XML el paso siguiente sera crear los diferentes elementos que lo componen. El elemento raiz de nuestro esquema se llama es profesores. Lo creamos de la siguiente forma: */ $raiz=$mi_XML->CreateElement('profesores'); /* Debemos aadirlo como un hijo (Child) del objeto principal */ $mi_XML->appendChild($raiz); /* vamos a agregar algunod de comentarios. Empezamos por crearlos */ $c1=$mi_XML->CreateComment('Voy fuera de profesores');

$c2=$mi_XML->CreateComment('Voy dentro de profesores'); $c3=$mi_XML->CreateComment('Quiero ser el primero'); $c4=$mi_XML->CreateComment('Quiero ponerme antes de los profes'); $c5=$mi_XML->CreateComment('Me insertarn de otra forma'); /* los insertamos (lo importante es donde) El primer comentario ser un hijo del objeto principal y se insertar detrs del ltimo de los ya insertados (detrs del elemento profesores en este caso*/ $mi_XML->appendChild($c1); /* este comentario ira dentro del elementos profesores ya que $raiz es la variable sobre la que fue creado el elemento profesores */ $raiz->appendChild($c2); /* colocaremos a hora $c3 en primera posicion mediante insertBefore */ $mi_XML->insertBefore($c3,$raiz); /* el comentario $c4 lo vamos a colocar justamente detras de $c3 $c3 "ser el siguiente hermano de $c3" */ $mi_XML->insertBefore($c4,$c3->nextSibling); $mi_XML->getElementsByTagName('profesores')->item(0)->appendChild($c5); /* crearemos un nuevo elemento (profe) */ $un_profe=$mi_XML->CreateElement('profe'); /* lo insertamos dentro de del nodo $raiz (profesores) */ $raiz->appendChild($un_profe); /* iremos aadiendo a este profe recien creado los diferentes elementos segun el diseo del grfico del organigrama */ $un_profe->setAttribute('situacion',utf8_encode("Func en practicas")); $p1=$mi_XML->CreateElement('nombre','Antonio'); $p2=$mi_XML->CreateElement('apellidos','Lpez del Ro'); $un_profe->appendChild($p1); $mi_XML->getElementsByTagName('profe')->item(0)->appendChild($p2); $mi_XML->getElementsByTagName('profe')->item(0)->setAttribute('sexo',"varon"); $p3=$mi_XML->CreateElement('nacimiento','21-01-1978'); $p3->setAttribute('zodiaco','Acuario'); $un_profe->appendChild($p3); /* ahora va la retribucin */ $p4=$mi_XML->CreateElement('retribucion'); $p4->setAttribute('IRPF','15 %'); $p4->setAttribute('sexenios','5'); $p5=$mi_XML->CreateElement('base'); $p6=$mi_XML->CreateElement('complemento'); $p5t=$mi_XML->createTextNode('1678,32 '); $p6t=$mi_XML->createTextNode('1678,32 '); $un_profe->appendChild($p4); $p4->appendChild($p5); $p4->appendChild($p6); $p5->appendChild($p5t); $p6->appendChild($p6t); $p7=$mi_XML->CreateElement('valoracion'); $cdata =$mi_XML->createCDATASection("Inspeccin da 23/08/1998\n Llega tarde y sin corbata"); $p7->appendChild($cdata); $un_profe->appendChild($p7); /* agregado masivo de datos a partir de arrays que pueden proceder de la lectura de una base de datos */ $nombres=array('Juan','Perico','Andres','Dolores','Rosario','Alejandra'); $apellidos=array('Fernndez Gonzlez','Ruz del Olmo','Garca Garca','Daz Alonso', 'Carbajal Berrocal','Altamira del Busto'); $sexos=array('Varon','Varon','Varon','Hembra','Hembra','Hembra'); $situaciones=array ('Catedrtico','Profesor','Interino','Interina','Catedrtica','Profesora'); $nacimiento=array('14-12-1967','21-02-1981','23-04-1978','16-06-1967','05-08-1981','0310-1987'); $signo=array('Aries','Acuario','Libra','Tauro','Sagitario','Cancer');

$sueldo_base=array('1.247,32 ','1.257,22 ','1.217,02 ','1.307,20 ','2.047,95 ','1.300,00 '); $complementos=array('1.300 ','1.124 ','1.800 ','1.417 ','1.632 ','1.497 '); $irpf=array('13%','12%','23%','21%','18.5%','11%'); $sexenios=array(1,2,3,4,5,6); $valoracion=array('Excelente profesional','Manifiestamente mejorable','Necesita reciclaje', 'Impecable','Excepcional','Promete grandes xitos'); $cuenta=$mi_XML->getElementsByTagName('profe')->length; for ($i=0;$i<sizeof($nombres);$i++){ $un_profe=$mi_XML->CreateElement('profe'); $raiz->appendChild($un_profe); $un_profe->setAttribute('situacion',$situaciones[$i]); $p1=$mi_XML->CreateElement('nombre',$nombres[$i]); $p2=$mi_XML->CreateElement('apellidos',$apellidos[$i]); $un_profe->appendChild($p1); $mi_XML->getElementsByTagName('profe')->item($i+$cuenta)->appendChild($p2); $mi_XML->getElementsByTagName('profe')->item($i+$cuenta)>setAttribute('sexo',$sexos[$i]); $p3=$mi_XML->CreateElement('nacimiento',$nacimiento[$i]); $p3->setAttribute('zodiaco',$signo[$i]); $un_profe->appendChild($p3); $p4=$mi_XML->CreateElement('retribucion'); $p4->setAttribute('IRPF',$irpf[$i]); $p4->setAttribute('sexenios',$sexenios[$i]); $p5=$mi_XML->CreateElement('base'); $p6=$mi_XML->CreateElement('complemento'); $p5t=$mi_XML->createTextNode($sueldo_base[$i]); $p6t=$mi_XML->createTextNode($complementos[$i]); $un_profe->appendChild($p4); $p4->appendChild($p5); $p4->appendChild($p6); $p5->appendChild($p5t); $p6->appendChild($p6t); $p7=$mi_XML->CreateElement('valoracion'); $cdata =$mi_XML->createCDATASection($valoracion[$i]); $p7->appendChild($cdata); $un_profe->appendChild($p7); } echo $mi_XML->saveXML(); $mi_XML->save('ejemplo478.xml'); ?>
Ejecutar el script Ver documento XML

Como muestra de cual es el procedimiento para interpretar y reconocer los valores de los nodos de un documento hemos incluido este ejemplo.
Ejemplo481.php Ver cdigo fuente

Extraer datos de un fichero XML


En la pgina anterior veamos un ejemplo de como confeccionar un documento XML partiendo de los contenidos en una tabla MySQL. En este ejemplo veremos algunas opciones para efectuar el proceso inverso. Partiendo del documento XML que hemos elaborado en el ejemplo anterior recogeremos en variables PHP los contenidos de aquel documento.

<?php /* creamos un nuevo objeto y cargamo el fichero XML creado en el ejemplo anterior */ $mi_XML = new DOMDocument(); $mi_XML->load('ejemplo478.xml'); /* determinamos el numero de nodos con nombre "profe" */ $numero_profes=$mi_XML->getElementsByTagName('profe')->length; /* creamos nuevos objetos que contenga los nodos con los diferentes nombres Esta manera de hacerlo puede plantear un problema. De haber otros nodos, por ejemplo alumnos que contuvieran nombres o apellidos los recogeria todos sin discriminar a que nodo padre pertenecen */ $los_profes=$mi_XML->getElementsByTagName('profe'); $los_nombres=$mi_XML->getElementsByTagName('nombre'); $los_apellidos=$mi_XML->getElementsByTagName('apellidos'); $el_nacimiento=$mi_XML->getElementsByTagName('nacimiento'); $la_retribucion=$mi_XML->getElementsByTagName('retribucion'); $la_base=$mi_XML->getElementsByTagName('base'); $el_complemento=$mi_XML->getElementsByTagName('complemento'); $la_valoracion=$mi_XML->getElementsByTagName('valoracion'); /* recorremos el bucle de los diferentes objetos extrayendo sus valores mediante nodeValue en el caso de nodos y por medio de getAttribute en el caso de los atributos. Vamos recogiendo los diferentes valores en arrays escalares */ for ($i=0;$i<$numero_profes;$i++){ $sexo[]=$los_profes->item($i)->getAttribute('sexo'); $situacion[]=$los_profes->item($i)->getAttribute('situacion'); $nombre[]=$los_nombres->item($i)->nodeValue; $apellidos[]=$los_apellidos->item($i)->nodeValue; $nacimiento[]=$el_nacimiento->item($i)->nodeValue; $zodiaco[]=$el_nacimiento->item($i)->getAttribute('zodiaco'); $base[]=$la_base->item($i)->nodeValue; $irpf[]=$la_retribucion->item($i)->getAttribute('IRPF'); $sexenios[]=$la_retribucion->item($i)->getAttribute('sexenios'); $complemento[]=$el_complemento->item($i)->nodeValue; $valoracion[]=$la_valoracion->item($i)->nodeValue; } /* insertamos el encabezado de una tabla para presentar los resultados que tambin podran ser utilizados para crear una tabla en MySQL o para cualquier otro proposito en el que se manejen variables PHP */ ?> <table> <tr style="font-size:10px"><td>Nombre</td><td>Apellidos</td> <td>Sexo</td><td>Situacin</td><td>Fecha nacimiento</td> <td>Zodiaco</td><td>Sueldo base</td><td>Complementos</td> <td>IRPF</td><td>Sexenios</td><td>Valoracin</td></tr> <?php /*mediante este bucle creamos las sucesivas filas de la tabla */ for ($i=0;$i<sizeof($nombre);$i++){ print "<tr style='font-size:10px'><td>".$nombre[$i]."</td>"; print "<td>".utf8_decode($apellidos[$i])."</td><td>".$sexo[$i]."</td>"; print "<td>".utf8_decode($situacion[$i])."</td><td>".$nacimiento[$i]."</td>"; print "<td>".$zodiaco[$i]."</td><td>".utf8_decode($base[$i])."</td>"; print "<td>".utf8_decode($complemento[$i])."</td><td>".$irpf[$i]."</td>"; print "<td>".$sexenios[$i]."</td><td>".utf8_decode($valoracion[$i])."</td></tr>"; } print "</table><br /><br /><br />"; /* como opcin alternativa para extraer los mismos valores asegurndose que no se incluyen ms que los correspondientes a los profesores podemos extraerlos del nodo profes. Extraemos los atributos de cada uno de los objetos profe (sexo y situacin) y los dems valores los extraemos siempre del item(0) ya que el objeto nombre es hijo (nico) de profes */

$prof=$mi_XML->getElementsByTagName('profe'); for ($i=0;$i<$numero_profes;$i++){ $n_sexo[]=$prof->item($i)->getAttribute('sexo'); $n_situacion[]=$prof->item($i)->getAttribute('situacion'); $n_nombre[]=$prof->item($i)->getElementsByTagName('nombre')->item(0)->nodeValue; $n_apellidos[]=$prof->item($i)->getElementsByTagName('apellidos')->item(0)->nodeValue; $n_nacimiento[]=$prof->item($i)->getElementsByTagName('nacimiento')->item(0)>nodeValue; $n_zodiaco[]=$prof->item($i)->getElementsByTagName('nacimiento')->item(0)>getAttribute('zodiaco'); $n_base[]=$prof->item($i)->getElementsByTagName('base')->item(0)->nodeValue; $n_irpf[]=$prof->item($i)->getElementsByTagName('retribucion')->item(0)>getAttribute('IRPF'); $n_sexe[]=$prof->item($i)->getElementsByTagName('retribucion')->item(0)>getAttribute('sexenios'); $n_complemento[]=$prof->item($i)->getElementsByTagName('complemento')->item(0)>nodeValue; $n_valoracion[]=$prof->item($i)->getElementsByTagName('valoracion')->item(0)>nodeValue; } /* repetimos el proceso anterior con un pequeo cambio. Durante la codificacin/decodificacin del smbolo del euro hemos perdido ese carcter que ahora aparece sustituido por un signo de interrogacin. str_replace nos permite corregir esa deficiencia visual tal como puedes ver si comparas las dos tablas resultantes de la ejecucin de este script */ ?> <table> <tr style="font-size:10px"><td>Nombre</td><td>Apellidos</td> <td>Sexo</td><td>Situacin</td><td>Fecha nacimiento</td> <td>Zodiaco</td><td>Sueldo base</td><td>Complementos</td> <td>IRPF</td><td>Sexenios</td><td>Valoracin</td> <?php for ($i=0;$i<sizeof($nombre);$i++){ print "<tr style='font-size:10px'><td>".$n_nombre[$i]."</td>"; print "<td>".utf8_decode($n_apellidos[$i])."</td><td>".$n_sexo[$i]."</td>"; print "<td>".utf8_decode($n_situacion[$i])."</td><td>".$n_nacimiento[$i]."</td>"; print "<td>".$n_zodiaco[$i]."</td><td>".str_replace('?', '', utf8_decode($n_base[$i]))."</td>"; print "<td>".str_replace('?', '', utf8_decode($n_complemento[$i]))."</td><td>".$n_irpf[$i]."</td>"; print "<td>".$n_sexe[$i]."</td><td>".utf8_decode($n_valoracion[$i])."</td></tr>"; } print "</table><br /><br /><br />"; ?>
Ejecutar el script

Importar datos de XML a otro XML


Adems de los mtodos descritos anteriormente disponemos de: $objeto->importNode(nodo_a_importar, boleano); Agrega al objeto actual el contenido del objeto nodo_a_importar. La opcin booleano debe tener el valor TRUE cuando se pretenda importar los atributos junto con los elementos del nodo. Este ejemplo es una pequea muestra de las posibilidades que ofrece PHP para la modificacin de los contenidos de ficheros XML.

<?php header ("content-type: text/plain"); /* creamos dos objetos uno llamado importador que ser el que recoja los datos de un documento preexistente y mi_XML que ser el objeto que contendr el nuevo fichero */ $importador = new DOMDocument(); $mi_XML = new DOMDocument('1.0','utf-8'); /* cargamos el documento ejemplo478.xml completo */ $importador->load('ejemplo478.xml'); /* extraemos el objeto raiz llamado profesores y objeto nico, por eso el item(0))(olvidando lneas de comentario del orginal) y lo ponemos en un objeto nuevo llamado colocar */ $colocar = $importador->getElementsByTagName("profesores")->item(0); /* el objeto mi_XML aun no contiene nada asi que crearemos un nuevo objeto y se lo agregaremos. Al ser el primer elemento ser el elemento raiz del nuevo documento*/ $nueva_raiz=$mi_XML->CreateElement('plantilla_completa'); $mi_XML->appendChild($nueva_raiz); /* insertamos los elementos extraidos del fichero importado que habamos recogido en una variable llamada colocar */ $agregar = $mi_XML->importNode($colocar, true); /* colocamos el nuevo objeto agregar como hijo de la raiz de documento */ $nueva_raiz->appendChild($agregar); /*aadimos un nuevo atributo al elemento profesores (unico, era el raiz del fichero que acabamos de importar) */ $mi_XML->getElementsByTagName("profesores")->item(0)>setAttribute('nivel','Secundaria'); /*creamos un objeto con con datos del profesores del nodo importador repitiendo lo que hemos hecho conaterioridad */ $extraer = $importador->getElementsByTagName("profesores")->item(0); /* importamos el nodo completo */ $agregar = $mi_XML->importNode($extraer, true); /* insertamos nuevamente el nodo profesores recogido previamente en el objeto agregar */ $nueva_raiz->appendChild($agregar); /* asignamos al nodo profesores recien creado item(1) el atributo nivel */ $mi_XML->getElementsByTagName("profesores")->item(1)->setAttribute('nivel','Primaria'); /* creamos un objeto primarios que contiene todos los elementos profe de estos ultimos profesores */ $primarios=$mi_XML->getElementsByTagName("profesores")->item(1)>getElementsByTagName("profe"); /* modificamos el atributo situacin de los profes de primarios */ for($i=0;$i<$primarios->length;++$i){ $cambiar=$primarios->item($i)->getAttribute('situacion'); switch ($cambiar){ case "Catedrtica": $primarios->item($i)->setAttribute('situacion','Profesora de Segundo Ciclo'); break; case "Profesor": $primarios->item($i)->setAttribute('situacion','Profesor de Primer Ciclo'); break; case "Profesora": $primarios->item($i)->setAttribute('situacion','Profesora de Primer Ciclo'); break; case "Catedrtico": $primarios->item($i)->setAttribute('situacion','Profesor de Segundo Ciclo'); break; } } /* vamos a modificar datos de nombres y apellidos para evitar los duplicado consecuencia de haber importado dos veces el mismo nodo */

$nuevos_apellidos=array('Alonso Galguera','Ruz de Alda','Alonso Aller', 'Menndez Lpez','Garca Ura','Alvarez del Campo','Feito Parrondo'); $nuevo_nombre=array ('Luis','Eduardo','Fernando','Gonzalo','Carmela', 'Luisa','Servanda'); /* recorremos los elementos primarios cambiando el valor de los nodos nombre (con item0 por tener solo un elemento) por el nuevo nombre y los apellidos por lo nuevos apellidos y adems hacemos una sustitucin de la valoracin en el caso de producirse una coincidencia */ for($i=0;$i<$primarios->length;++$i){ $primarios->item($i)->getElementsByTagName("nombre")->item(0)>nodeValue=$nuevo_nombre[$i]; $primarios->item($i)->getElementsByTagName("apellidos")->item(0)-> nodeValue=utf8_encode($nuevos_apellidos[$i]); if($primarios->item($i)->getElementsByTagName("valoracion")->item(0)-> nodeValue=="Necesita reciclaje"){ $primarios->item($i)->getElementsByTagName("valoracion")->item(0) ->firstChild->nodeValue=utf8_encode("Adems de reciclaje\n necesita un milagro"); } /* quitamos el atributo zodiaco a todos profes de primara */ $primarios->item($i)->getElementsByTagName("nacimiento")->item(0)>removeAttribute('zodiaco'); /* quitamos el atributo sexenios a todos aquellos cuya situacin empiece por Inter */ if(substr($primarios->item($i)->getAttribute("situacion"),0,5)=="Inter"){ $primarios->item($i)->getElementsByTagName("retribucion")->item(0)>removeAttribute('sexenios'); } } /*Busco a Servanda le cambio el nombre por Severina*/ for($i=0;$i<$primarios->length;++$i){ $nombre=$primarios->item($i)->getElementsByTagName("nombre")->item(0)->nodeValue; if ($nombre=="Servanda"){ $primarios->item($i)->getElementsByTagName("nombre")->item(0)>nodeValue="Severina"; } } /* visualizamos los resultados */ echo $mi_XML->saveXML(); ?>
Ejecutar el script

PDO Bases de datos SQLite / MySQL Bases de datos SQLite


SQLite es una librera que permite gestionar bases de datos SQL sin necesidad de tener instalado un servidor como requieren MySQL y otros gestores. Ello significa que en la mayora de los casos la gestin de bases de datos personales podra realizarse sin necesidad de instalar ningn servidor adicional a Apache + PHP. Una base de datos SQLite es simplemente un fichero cuyo nombre y extensin podemos asignar con total libertad y que puede estar alojado en cualquier directorio de nuestro servidor PHP con la nica condicin de que ese directorio en el caso de trabajar sobre Ubuntu tenga permisos de escritura. Aunque PHP dispone de todo un conjunto de funciones especficas para las bases de datos SQLite similares a las vistas para el caso de MySQL nosotros vamos a ver la forma de gestionar bases de datos (tanto SQLite como MySQL) de un modo distinto. Lo haremos por medio de la extensin PDO de PHP.

De esta forma, adems de familiarizarnos con el manejo de las bases de datos SQLite, conoceremos una forma alternativa de gestionar MySQL. Es por ello que a lo largo de esta pgina y las siguientes nos referirmos con frecuencia a ejemplos, situaciones y operaciones ya estudiadas en MySQL. Ahora trataremos de hacer algo muy similar a aquello pero utilizando de forma exclusiva la extensinPDO.

PDO - PHP Data Objects


PHP Data Objects (PDO) es una extensin de PHP para la formalizacin de las conexiones de PHP con una de base de datos por medio de una interfaz uniforme. PDO proporciona una capa de abstraccin de acceso a datos, que significa que, se utilizarn las mismas funciones para la gestin de las bases de datos con independencia del tipo de base que estemos utilizando. Ello significa que, con muy ligeras modificaciones, un mismo script podra gestionar diferentes tipos de bases de datos tales como: SQLite, MySQL, Postgres, Oracle Firebird.

Configuracin de PHP
El uso de PDO requiere el uso de una extensin especfica de PHP para cada uno de los tipos de bases de datos que pretendamos gestionar. En nuestro caso vamos a manejar MySQL y SQLite lo que requiere que, bajo Windows, usemos las extensionesextension=php_pdo_sqlite.dll y extension=php_pdo_mysql.dll Habremos de editar el fichero php.ini, buscar esas dos extensiones, descomentarlarlas (quitar el punto y coma que llevan delante), guardar los cambios y reiniciar el servidor. Cuando se trata de Ubuntu es preciso realizar la siguiente instalacin:

sudo apt-get install php5-sqlite con lo cual, en cualquiera de los dos casos, una vez reiniciado el servidor la pgina http://localhost/info.php debera mostrarnos una informacin similar a esta:

Gestin de bases de datos SQLite y MySQL mediante PDO


Dada la gran similitud entre los procedimientos (esa es una de las ventajas de utilizar PDO) vamos a intentar ir viendo de forma simultnea el uso de este interface tanto para SQLite como para MySQL. Lo iremos haciendo en distintos epgrafes procurando mostrar las afinidades y diferencias. Despus de haber visto el tema relativo al manejo de clases y objetos y la aplicacin de la clase TCDF para la gestin de ficheros PDF te resultar fcil y familiar el manejo del PDO ya que lo que haremos en estos temas ser manejar objetos de la clase PDO.

Aunque iremos viendo los diferentes mtodos de esta clase tiene particular inters que empecemos conociendo un los ms importantes: $objeto->query(SENTENCIA) que permite ejecutar cualquier SENTENCIA SQL sobre el $objeto sea cual fuere el tipo de base de datos en uso. Quiere ello decir que usaremos este mismo mtodo para cualquier proceso de: creacin, modificacin, baja, o consulta de bases datos y tablas.

Creacin de bases y/o acceso a bases de datos


Creacin y/o conexin a una base de datos SQLite
Requiere nicamente la creacin de un objeto PDO con la siguiente sintaxis: $objeto= new PDO ('sqlite: fichero ') dnde $objeto es el identificador de un nuevo objeto, sqlite: es una palabra reservada y obligatoria que especifica el tipo de base de datos y fichero es la ruta y nombre de un fichero destinado a guardar la nueva base de datos. Si el fichero no existe se creara uno nuevo y en caso de que ya existiera no se sobreescribira manteniendo toda la informacin que pudiera contener. En este ejemplo puedes ver la forma de crear bases de datos SQLite. Si lo ejecutas podrs ver que se han creado los dos ficheros en los directorios indicados y que, su longitud es cero bytes. Es lgico que as sea ya que an no contienen informacin alguna.

<?php /* creamos un objeto PDO con el nombre $dbSQLite. Es importante que el parmetro que se incluye comience por sqlite: (esa palabra es la indica el driver debe utilizar PHP para gestionar la base de datos es SQLite)y a continuacin la cadena con la ruta y nombre del fichero que contendr la base de datos */ $dbSQLite= new PDO('sqlite:./images/baseSQLite.zpq'); /* una opcin un poco ms sofisticada podra utilizar una funcin y devolvernos un mensaje de confirmacin o de error. */ function conecta($nombre){ if ($db = new PDO('sqlite:'.$nombre)){ print "Creado o abierto el fichero SqLite: ".$nombre.'<br />'; return($db); } else { print "Error: No puede conectarse con la base de datos.<br />"; print "<br />".$db->errorInfo()."<br />"; exit(); } } /* si hacemos una llamada a esta funcin pasndole como parmetro el nombre de la base de datos y (opcionalmente) la ruta habremos creado un nuevo objeto y un nuevo fichero de base de datos */ $dbSQLite1= conecta('practicar'); /* destruimos el objeto con ello desconectamos de la base de datos */ $dbSQLite1=NULL; $dbSQLite=NULL; /* destruimos los objetos (la conexin) pero los ficheros se mantienen*/ ?>
ejemplo482.php

Cuidado! Es importante elegir un lugar adecuado para almacenar las bases de datos SQLite. Al tratarse de un nico fichero si lo dejamos dentro del directorio raz (htdocs en la configuracin aqu descrita) o en uno de sus directorios es obvia su vulnerabilidad. Fjate que este enlace http://www.rinconastur.net/php/ejemploSQLite permite descargar sin problema

alguno la base de datos SQLite que hemos incluido como ejemplos. Adems, al carecer de contrasea, los datos que contiene son totalmente accesibles. La forma de evitar o al menos paliar ese riesgo sera almacenar este fichero fuera del document_root (htdocs) de la misma forma que hacamos con las contraseas de acceso a MySQL

Creacin y conexin con una base de datos MySQL


Utilizando la clase PDO el acceso a una base de datos MySQL (como es lgico, el servidor de bases de datos MySQL tiene que estar activo) requiere nicamente la creacin de un objeto PDO con la siguiente sintaxis: $objeto= new PDO ("mysql: servidor " ,usuario,contrasea ) dnde $objeto es el identificador de un nuevo objeto, mysql: es una palabra reservada y obligatoria que especifica el tipo de base de datos, servidor es una cadena formada por: host=nombre_del_servidor_MySQL (en nuestro caso localhost), usuario el nombre de usuario (pepe en el caso de nuestros ejemplos) y contrasea (la contrasea de usuario, pepa en nuestro caso). La cadena que estamos sealando como servidor admite una opcin un poco ms amplia que tendra la forma:host=nombre_del_servidor_MySQL ; dbname=nombre_de_la_base_de_datos. En ese caso el objeto devuelto sera la conexin al servidor MySQL y el acceso a la base de datos sealada mediante nombre_de_la_base_de_datos. Sera una situacin equivalente a la resultante del uso de mysql_select_db cuando usbamos las funciones MySQL de PHP. En este ejemplo puedes ver la forma de acceder a bases de datos MySQL. Por mantener el paralelismo con SQLite nos hemos visto obligados a incluir dos pasos. En el primero se comprueba la existencia de la base de datos y se crea si no existera. En el segundo se produce el acceso a la propia base de datos.

<?php function conecta($base){ $db = new PDO('mysql:host=localhost','pepe','pepa'); /* crea la base de datos si no existe */ $db->query("CREATE DATABASE IF NOT EXISTS ".$base); /* crea un nuevo objeto usando la base de datos pasada como parmetro sin riesgo de error por inexistencia de la base */ if($db1 = new PDO('mysql:host=localhost;dbname='.$base,'pepe','pepa')){ print "Creado o abierta la base de datos MySQL: ".$base.'<br />'; return($db1); } else { print "Error: No puede conectarse con la base de datos.<br />"; print "<br />".$db1->errorInfo()."<br />"; exit(); } } /* Hacemos una llamada a esta funcin pasndole como parmetro el nombre de la base de datos */ $dbSQLite1= conecta('practicar'); ?>
ejemplo483.php

Cuidado! Presta atencin a la sintaxis sin olvidar la correcta ubicacin de las comillas. $objeto=new PDO ("mysql:host=localhost","pepe","pepa") o $objeto=new PDO ("mysql:host=localhost; dbname=ejemploSQLite", "pepe", "pepa") sera la sintaxis vlida. Utiliza siempre comillas dobles (estas " ") en este tipo de sentencias. Si los nombres de bases de datos, usuarios, host y/o contraseas proceden de variables la sintaxis que debers utilizar ser esta: new PDO("mysql:host=$host;dbname=$base_datos",$usuario,$password)

Unificacin del proceso de conexin

Nuestro propsito es ir desarrollando, de forma simultnea, ejemplos con ambas bases de datos. Eso no requerir manejar, en paralelo, objetos de ambos tipos. Para facilitar un poco las cosas,en el ejemplo siguiente veremos como unificar en una sola funcin los procesos de conexin a ambas bases de datos. De esa forma, modificando un solo parmetro, podramos crear indistintamente objetos de uno u otro tipo.

<?php function conecta($base,$tipo){ if ($tipo=='MySQL'){ $db = new PDO('mysql:host=localhost','pepe','pepa'); /* crea la base de datos si no existe */ $db->query("CREATE DATABASE IF NOT EXISTS ".$base); /* crea un nuevo objeto usando la base de datos pasada como parmetro sin riesgo de error por inexistencia de la base */ if($db1 = new PDO('mysql:host=localhost;dbname='.$base,'pepe','pepa')){ print "Creado o abierta la base de datos MySQL: ".$base.'<br />'; return($db1); } else { print "Error: No puede conectarse con la base de datos.<br />"; print "<br />".$db1->errorInfo()."<br />"; exit(); } } if ($tipo=='SQLite'){ if ($db = new PDO('sqlite:'.$base)){ print "Creado o abierto el fichero SqLite: ".$base.'<br />'; return($db); } else { print "Error: No puede conectarse con la base de datos.<br />"; print "<br />".$db->errorInfo()."<br />"; exit(); } } } /* Hacemos una llamada a esta funcin pasndole como parmetros nombre de la base de datos y tipo*/ $dbDual= conecta('practicar','MySQL'); ?>
Caso MySQL Caso SQLite

Desconexin de una base de datos SQLite


Aunque en SQLite no cabe hablar de desconexin, utilizaremos esa palabra por similitud con lo visto para MySQL. En este caso lo que llamaremos desconexin no ser otra cosa que la destruccin del objeto creado a acceder. Para ello bastara con escribir: $objeto= NULL En cualquier caso resulta innecesario. En PHP los objetos se destruyen al finalizar la ejecucin del script mediante el que han sido creados.

Borrar bases de datos SQLite


Como quiera que una base de datos SQLite no es otra cosa que un fichero, para eliminarla sera suficiente borrar tal ficheromediante la funcin PHP: unlink(nombre_del_fichero) Cuando se trata de eliminar bases de datos (como es lgico se eliminaran las eventuales tablas e informacin que pudiera contener) basta proceder de igual forma que para borrar cualquier otro fichero.

<?php /* borramos las bases de datos creadas en el ejemplo anterior */ unlink('./images/baseSQLite.zpq'); unlink('practicar'); ?>
ejemplo486.php

Borrar bases de datos MySQL


Cuando se trata de borrar bases de datos MySQL se utiliza el mtodo: $objeto->query(DROP DATABASEnombre_de_la_base) como vers la sentencia SQL es la que hemos manejado con anterioridad y que puedes recordar en desde este enlace. El ejemplo siguiente contiene un script que borra la base de datos MySQL creada en los ejemplos anteriores.
Ver cdigo fuente

Formas de almacenamiento de SQLite


A diferencia de MySQL, SQLite maneja solamente cinco formas de almacenamiento: NULL. Su valor es un valor nulo. INTEGER. Es un entero con signo, almacenado en 1, 2, 3, 4, 6, u 8 bytes dependiendo de la magnitud del nmero. REAL. El valor es un nmero de punto flotante de 8 bytes. TEXT. El valor es una cadena de texto, almacenados utilizando la codificacin de base de datos (UTF-8, UTF-16BE o UTF16LE). BLOB. El valor son los datos de entrada almacenados tal cual fueron introducidos. En cualquier caso SQLite es extremadamente flexible en este sentido. Cualquier campo, con excepcin de los definidos comoINTEGER PRIMARY KEY, puede utilizarse para almacenar un valor de cualquier tipo. SQLite no dispone de un tipo especfico para almacener fechas. Sin embargo dispone de fuciones internas permiten tratar datos de fecha y hora a partir de los siguientes formatos: Para fechas con formato: YYYY-MM-DD HH:MM:SS.SSS deben utilizarse campos tipo TEXT. Fechas expresadas en cuenta de das julianos la funcin juliantojd() nos permite conocer esos valores deberemos almacenarlo en un campo de tipo REAL. Fechas expresadas en tiempo Unix se almacenaran en un campo de tipo INTEGER

Parmetros de los campos


Adems del nombre de campo y la declaracin de tipo de datos, SQLite permite incluir opcionalmente unos parmetros adicionales similares a los utilizados por MySQL. Entre ellos los siguientes: PRIMARY KEY, UNIQUE, INTEGER PRIMARY KEY, CHECK, NOT NULL,DEFAULT, AUTOINCREMENT. La diferencias ms sustanciales respecto a MySQL son estas: SQLite no admite campos con formatos similares a los tipos ENUM y SET. SQLite no admite que se incluyan los flags: ZEROFILL ni UNSIGNED que s se usan en MySQL. Los campos autoincrementales en SQLite solo son posibles si se les define como INTEGER PRIMARY KEY AUTOINCREMENT.

Cuidado!

SQLite ignora los valores que se trate de asignar al tamao del campo. SQLite no impone ninguna limitacin en el 9 tamao de un campo siempre que no sobrepase el valor mximo preestablecido que est establecido en 10 bytes.

Flexibilidad en la declaracin de tipos de datos


SQLite es enormemente flexible en cuanto a la declaracin del tipos de datos contenidos en sus tablas. En este sentido debemos diferenciar tres elementos: tipos declarados, afinidades y forma de almacenamiento. Cuando definimos tablas en MySQL es necesario hacer una estricta declaracin de tipos para cada uno de los campos. Recuerda que la sintaxis era similar a esta: numero1 VARCHAR(32). En el caso de SQLite las cosas son ms sencillas ya que la propia librera dispone de recursos capaces de interpretar de forma inteligente los tipos declarados y traducirlos a una de sus cinco formas de almacenamiento. Para ello sigue las reglas especificadas en la tabla siguiente:
Regla 1 2 3 4 5 Funcionamiento Si el tipo declarado contiene la cadena INT se le asigna afinidad INTEGER Si el tipo declarado contiene cualquiera de las cadenas: CHAR, CLOB, o TEXT, se asignar afinidad TEXT. Si el tipo declarado contiene la cadena BLOB, o si no se define ningn tipo, se le asignar afinidad NONE Si el tipo declarado contiene cualquiera de las cadenas: REAL, FLOA, o DOUB se el asigna afinidad REAL En cualquier otro caso la afinidad se considera NUMERIC

Quiere esto decir que podramos permitirnos la frivolidad de definir un tipo de campo como tipo paraguas. Las reglas de afinidadanteriores lo convertiran de forma automtica en NUMERIC dado que no contiene ninguna de las cadenas indicadas en las reglas anteriores. Esta peculiaridad de SQLite resulta muy til cuando se trata de compatibilizar su sintaxis con la de otros gestores de bases de datos ms estrictas en cuanto a su sintaxis. En ejemplos posteriores veremos como SQLite es capaz de manejar, sin apenas modificaciones, definciones de tablas propias de MySQL. Esta tabla es un resumen de las afinidades de tipos entre las definiciones de los gestores ms habituales y SQLite.
Nombres comunes en SQL utilizables en la declaracin de tipos INT, INTEGER, TINYINT, SMALLINT, MEDIUMINT, BIGINT, UNSIGNED BIG INT, INT2 ,INT8 CHARACTER(20), VARCHAR(255), VARYING CHARACTER(255), NCHAR(55), NATIVE CHARACTER(70), NVARCHAR(100), TEXT, CLOB BLOB (sin especificar tipos de datos) REAL, DOUBLE, DOUBLE PRECISION, FLOAT NUMERIC, DECIMAL(10,5), BOOLEAN, DATE, DATETIME Afinidad INTEGER TEXT NONE REAL NUMERIC Regla 1 2 3 4 5

La flexibilidad de SQLite an tiene un nuevo aspecto diferencial. Qu puede ocurrir si tratamos de agregar datos alfanumricos a un campo definido como NUMERIC? SQLite intentar adecuar los contenidos de los campos a la forma de establecimiento establecida en la definicin de tabla y/o las reglas de afinidad y cuando esto no resulta posible adeca la forma de almacenamiento a los contenidos. En la tabla tienes descritas algunas situaciones en las que se producen adaptaciones de este tipo.
Afinidad TEXT Comportamiento Un campo con afinidad TEXT almacena todos los datos utilizando las formas NULL, TEXT o BLOB. Si se inserta un dato numrico en un campo con afinidad TEXT ser convertido en cadena antes de ser almacenado Un campo con afinidad NUMERIC puede contener valores de cualquiera de las cinco clases de almacenamiento. Cuando se insertan textos la clase de almacenamiento del texto el campo intenta convertirse a INTEGER o REAL (en orden de preferencia). Realiza esa transformacin si se conservan los 15 primeros dgitos significativos del nmero (conversin sin prdidas y reversible). Si la conversin sin prdida no es posible, entonces el valor se almacena con la clase de almacenamiento TEXT. No se intenta convertir los valores NULL o BLOB. Una cadena con aspecto de punto flotante con un punto decimal o notacin exponencial,que pueda ser expresada como un entero ser convertida en entero. Por ejemplo, la cadena 3 .0 e +5 se almacena en una columna con afinidad NUMERIC con el valor 300.000, no como el valor de punto flotante 300.000,0. Una columna que utiliza afinidad INTEGER se comporta igual que una columna con afinidad NUMRICO. La diferencia entre la afinidad INTEGER y NUMERIC slo es evidente en una expresin de conversin Un campo con afinidad REAL se igual que con afinidad NUMERIC excepto que fuerza valores enteros en la representacin de punto flotante. Los valores de punto flotante sin ningn componente fraccionaria (por ejemplo 23.0) se escriben en el disco como enteros con el fin de ocupar menos espacio. Cuando son leidos recuperan su condicin de punto flotante. Una columna con afinidad NONE no establece ninguna preferencia de clase de almacenamiento.

NUMERIC

INTEGER

REAL NONE

Errores en la clase PDO


La clase PDO dispone de un mtodo que nos permite obtener informacin sobre los errores que ocasionalmente puedan producirse en el manejo de sus mtodos y/o propiedades. Su sintaxis es esta: $error=$objeto->errorInfo() dnde el array escalar $error resultante de la ejecucin del mtodo errorInfo est formado por tres elementos cuyos contenidos seran los siguientes: $error[0] Identificador alfanumrico de cinco caractes $error[1] Cdigo del error $error[2] Mensaje explicativo del error

Creacin de tablas
La creacin de tablas SQLite, tiene una sintaxis prcticamente igual a la utilizada por MySQL. Requiere una de estas dos sentencias CREATE TABLE IF NOT EXISTS tabla (campo1, campo2,... ) o CREATE TABLE tabla (campo1, campo2,... ) La nica diferencia entre ambas opciones es que la segunda dara un error si tratramos de crear una tabla preexistente mientras que la primera no da ese mensaje de error. La definicin de los campos es mucho menos estricta que en MySQL. Sera suficiente con asignarles un nombre sin tan siquiera declarar un tipo. La declaracin de tipos, si se opta por hacerla, tiene la amplitud comentada en prrafos anteriores respecto a las afinidades y los parmetros restrictivos los llambamos flags de campo en MySQL tienen como all carcter opcional y, tal como indicamos un poco ms arriba, son bsicamente los mismos que MySQL con las excepciones ya comentadas. La ejecucin de las sentencias SQLite por medio de la clase PDO requiere utilizar el mtodo siguiente: $resultado=$objeto->query(sentencia) dnde $resultado puede recoger un valor booleano (que confirmara la correcta ejecucin de la sentencia o los eventuales errores producidos durante la ejecucin de la misma) o el objeto con el resultado de la ejecucin de dicha sentencia (una consulta, por ejemplo).

Base de datos ejemplos


Utilizaremos una base de datos con nombre ejemploSQLite tanto en SQLite como en MySQL. En el primero de los casos ser un fichero con ese nombre (ejemploSQLite)que se crear en el servidor. En el segundo ser una nueva base de datos aadida a nuestro servidor MySQL. En el mismo script crearemos una tabla en ambas bases (utilizando la misma sentencia) tal como puedes ver en el cdigo fuente.
Ver cdigo fuente

PDO Altas SQLite / MySQL Los diferentes elementos de una tabla


Cuando estudibamos las tablas MySQL habamos creado una tabla cuyo cdigo fuente puedes ver aqu. Vamos a evaluar ese cdigo y efectuar algunas modificaciones para poder utilizarlo en SQLite. Para mayor comodidad hemos guardado la funcion conecta(), que permita instanciar el constructor de PDO, en un fichero llamado conecta.inc.php para poder incluirlo de una forma ms cmoda en todos nuestros scripts.

Las diferencias sintcticas en la definicin de la tabla de ambos tipos de base de datos (MySQL y SQLite) son las que tienes resumidas en esta tabla:
Diferencias de sintaxis en definicin de tablas MySQL SQLite

Contador TINYINT(8) UNSIGNED ZEROFILL NOT NULL AUTO_INCREMENT Contador INTEGER PRIMARY KEY AUTOINCREMENT

SQLite no admite ni ZEROFILL ni UNSIGNED. Los campos auticrementales en SQLite tienen que ser definidos obligatoriamente como: INTEGER PRIMARY KEY AUTOINCREMENT MySQL SQLite

DNI CHAR(8) NOT NULL DNI CHAR(8) NOT NULL UNIQUE Sexo Enum('M','F') DEFAULT 'M' not null Sexo VARCHAR DEFAULT 'M' not null

Los indices nicos se definen en SQLite incluyendo la palabra UNIQUE como un flag en la definicin del campo. MySQL SQLite

SQLite no permite campos del tipo Enum. Por esa razon lo convertimos en VARCHAR. Ya buscar SQLite las afinidades de esta palabra. En cualquier caso no va a presentarnos demasiados problemas. Bastara con utilizar algn recurso de PHP para restringir el contenido de ese campo a un valor 'M' o 'F'. MySQL SQLite

Idiomas SET(' Castellano',' Francs','Ingls',' Alemn',' Blgaro',' Chino') Idiomas VARCHAR

Tampoco estn permitidos en SQLite los campos tipo SET. Lo sustituimos por VARCHAR. Por cuestin de compatibilidad entre ambas tablas optamos por hacer de este mismo tipo, VARCHAR, el campo Idiomas de la tabla MySQL. Dado que este tipo va a recoger un nmero en la tabla siempre ser posible emular su comportamiento incluyendo una funcin PHP que interprete ese valor MySQL SQLite En SQLite las claves primarias, nicas e indices se incluyen en la propia definicin del campo. Por lo tanto esta lnea no es requerida. MySQL SQLite En SQLite las claves primarias, nicas e indices se incluyen en la propia definicin del campo. Por lo tanto esta lnea no es requerida. MySQL SQLite La definicin de tipo de tabla es exclusiva de MySQL. Cuando se trata de SQLite no se requiere esa definicin

PRIMARY KEY(DNI)

UNIQUE auto (Contador)

type=MyISAM

Respetando las exigencias comentadas en la tabla anterior hemos creado este script mediante el cual construiremos dos tablas de caractersticas bastante similares.

<?php include('conecta.inc.php'); /* Hacemos dos llamada a esta funcin conecta incluida en el fichero conecta.inc.php como parmetros nombre de la base de datos y tipo. Creamos dos objetos, uno para MySQL y en la otra el SQLite */ $dbMySQL= conecta('ejemploSQLite','MySQL'); $dbSQLite= conecta('ejemploSQLite','SQLite'); /* asignamos a la variable tabla en nombre de la nueva tabla */ $tabla='demo4'; /* transcribimos el cdigo del ejemplo 379 */ $crear="CREATE TABLE IF NOT EXISTS $tabla ("; $crear.="Contador TINYINT(8) UNSIGNED ZEROFILL NOT NULL AUTO_INCREMENT,"; $crear.="DNI CHAR(8) NOT NULL, "; $crear.="Nombre VARCHAR (20) NOT NULL, "; $crear.="Apellido1 VARCHAR (15) not null, "; $crear.="Apellido2 VARCHAR (15) not null, "; $crear.="Nacimiento DATE DEFAULT '1970-12-21', "; $crear.="Hora TIME DEFAULT '00:00:00', "; $crear.="Sexo Enum('M','F') DEFAULT 'M' not null, "; $crear.="Fumador CHAR(0) , ";

$crear.="Idiomas SET(' Castellano',' Francs','Ingls',' Alemn',' Blgaro',' Chino'), "; $crear.=" PRIMARY KEY(DNI), "; $crear.=" UNIQUE auto (Contador)"; $crear.=")type=MyISAM"; $crear1="CREATE TABLE IF NOT EXISTS $tabla ("; $crear1.="Contador INTEGER PRIMARY KEY AUTOINCREMENT,"; $crear1.="DNI CHAR(8) NOT NULL UNIQUE, "; $crear1.="Nombre VARCHAR (20) NOT NULL, "; $crear1.="Apellido1 VARCHAR (15) not null, "; $crear1.="Apellido2 VARCHAR (15) not null, "; $crear1.="Nacimiento DATE DEFAULT '1970-12-21', "; $crear1.="Hora TIME DEFAULT '00:00:00', "; $crear1.="Sexo VARCHAR DEFAULT 'M' not null, "; $crear1.="Fumador CHAR(0) , "; $crear1.="Idiomas VARCHAR "; $crear1.=")";

/* realizamos la consulta de creacin en ambas bases de datos*/ if($dbSQLite->query($crear1)){ print "La tabla SQLite $tabla ha sido CREADA<br>"; } else{ print "Ha habido un error de PDO: <br />" ; echo "<pre>"; print_r($dbSQLite->errorInfo()); echo "</pre>"; } /* repetimos el mismo proceso ahora con la base de datos MySQL */ if($dbMySQL->query($crear)){ print "La tabla MySQL $tabla ha sido CREADA<br>"; } else{ print "Ha habido un error de PDO: <br />" ; echo "<pre>"; print_r($dbSQLite->errorInfo()); echo "</pre>"; } ?>

Aadir registros a una tabla


La sentencia SQLite que permite aadir registros a una tabla muy similar a la utilizada por MySQL es la siguiente: INSERT INTO tabla (campo1,campo2,..) VALUES (valor1,valor2,..)

dnde tabla es el nombre de la tabla, campo1, campo2, etc. son los nombres de los campos y valor1, valor2, etc. son los valores a incluir en cada uno de los campos. La nica diferencia entre esta sentencia y la equivalente de MySQL es que aqu la palabra INTO tiene carcter obligatorio mientras que all solo es opcional.

Aadir un registro
Igual que ocurra en el caso de MySQL tambin aqu puede aadirse un registro incluyendo los valores en la propia sentencia o recogindolos de variables PHP previamente definidas.

En este ejemplo, dual como todos los siguientes, se agrega a la tabla demo4 de dos bases de datos distintas SQLite y MySQL cuyo nombre es ejemploSQLite un registro cuyos valores son:
DNI Nombre Apellido1 Apellido2 Nacimiento Sexo Hora Fumador Idiomas

1234 Lupicinio Servidor Servido 1954-11-23 M


Ver cdigo fuente

16:24:52 null

Presta atencin a los siguientes aspectos: En la sentencia no se alude al campo Contador. La razn es que se trata un campo AUTOINCREMENTAL y en ese tipo de campos los valores de los registros se escriben automticamente cada vez que se aade uno nuevo. El registro no se aadira si el valor de DNI coincidiera con otra ya existente en la tabla. Recuerda que habamos definido ese campo como ndice primario. Si no hubiramos incluido el aviso de error no tendramos ninguna referencia sobre el xito de la insercin y no detectaramos el problema de duplicidad. Sencillamente ocurrira que el registro no se aadira pero no nos enteraramos de tal circunstancia. En el tratamiendo del campo Fumador definido en MySQL con longitud cero y que solo permite como valores NULL o una cadena vaca es vlido todo lo comentado en esta pgina. Lo transcribimos literalmente un poco ms abajo. El error PDO generado al producirse una coincidencia de valores en un campo nico tiene el cdigo 19. En este ejemplo puedes la manera de utilizarlo para depurar el mensaje de advertencia.
Ver cdigo fuente

Aadir un registro a partir de datos contenidos en variables


Tambin es posible aadir registros a partir de valores contenidos en variables PHP. Esta opcin es, sin ninguna duda, la ms utilizada, ya que lo habitual ser escribir el contenido a aadir en un form y despus a travs del method (POST o GET) pasar al script de insercin esos valores como variables PHP. Aqu tienes el cdigo fuente de un ejemplo con la tabla anterior.
Ver cdigo fuente

Quiz te resulten de alguna utilidad estos comentarios: Observa en el cdigo fuente que al insertar las variables en los VALUES de la sentencia MySQL ponemos cuando se trata de valores tipo cadena '$variable' (el nombre de la variable entre comillas) y cuando se trata de valores nmericos sin comillas. Si quieres introducir el valor NULL en un campo tipo VAR(0) define la variable as: $variable="NULL" y si quieres introducir unacadena vaca defnela de este otro modo:$var="''" -comillas dobles (") seguidas de dos comillas sencillas (') y para terminar otras comillas dobles (") y cuando hagas alusin a esa esta variable como un VALUE en la sentencia de insercin no la pongas entre comillas.

Aadir datos mediante formulario


Creacin del formulario
El caso ms frecuente casi el nico es que los registros de una tabla se aadan utilizando un formulario y enviando desde l los datos a un script PHP que ejecute la opcin de aadir. Si no recuerdas el funcionamiento de este mtodo pulsa aqu En el ejemplo hemos desarrollado un formulario para aadir registros a la tabla demo4 idntico al descrito para MySQL. Su cdigo fuente est en este enlace.
Ver cdigo fuente

Aadir nuevo registro con datos del formulario


Tampoco existen grandes diferencias con lo dicho para MySQL en cuanto a la forma de interpretar los datos recibidos a travs del formulario. Aqu tienes comentado el script que efecta la insercin de datos en las tablas de ambos tipos.
Aadir registros mediante formulario Cdigo fuente del script

Tablas para pruebas


Tal como hacamos cuando estudibamos MySQL aqu tienes comentado un script que permite agregar aleatoriamente y de formaautomtica una serie de registros para pruebas a las tablas demo4 de la base de datos ejemploSQLite tanto en formato SQLite como en MySQL.
Ver cdigo fuente

PDO Consultas SQLite / MySQL Algunos ejemplos de consultas


Las consultas de los datos y registros contenidos en una tabla ofrecen un amplsimo abanico de posibilidades a partir de las opciones ya descritas en pginas anteriores para las tablas MySQL. Salvo pequeos detalles que iremos comentando a lo largo de los sucesivos ejemplos la sintaxis y los resultados son muy similares entre las consultas a tablas SQLite y MySQL. Repetiremos las consultas ya comentadas anteriormente para estas nuevas tablas creadas y manejadas mediante objetos PDO.

La consulta ms simple
Si utilizamos la sentencia SELECT * FROM tabla obtendremos informacin sobre todos los campos (*) y la salida estar en el mismo orden en el que fueron aadidos los datos. Si visualizas este ejemplo, vers que aparecen ordenados por el valor autonumrico del campo Contador lo cual, como ves, resulta coherente con la afirmacin anterior. La nica diferencia entre los resultados de la misma consulta en ambas bases de datos estara en la presentacin del campo autonmerico. En el caso de MySQL aparece con ceros a la izquierda dado que al definir la tabla establecimos TINYINT(8) UNSIGNED ZEROFILL mientras que en caso de SQLite estuvimos obligados configurar ese campo autoincremental como INTEGER PRIMARY KEY. Si observas el cdigo fuente, en el caso del campo Idioma hemos tenido que hacer un pequeo arreglo en la consulta SQLite para visualizar los mismos datos que en MySQL. La razn es la no admisin de campos tipo SET ni ENUM por parte de SQLite.
Ejecutar consulta Ver cdigo fuente

Consultando slo algunos campos


Ahora utilizaremos la sentencia SELECT campo1,campo2, ... FROM tabla y tendremos como resultado una lista completa, por el mismo orden que la anterior, pero slo mostrando los campos indicados.
Ejecutar consulta Ver cdigo fuente

La respuesta es idntica en ambas bases de datos.

Cuidado! En los comentarios contenidos en estos ejemplos puedes ver la forma en la que mysql_fetch_row ymysql_fetch_array tratan los ndices escalares de los resultados que producen los SELECT de MySQL. Los valores de los ndices se asignan a los contenidos de los campos por el mismo orden en el que estos se escriben en la sentencia SELECT. El campo1 (primero que se escribe) ser recogido por el elemento de ndice cero del array, el campo2 ser recogido con ndice uno y as sucesivamente

Consultando slo algunos campos y limitando la salida a n registros


Ahora utilizaremos la sentencia SELECT campo1,campo2, ... FROM tabla LIMIT (n, m) y tendremos como resultado una lista que contendr m registros a partir del n+1, por el mismo orden que la anterior, y mostrando los campos indicados.
Ejecutar consulta Ver cdigo fuente

La respuesta es idntica en ambas bases de datos.

Consultando slo algunos campos y ordenando la salida


Utilizaremos la sentencia MySQL de esta forma SELECT campo1,campo2, ... FROM tabla ORDER BY campo_n [ASC|DESC], campo_m [ASC|DESC] y tendremos como resultado una lista ordenada por el primero de los campos indicados en ORDER BY, y en caso de coincidencia de valores en ese campo, utilizaramos el criterio de ordenacin sealado en segundo lugar.
Ejecutar consulta Ver cdigo fuente

La respuesta es idntica en ambas bases de datos.

Consulta seleccionando registros


Utilizaremos la sentencia MySQL de esta forma SELECT campo1, ... FROM tabla WHERE condicin que nos devolver la lista de registros que cumplen la condicin indicada. Aqu tienes un ejemplo muy sencillo.
Ejecutar consulta Ver cdigo fuente

La respuesta es idntica en ambas bases de datos.

Consultas condicionadas
La clasula WHERE permite un variado abanico de condiciones, que trataremos de resumir aqu. Las opciones sealadas con (*) tiene alguna diferencia de comportamiento. En el propio ejemplo o en llamada a pie de tabla tienes comentadas sus causas.
Operador Tipo Sintaxis Descripcin Cdigo Ver

de campo

fuente ejemplo Selecciona los registros que contienen en el campo un valor igual a num Selecciona los registros que contienen en el campo una cadena idntica a cadena (*) Selecciona los registros que contienen en el campo un valor menor a num Selecciona los registros que contienen en el campo una cadena cuyos n primeros caracteres sonmenores que los de la cadena, siendo n el nmero de caracteres que contiene cadena. (**) Selecciona los registros que contienen en el campo un valor menor O igual a num Selecciona los registros que contienen en el campo una cadena cuyos n primeros caracteres sonmenores que los de la cadena, siendo n el nmero de caracteres que contiene cadena y aade respecto al caso anterior la opcin de que en caso de que ambos valores fueran iguales tambin los presentara (**) Selecciona los registros que contienen en el campo un valor mayor a num Selecciona los registros que contienen en el campo una cadena cuyos n primeros caracteres sonmayores que los de la cadena, siendo n el nmero de caracteres que contiene cadena. (**) Ver Ver Ver Ver Ver Probar Probar Probar Probar Probar

= = < < <=

Numrico WHEREcampo=num Cadena WHEREcampo="cadena"

Numrico WHEREcampo<num Cadena WHEREcampo<"cadena"

Numrico WHEREcampo<=num

<= > > >= >=

Cadena

WHEREcampo<="cadena"

Ver

Probar

Numrico WHEREcampo>num Cadena WHEREcampo>"cadena"

Ver Ver

Probar Probar Probar

Numrico WHEREcampo>=num

Selecciona los registros que contienen en el campo un valor mayor o igual a num Ver Selecciona los registros que contienen en el campo una cadena cuyos n primeros caracteres sonmayores que los de la cadena, siendo n el nmero de caracteres que contiene cadena y aade respecto al caso anterior la opcin de que en caso de que ambos valores fueran iguales tambin los presentara (**) Selecciona los registros que contienen en el campo valores que coinciden con alguno de los especificados dentro del parntesis. Cuando se trata de valores no numricoz han de ir entre comillas

Cadena

WHEREcampo>="cadena"

Ver

Probar

IN

Numrico WHERE campoIN o (valor1,valor2..) Cadena

Ver

Probar

Numrico WHERE campoBETWEEN BETWEEN o valor1 AND valor2 Cadena

Selecciona los registros en los que los valores contenidos en el campo seleccionado estn comprendidos en el intervalo valor1 (mnimo) valor2 (mximo) incluyendo en la seleccin ambos extremos. Ver Cuando los contenidos de los campos son cadenas sigue los mismos criterios que se indican para los dems operadores de comparacin Selecciona los registros en los que los valores contenidos en el campo seleccionado son NULOS Selecciona los registros en los que los valores contenidos en el campo seleccionado son NO NULOS Ver Ver

Probar

IS NULL IS NOT NULL

Cadena Cadena

WHERE campo IS NULL WHERE campo IS NOT NULL

Probar Probar

(*) Cuando se trata de cadenas de caracteres, el concepto menor que significa anterior en la ordenacin de los caracteres segn su cdigo ASCII y mayor quesignifica posterior en esa misma ordenacin. (**) La discriminacin de Maysculas/Minsculas depender del tipo de campo. Recuerda que en MySQL los tipo BLOB hacen esa discriminacin, mientras que los de tipo TEXT son insensibles a maysculas/Minsculas y tambin a vocales con y sin tilde. SQLite siempre toma en consideracin esas diferencias.

Cuando se trata de comparar cadenas MySQL dispone de una potente instruccin (LIKE) que permite establecer los criterios de seleccin a toda o parte de la cadena. Su sintaxis contempla distintas posibilidades utilizando dos comodines>: % (que se comporta de forma similar al (*) en las bsquedas de Windows) y _ (de comportamiento similar a (?) en Windows). Aqu tienes algunas de sus posibilidades:
Cdigo Ver fuente ejemplo Ver Ver Ver Ver Probar Probar Probar Probar

Sintaxis WHERE campoLIKE '%cadena%' WHERE campoLIKE 'cadena%' WHERE campoLIKE '%cadena' WHERE campoLIKE '_cadena%'

Descripcin Selecciona todos los registros que contengan la cadena en el campo indicado sea cual fuere su posicin Selecciona todos los registros en los que el campo indicado que contengan la cadena exactamente al principio del campo Selecciona todos los registros en los que el campo indicado que contengan la cadena exactamente al final del campo Selecciona todos los registros en los que el primer caracter del campo puede ser cualquiera pero los siguientes han de serexactamente los indicados en cadena pudiendo ir seguidos de cualesquiera otros caracteres

El comodn (_) puede ir tanto al principio como al final y puede repetirse tantas veces como sea necesario. Por tanto sera correctoLIKE '___es%' y tambin LIKE 'a___es%' as como: LIKE '%a___es'.

La clasula WHERE aun tiene ms opciones. Acepta mltiples condiciones vinculadas por los operadores lgicos AND, OR, NOT o sus sintaxis equivalentes: &&, || y !. El comportamiento de estos operadores es idntico al descrito para sus homnimos de PHP en esta pgina

Utilizando funciones sobre campos


Por medio de la sintaxis SELECT MAX(campo1), MIN (campo2), ... FROM tabla obtendramos UNA SOLA FILA cuyos valores seran los resultados de la aplicacin de las funciones a todos los registros del campo indicado. Aqu tienes un ejemplo que determina todos los valores de esos estadsticos aplicados al campo Contador de nuestra tabla demo4.
Ejecutar consulta Ver cdigo fuente

Observa que en el cdigo fuente hemos incluido dos consultas distintas y que la consulta MySQL devuelve un valor ms que SQLite. Se debe a que la funcin STDDEV (desviacin tpica de la poblacin) no est definida en SQLite.

Aplicando la opcin GROUP BY


Tal como sealamos al margen, las funciones anteriores pueden aplicarse a grupos de registros seleccionados mediante un criterioGROUP BY (nombre del campo) En este ejemplo obtendremos los mismos parmetros estadsticos que en el anterior, pero ahora agrupados por sexo, lo que significara que obtendremos dos filas de resultados. Aqu tienes el ejemplo
Ejecutar consulta Ver cdigo fuente

Es vlido el comentario del caso anterior para STDDEV (desviacin tpica de la poblacin) que no est definida en SQLite.

Manejo de fechas en las consultas


MySQL dispone de algunas clusulas de gestin de fechas que pueden tener una gran utilidad a la hora de gestionar consultas. En el caso de SQLite las cosas son algo distintas. No dispone de tales herramientas sin embargo si posee algunas funciones que permiten obtener resultados similares. En los ejemplos utilizamos las siguientes: substr(campo,posicion_inicial,numero_caracteres) extrae del contenido del campo de la tabla indicado el numero_caracteres comenzando a partir del que ocupa la posicion_inicial. Siposicion_inicial es un nmero negativo la determinar contando los caracteres contenidos en el campo de derecha a izquierda.
Formato Descripcin %d %e %m %c %y %Y Da del mes en formato de dos dgitos Da del mes en formato de uno dos dgitos Nmero del mes en formato de dos dgitos Nmero del ao en formato de dos dgitos Nmero del ao en formato de cuatro dgitos Sintaxis Ver cdigo Ver ejemplo Probar Probar Probar Probar Probar Probar

DATE_FORMAT(Nacimiento,'%d') Ver DATE_FORMAT(Nacimiento,'%e') Ver DATE_FORMAT(Nacimiento,'%m') Ver DATE_FORMAT(Nacimiento,'%y') Ver DATE_FORMAT(Nacimiento,'%Y') Ver

Nmero del mes en formato de uno o dos dgitos DATE_FORMAT(Nacimiento,'%c') Ver

Creacin de tablas a partir de la consulta de otra tabla


Reiteramos aqu lo ya comentado cuando estudibamos MYSQL. Es frecuente -podra decirse que es lo habitual- relacionar tablasmediante campos con idntico contenido. Supongamos que entre los individuos de nuestra tabla demo4 se pretende establecer un proceso de seleccin para elegir entre ellos un nmero determinado de astronautas, pongamos por caso.

Supongamos tambin, que la seleccin va a constar de tres pruebas que sern juzgadas y calificadas por tres tribunales distintos. Una primera opcin sera crear tres tablas una para cada tribunal e incluir en ellas todos los datos de cada uno de los individuos. Esa opcin es factible pero no es ni la ms cmoda, ni tampoco es la ms rpida ni la que menos espacio de almacenamiento necesita. No debemos olvidar que una tabla puede tener una enorme cantidad de registros. Una opcin alternativa sera crear tres nuevas tablas que slo contuvieran dos campos cada una. Por ejemplo el campo DNI y el campo Calificacin. Como quiera que el campo DNI ha de contener los mismos valores en las cuatro tablas y adems es un campo nicopodran crearse las nuevas tablas y luego copiar en cada una de ellas todos los DNI de la tabla original. Nos garantizara que no habra errores en los DNI y adems nos garantizara que se incluyeran todos los aspirantes en esas nuevas tablas. Aqu tienes el cdigo fuente de un script que crea esas tres tablas (a las que hemos llamado prueba1, prueba2 y prueba3.
Ver cdigo fuente

Una consulta conjunta de varias tablas


MySQL permite realizar consultas simultneas en registros situados en varias tablas. Para ese menester se usa la siguiente sintaxis:

SELECT tabla1.campo1, tabla2.campo2, ... FROM tabla1, tabla2

en la que, como ves, modificamos ligeramente la sintaxis ya que anteponemos el nombre de la tabla al del campo correspondiente separando ambos nombres por un punto, con lo cual no hay posibilidad de error de identificacin del campo incluso cuando campos de distinta tabla tengan el mismo nombre. Otra innovacin -respecto a los ejemplos anteriores- es que detrs de la clusula FROM escribimos los nombres de todas las tablas que est usando SELECT. A partir de ah se pueden establecer todo tipo de relaciones para las sentencias WHERE, ORDER BY y GROUP BY utilizando para ellocampos de cualquiera de las tablas sin otra particularidad ms que poner cuidado al aludir a los campos utilizando siempre la sintaxisnombre_tabla.nombre_campo. A modo de ejemplo hemos procurado comentarlo lnea a lnea aqu tienes un script PHP que hace una consulta conjunta de las tablasdemo4, demodat1, demodat2 y demodat3 y nos presenta una tabla con los datos personales y las puntuaciones de las tres pruebas as como las suma de puntos de las tres y, adems, ordena los resultados -de mayor a menor- segn la suma de las tres puntuaciones.
Ejecutar consulta Ver cdigo fuente

Declaraciones preparadas (Prepare statement)


La clase PDO dispone de una alternativa al mtodo query que conviene conocer. Requiere realizar el proceso de consulta en dos pasos que utilizan los mtodos siguientes: $actuacion= $objeto->prepare(SENTENCIA) El mtodo prepare prepara la SENTENCIA para su ejecucin devolviendo el resultado como un objeto $actuacion. Este mtodo no ejecuta la sentencia, solo la prepara. $actuacion-> execute() El mtodo execute es propio de los objetos resultantes de la $actuacion de una sentencia. Devuelve el objeto resultado de la ejecucin de esa sentencia. Este objeto permite extraer y organizar los resultados mediante mtodos como estos:

$recuento=$actuacion-> rowCount() Tambin rowCount es un mtodo propio de los objetos resultantes de una $actuacion . La variable recuento contiene el nmero de registros afectados por la ejecucin de esa sentencia. Cuando se trata de sentencias que devuelven resultados (caso tpico de las consultas) pueden utilizarse algunos mtodos que facilitan la organizacin de la informacin. Los ms tiles pueden ser estos: $resultado=$actuacion-> fetch(PDO::FETCH_NUM ) aplicando el mtodo fetch al objeto que resulta de execute ($actuacion) se recoge el $resultado en un array escalar cuyo primer ndice es cero y que sigue el mismo orden por el que los campos han sido incluidos en la consulta en el registro actual. $resultado=$actuacion-> fetch(PDO::FETCH_ASSOC ) Cuando se incluye FETCH_ASSOC el resultado ser un array asociativo cuyos ndices coinciden con los nombres de los campos incluidos en la consulta en el registro actual. $resultado=$actuacion-> fetch(PDO::FETCH_BOTH ) FETCH_BOTH es el valor por defecto. Devuelve un array asociativo indexado por los nombres de los campos y otro escalar indexado (a partir de cero) por las posiciones de los campos en la sentencia SELECT en el registro actual. $resultado=$actuacion-> fetchAll(PDO::FETCH_BOTH )

Sentencias que devuelven ms de un resultado


Cuando una sentencia produce como resultados varios registros caso habitual en las consultas las opciones anteriores no ofrecen los resultados esperados. En esos supuestos es necesaria las siguiente modificacin:

Hay que modificar el mtodo fetch agregando el siguiente parmetro: $resultado=$actuacion-> fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_NEXT ) de esta forma ya estaremos en condiciones de construir esa consulta y efectuar la lectura de los resutados por medio de un bucle tal como puedes ver en este ejemplo.

<?php include('conecta.inc.php'); $dbMySQL= conecta('ejemploSQLite','MySQL'); $dbSQLite= conecta('ejemploSQLite','SQLite'); $tabla="demo4"; $query= "SELECT Nombre, Apellido1, Apellido2 FROM $tabla WHERE Nombre='Dorotea'"; /* preparamos la consulta*/ $consulta=$dbSQLite->prepare($query); /* ejecutamos la consulta */ $consulta->execute(); print "<br><br>La consulta SQLite ha producido los siguientes resultados<br><br>"; /* creamos un bucle que ir recorriendo los resultados de la consulta como consecuencia de haber agregado a fecth el valor PDO::FETCH_ORI_NEXT */ while($resultado=$consulta->fetch(PDO::FETCH_ASSOC,PDO::FETCH_ORI_NEXT)){ print $resultado['Apellido1']." ".$resultado['Nombre']."<br />"; } /* repetimos el mismo proceso anterior, esta vez para el objeto MySQL */ $consulta=$dbMySQL->prepare($query); $consulta->execute(); print "<br><br>La consulta MySQL ha producido los siguientes resultados<br><br>"; while($resultado=$consulta->fetch(PDO::FETCH_ASSOC,PDO::FETCH_ORI_NEXT)){ print $resultado['Apellido1']." ".$resultado['Nombre']."<br />";

} ?>
Realizar consultas

Otra posibilidad, alternativa a la anterior, nos la ofrece el siguiente mtodo PDO: $resultado=$actuacion-> fetchAll() dnde $resultado es un array bidimensional que contiene el resultado de la ejecucin de una sentencia previamente preparada mediante $actuacion=$objeto->prepare(SENTENCIA) y ejecutada por medio de $actuacion->execute(). El primer ndice del array es de tipo escalar (contiene el nmero de orden, empezando en cero, de cada registro ledo) El segundo ndice ofrece dos posibilidades. Una de carcter escalar (siendo su valor el nmero de orden, partiendo de cero, del nombre del campo en la sentencia que crea la consulta) y otra asociativa siendo el nombre del ndice identico a nombre del campo o campos sobre los que se realiza la consulta.

<?php include('conecta.inc.php'); $dbMySQL= conecta('ejemploSQLite','MySQL'); $dbSQLite= conecta('ejemploSQLite','SQLite'); $tabla="demo4"; $query= "SELECT Nombre, Apellido1, Apellido2 FROM $tabla WHERE Nombre='Dorotea'"; /* preparamos y ejecutamos la consulta */ $consulta=$dbSQLite->prepare($query); $consulta->execute(); print "<br><br>La consulta SQLite ha producido los siguientes resultados<br><br>"; /* mediante fetchall nos devolver un array bidimensional con todos los resultados*/ $resultado=$consulta->fetchAll(); /* el bucle nos recorrer los primeros indices y extraeremos los valores de los elementos deseados de cada uno de esos indices */ for ($i=0;$i<sizeof($resultado);$i++){ print $resultado[$i]['Nombre']." ".$resultado[$i]['Apellido1']."<br>"; } /* repetimos la misma consulta ahora con el objeto MYSQL*/ $consulta=$dbMySQL->prepare($query); $consulta->execute(); print "<br><br>La consulta MySQL ha producido los siguientes resultados<br><br>"; $resultado=$consulta->fetchAll(); for ($i=0;$i<sizeof($resultado);$i++){ print $resultado[$i]['Nombre']." ".$resultado[$i]['Apellido1']."<br>"; } ?>
Realizar consultas

La tabla sqlite_master
Auque en algunas situaciones puntuales las transacciones de las que hablaremos ms adelante ser necesario el uso de un fichero temporal llamado rollback journal, la gestin de una base de datos SQLite puede hacerse mediante un nico archivo llamado archivo principal de la base de datos. Ese archivo principal est formado varias por partes iguales, llamadas pginas, de tamaos comprendidos entre 512 y 65536 31 bytes. El nmero de pginas mximo puede ser 2 - 2 lo cual significa que un fichero de base de datos SQLite podra llegar a tener (considerando todas las pginas posibles y el tamao mximo de estas) una dimensin de 140 terabytes. En la seccin de encabezado del archivo principal de base de datos est la tabla sqlite_master, gestionada de forma automtica, que contiene la informacin sobre la ubicacin de las restantes tablas (nmero de pgina en el que estn situadas), ndices, view y trigger contenidos en la base de datos. Se crea de forma automtica mediante una sentencia similar a esta:

CREATE TABLE sqlite_master( type text, name text, tbl_name text, rootpage integer, sql text )
En ella, el campo type de esta tabla recoge, dependiendo del tipo de objeto utilizado, uno de los siguientes valores: 'table', 'index', 'view'o 'trigger'. El campo name contendr el nombre del elemento(indice, consulta, trigger o tabla). En tbl_name se recoge el nombre de la tabla a la que est asociado el objeto (si el elemento es un ndice sera el nombre de la tabla a la que va asociado). Por ltimo, en rootpage se indica el nmero de pgina en la que comienza el objeto y el campo de texto sql suele incluir el texto de la sentencia utilizada para la creacin del objeto. Todas las tablas de una base de datos SQLite, estn registradas en sqlite_master. Una consulta como esta nos permite visualizar su contenido.

<?php include('conecta.inc.php'); $dbSQLite= conecta('ejemploSQLite','SQLite'); /* Escribimos una consulta todos los datos de la tabla correspondiente a registros tipo table */ $llamadaSQLite = "SELECT * FROM sqlite_master WHERE type='table'"; if($resultado=$dbSQLite->query($llamadaSQLite)){ print "La tabla sqlite_master contiene los siguientes registros <br>"; foreach ($resultado as $registro=>$contenido){ print "<b>Tabla del registro n.: ".$registro."</b><br />"; foreach ($contenido as $campo=>$valor){ if (!is_int($campo)){ print "<i>Campo: </i>".$campo; print "<i> Valor: </i>".$valor."<br>"; } } } } else{ print "Ha habido un error de PDO: <br />" ; echo "<pre>"; print_r($dbSQLite->errorInfo()); echo "</pre>"; } ?>
ejemplo529.php

Si ejecutas el ejemplo anterior tal vez te encuentres con una tabla llamada sqlite_sequence en cuya estructura existen nicamente dos campos: name y seq. Esta tabla de crea de forma automtica cuando alguna de las tablas que componen la base de datos incluye un campo autoincremental. Ser en esta tabla donde se recogan los ltimos valores de estos campos en cada una de las tablas que los requieran.

Modificacin de la estructura de una tabla


Las modificaciones de tablas utilizan la sentencia ALTER TABLE complementada con las palabras reservadas ADD cuando se trata de agregar un nuevo campo. Si la modificacin conlleva la eliminacin de un campo el proceso ser un poco ms complejo ya que habra que hacerlo segn el siguiente proceso: 1. Crear una nueva tabla cuyo diseo incluya los nombres de campos que pretendemos mantener. 2. Copiar los datos de la tabla actual a la nueva tabla.

3. Eliminar la tabla antigua. 4. Cambiar el nombre a la nueva tabla asignndole el de la recin borrada.

Renombrar una tabla


Se puede cambiar el nombre de una tabla utilizando la sentencia: ALTER TABLE nombre_de_la_tabla RENAME TO nuevo_nombre dnde el nombre actual de la tabla es nombre_de_la_tabla y el futuro nuevo_nombre

Borrar una tabla


Las sentencias MySQL que permiten borrar una tabla son las siguientes: DROP TABLE nombre de la tabla o DROP TABLE IF EXISTS nombre de la tabla la diferencia entre ambas radica en que usando la segunda no se generara ningn error en el caso de que tratramos de borrar una tabla inexistente.

PDO Modificaciones SQLite / MySQL Sintaxis SQLite de modificacin de registros


Las sentencias SQLite que permiten la modificacin de registros en las tablas son prcticamente iguales a las comentadas para MySQL e igual que aquella existen clusulas obligatorias y opcionales. El orden en que deben estar indicadas ha de seguir la misma secuencia en la que estn descritas aqu. UPDATE Tiene carcter obligatorio, debe ser la primera palabra de la sentencia e indica a SQLite que vamos realizar una modificacin tabla Es obligatoria y contiene el nombre de la tabla que pretendemos modificar. SET Tiene carcter obligatorio y debe estar delante de las definiciones de campo y valor. campo1 = valor1 Es obligatoria al menos una definicin. Indica el nombre del campo a modificar (campo1) y el valor que se asignar a ese campo. Si se pretende modificar ms de un campo se repetir esta definicin tantas veces como sea necesario, separando cada una de ellas por una coma. WHERE Es un campo opcional y su comportamiento es idntico al sealado al mencionar el proceso de consultas. ORDER BY Tiene idntica funcionalidad a la descrita al referirnos a consultas

Modificar un campo en todos los registros de una tabla


La sentencia SQLite, que permite modificar uno o varios campos en todos los registros de una tabla, es la siguiente: UPDATE tabla SET campo1=valor1, campo2=valor2

Cuidado!

Hay que tener muy presente que con esta sentencia en la que no aparece WHERE se modificarn TODOS LOS REGISTROS DE LA TABLA y por lo tanto los campos modificados tendrn el mismo valor en todos los registros.

Algunas consideraciones sobre la sintaxis


Siempre que manejes PHP y SQLite debes tener muy presente todo lo ya comentado para el caso de MySQL que repetimos aqu para mayor comodidad de lectura. SQLite requiere SIEMPRE que los valores tipo cadena que incluyen campos de fecha vayan entre comillas. Por el contrario, losnumricos no deben llevar comillas. Presta mucha atencin a esto cuando escribas los valores directamente en la sentencia SQLite. Cuando pases valores desde una variable PHP debes tener muy en cuenta las consideraciones anteriores y si el contenido de la variable es una cadena que va a ser tratada como tal por SQLite tienes dos opciones para evitar el error: Definir la variable as: $variable =" 'valor'" (comillas dobles, comilla simple al principio y comilla simple, comilla doble al final) y poner en la sentencia MySQL el nombre de la variable sin entrecomillar ($variable), o Definir la variable PHP as: $variable =" valor" y al escribir el nombre de esa variable en la sentencia MySQL escribirlo entrecomillas sencillas, es decir, as: '$variable' No pienses que es caprichoso el orden que hemos puesto en las comillas. Recuerda que al llamar a la sentencia MySQL, el contenido de la sentencia va entre comillas (que por costumbre son comillas dobles, por esa razn todo entrecomillado que vaya dentro de esa sentencia ha de usar comillas simples para evitar un error seguro). De ah que al definir una variable PHP en la forma $variable =" 'valor'" las comillas dobles exteriores indican a PHP que se trata de una cadena, por lo que, al pasar la variable a MySQL ste recibir el contenido de la cadena que es, logicamente: 'valor' y en este caso las comillas forman parte del valor, razn por el que no es necesario escribir -en la sentencia MySQL- el nombre de la variable entrecomillado. En este primer ejemplo, hemos incluido una actualizacin de tablas que pondr 24 puntos de calificacin en la primera de las pruebas a todos los aspirantes a astronautas de nuestro ejemplo. Es un caso de actualizacin sin la condicin WHERE y tiene el cdigo comentado.
Ejecutar la modificacin Ver cdigo fuente

Tal como puedes ver, en el ejemplo utilizamos una preparacin declarada (prepare statement) como procedimiento alternativo para modificar la calificacin anterior y pasar a SIETE puntos la nota en todos los registros.

<?php /* incluimos la funcion conecta y creamos objetos de ambas bases de datos */ include('conecta.inc.php'); $dbMySQL= conecta('ejemploSQLite','MySQL'); $dbSQLite= conecta('ejemploSQLite','SQLite'); /* escribimos la consulta que actualizar a 7 el campo Puntos de la tabla prueba1 */ $consulta = "UPDATE prueba1 SET Puntos=7"; /*preparamos la consulta de la tabla SQLite*/ $actualiza = $dbSQLite->prepare($consulta); /* aplicamos el mtodo execute al objeto creado por el mtodo anterior */ $actualiza->execute(); /* leemos el numero de registros afectados por la ejecucin de la sentencia */ $numero_resultados = $actualiza->rowCount(); /* visualizamos la informacin del resultado */ print("Se han actualizado $numero_resultados registros"); /* repetimos exactamente el proceso anterior preparando un objeto MySQL*/ $actualiza = $dbMySQL->prepare($consulta); $actualiza->execute(); $numero_resultados = $actualiza->rowCount(); print("Se han actualizado $numero_resultados registros"); ?>

Ejecutar la modificacin

Ver cdigo fuente

Seleccin y modificacin de un solo registro


Es una de las opciones ms habituales. Es el caso en el que mediante un formulario asignamos una condicin a WHERE y simultneamente asignamos los nuevos valor del campo o campos elegidos. Requiere la siguiente sintaxis: UPDATE tabla SET campo1=valor1, campo2=valor2 WHERE condicin La condicin es fundamental en esta opcin y normalmente aludir a un campo ndice (clave principal o nica), de modo que sea un solo registro el que cumpla la condicin. Podra ser el caso, en nuestro ejemplo, del campo DNI que por su unicidad garantizara que la modificacin solamente va a afectar a uno solo de los registros. El ejemplo siguiente nos permitir hacer modificaciones de este tipo en la tabla prueba2. Observa el cdigo fuente y vers hacemos una primera consulta utilizando prepare y execute y que la posterior inclusin de la modificacin la efectuamos utilizando query.
Ejecutar la modificaccin Ver cdigo formulario Ver cdigo script

Modificacin simltanea de un campo en cualquiera de los registros


Aqu tienes un ejemplo que permite visualizar el valor actual de todas las puntuaciones de la prueba 1 de los astronautas as como sus nombres y apellidos y DNI y en la cual se pueden modificar ninguno, uno, varios o todos los valores y posteriormente actualizarlos todos con los nuevos valores. En este caso hemos separado los scripts buscando una mejor visualizacin de los resultados. Los scripts, tal como podrs ver si observas los cdigo fuente, son practicamente idnticos. la nica y lgica diferencia es que en el primer caso creamos objetos SQLite y en el segundo MySQL.
Ejecutar la modificaccin en SQLite Ejecutar la modificaccin en MySQL Ver cdigo formulario Ver cdigo formulario Ver cdigo script Ver cdigo script

Sintaxis SQLite para borrado de registros


La sintaxis SQLite para las sentencia de borrado de registros de una tabla puede contener las siguientes clusulas que, al igual que ocurra en casos anteriores, pueden tener categora de obligatorias u opcionales. La secuencia en la que deben estar indicadas en la sentencia es idntica al orden en que estn descritas aqu. DELETE Tiene carcter obligatorio. Debe ser la primera palabra de la sentencia e indica a SQLite que tratamos de borrar uno o msregistros. tabla Es obligatoria e indica el nombre de la tabla en la que pretendemos efectuar el borrado o eliminacin de los registros. WHERE Es un campo opcional y su comportamiento es idntico al sealado en al mencionar el proceso de consultas.

Borrar todos los registros de una tabla


La sentencia SQLite que permite borrar todos los registros de una tabla es la siguiente: DELETE FROM tabla Ten muy presente que con esta sentencia -en la que no aparece WHERE- se BORRARN TODOS LOS REGISTROS DE LA TABLA. Respecto a otras posibles opciones, no difiere en nada de lo indicado en la pgina anterior. Simplemente habra que sustituir en aquellos script UPDATE por DELETE. Borrar un registro no es otra cosa que un caso particular de modificacin.

Integridad referencial tras el borrado de una tabla


Recuerdas el ejemplo de las pruebas de seleccin de astronautas? Recuerdas que las tres tablas de puntuaciones haban sido creadas a partir de la tabla de datos de los aspirantes? Qu ocurrira si borrsemos uno o varios registros de una de ellas? Qu ocurrira se despus de crear esas tablas aadisemos nuevos aspirantes a la lista de candidatos? Es obvio que si no hacemos algo para evitarlo se perdera la integridad referencial la relacin uno a uno entre los registros de esas tablas. Ocurrira que no todos los individuos que estn incluidos en una de esas tablas lo estaran en las dems y por tanto, al ejecutar consultas o modificaciones posteriores correramos el riesgo de que se produjeran errores. Esa situacin es fcilmente evitable modificando ligeramente los scripts con los que se realizan los procesos de altas y bajas. Bastara con aadirles algunas sentencias que cada vez que se efecta un alta o baja en el fichero de datos personales efecten el mismo proceso en todos los dems ficheros relacionados con aquel. Aqu tienes comentado el cdigo fuente de la modificacin aadida al script que registra los nuevos aspirantes en el fichero de altas de la tabla demo4. Con esta modificacin se actualizaran automticamente los ficheros prueba1, prueba2 y prueba3 cada vez que se aadiera un nuevo aspirante. El formulario no requiere ninguna modificacin, Slo es necesario realizar los cambios en el script que realiza la insercin.
Aadir nuevo aspirante Ver cdigo formulario Ver cdigo script

Hecho este inciso continuaremos con la referencia al borrado de registros. En este ejemplo, tienes el cdigo fuente de un script que realiza el borrado de un registo mediante un formulario en el que se inserta el DNI tanto en la tabla demo4 como demodat1, demodat2 y demodat3 manteniendo la integridad referencial entre los cuatro ficheros.
Eliminar un aspirante Ver cdigo formulario Ver cdigo script

Borrar registros seleccionndolos de una lista


En el ejemplo siguiente tienes el cdigo para utilizar la clusula WHERE en un proceso de borrado de registros que presenta un formulario que contiene una lista con todos los registros actuales y una casilla de verificacin por cada uno. Al marcar las casillas y enviar el formulario el script que recibe los datos procede al borrado de todos los registros marcados en todas la tablas afectadas.
Borrar aspirantes MySQL Borrar aspirantes SQLite Ver cdigo formulario Ver cdigo formulario Ver cdigo script Ver cdigo script

Transacciones en tablas SQLite


Comntabamos al tratar las tablas InnoDB en los temas relativos a MySQL que uno de los riesgos que se plantean en la gestin de bases de datos es que pueda producirse una interrupcin del proceso mientras se est actualizando una o varias tablas. Decamos tambin que las transacciones evitan este tipo de situaciones ya que los datos se registran de manera provisional y no se consolidan hasta que una instruccin confirme que esas anotaciones tienen carcter definitivo.

Sintaxis de las transacciones


Existen tres sentencias muy similares a las de MySQL para gestionar las transacciones. Son las siguientes: $objeto->query("BEGIN")

Indica a SQLite que en ese punto comienza una transaccin. Todas las sentencias que se ejecuten a partir de ella tendrn carcterprovisional y no se concretarn de forma efectiva hasta que encuentre una sentencia que las confirme. $objeto->query("ROLLBACK") Mediante esta sentencia advertimos a SQLite que finaliza la transaccin pero que no debe hacerse efectiva ninguna de las modificaciones incluidas en ella. $objeto->query("COMMIT") Esta sentencia advierte a SQLite que ha finalizado la transaccin y que S debe hacer efectivos todos los cambios incluidos en ella.
Ejecutar ejemplo Ver cdigo fuente

Modificacin de estructuras de tablas SQLite


Las opciones de modificacin de estructuras de tablas SQLite se limitan a los tres tipos de actuaciones siguientes.

Borrar una tabla


Las sentencias MySQL que permiten borrar una tabla son las siguientes: DROP TABLE nombre de la tabla DROP TABLE IF EXISTS nombre de la tabla Las diferencia entre ambas radica en que usando la segunda no se generara ningn error en el caso de que tratramos de borrar una tabla inexistente.

Renombar una tabla


SQLite permite cambiar el nombre de una tabla haciendo uso de la sentencia siguiente: ALTER TABLE nombre_actual RENAME TO nuevo_nombre cambiara el nombre_actual por el nuevo_nombre.

Agregar un nuevo campo


SQLite permite agregar un nuevo campo a una tabla ya existente mediante la sentencia: ALTER TABLE tabla ADD COLUMN nuevo_campo agrega el nuevo_campo a la tabla.

Borrar o modificar un campo


Cuando se pretende borrar un campo de una tabla o modificar su tipo SQLite no dispone de una sentencia especfica que permita esas transformaciones. Para hacerlo deberamos recurrir a un proceso un poco ms complejo cuyos diferentes pasos son los siguientes: 1. Crear una nueva tabla cuyo diseo incluya los nombres de campos que pretendemos mantener. 2. Copiar los datos de la tabla actual a la nueva tabla. 3. Eliminar la tabla antigua. 4. Cambiar el nombre a la nueva tabla asignndole el de la recin borrada.

PDO Seguridad en SQLite / MySQL Inyeccin de cdigo


El hecho de utilizar los recursos PHP Data Objects no excluye los riesgos de seguridad derivados de lo que llambamos inyeccin de cdigo cuando tratbamos de MySQL. Todo lo argumentado all respecto a los riesgos y vulnerabilidades sigue teniendo plena vigencia tal como puedes ver en este ejemplo.

<?php include('conecta.inc.php'); $dbMySQL= conecta('ejemploSQLite','MySQL'); $dbSQLite= conecta('ejemploSQLite','SQLite'); $nombre="' or '34=34"; $tabla="demo4"; /* recogemos la cadena tal como viene en la condicin WHERE. Por tratarse de una cadena tenemos que entrecomillar el nombre de la variable en esa clusula */ $query= "SELECT Nombre, Apellido1, Apellido2 FROM $tabla WHERE Nombre='$nombre'"; /* esta consulta nos dar como resultado una lista de todos los registros de la tabla. Habremos vulnerado las mnimas reglas de seguridad */ /* primero con el objeto SQLite */ print "Esta es la condicin de la consulta: ".$query."<br />"; print "<br /><i>Resultado de la consulta SQLite</i><br />"; if($resultado=$dbSQLite->query($query)){ print "Estos son los resultados de la consulta en la base de /><br />"; foreach ($resultado as $matriz){ print $matriz[1]." ".$matriz[2].", ".$matriz[0]."<br } } /* Igual proceso el objeto MySQL */ print "<br /><i>Resultado de la consulta MySQL</i><br />"; if($resultado=$dbMySQL->query($query)){ print "Estos son los resultados de la consulta en la base de /><br />"; foreach ($resultado as $matriz){ print $matriz[1]." ".$matriz[2].", ".$matriz[0]."<br } } ?>
Ver ejemplo

datos SQLite<br />";

datos SQLite<br />";

Como habrs podido observar una consulta con el cdigo adecuado WHERE Nombre='' or '34=34' muestra la vulnerabilidad y devuelve todos los registros contenidos en la tabla por las mismas razones ya comentadas al estudiar MySQL. PDO dispone de un mtodo que pala en gran medida este tipo de riesgos. Se trata de: $variable=$objeto->quote(cadena) que recoge en $variable el contenido de la cadena incluyndolo dentro de unas comillas simples'. De esa forma una cadena como ' or '34=34 resultara transformada en '' or '34=34'

<?php include('conecta.inc.php'); $dbMySQL= conecta('ejemploSQLite','MySQL'); $dbSQLite= conecta('ejemploSQLite','SQLite'); $nombre="' or '34=34";

/* aplicamos el mtodo quote a la cadena con lo cual el nuevo valor de la variable \$nombre se entrecomillar de forma automatica */ $nombre=$dbSQLite->quote($nombre); $tabla="demo4"; /* ya no incluimos la variable \$nombre entre comillas. Ya se las ha asignado el mtodo quote */ $query= "SELECT Nombre, Apellido1, Apellido2 FROM $tabla WHERE Nombre=$nombre"; print "Esta es la condicin de la consulta: ".$query."<br />"; /* la consulta ahora ya no listar ninguno de los registros. Habremos mejorado la seguridad */ print "<br /><i>Resultado de la consulta SQLite</i><br />"; if($resultado=$dbSQLite->query($query)){ print "Estos son los resultados de la consulta en la base de datos SQLite<br /><br />"; foreach ($resultado as $matriz){ print $matriz[1]." ".$matriz[2].", ".$matriz[0]."<br />"; } } /* tambien en le caso de MySQL se producir el resultado esperado */ print "<br /><i>Resultado de la consulta MySQL</i><br />"; if($resultado=$dbMySQL->query($query)){ print "Estos son los resultados de la consulta en la base de datos SQLite<br /><br />"; foreach ($resultado as $matriz){ print $matriz[1]." ".$matriz[2].", ".$matriz[0]."<br />"; } } ?>
Ver ejemplo

En cualquier caso los procedimientos anteriores no son los ms aconsejables para la realizacin de consultas seguras. Lo aconsejable en estos casos es utilizar las declaraciones preparadas agregando algunas opciones a las ya comentadas. A la sintaxis ya conocida: $actuacion= $objeto->prepare(SENTENCIA) $actuacion-> execute() puede hacrsele una modificacin incluyendo un nuevo mtodo (bindParam) que tiene como finalidad enlazar el valor de una variable con un identificador incluido en la sentencia SQL. Una sintaxis como esta: $actuacion= $objeto->prepare('SELECT * FROM tabla WHERE (Nombre=? and Apellido1=?)') $actuacion-> bindParam(posicion, $variable,tipo, longitud); $actuacion-> execute() en la que hacemos las siguientes modificaciones: En la sentencia SQL sustituimos por ? lo que anteriormente eran nombres de variables (entre comillas por su condicin de cadenas alfanumricas) del tipo '$nombre' y '$apellido'. Agregamos tantas llamadas a mtodos bindParam como ? contiene la sentencia SQL incluida por mtodo prepare Las llamadas a los mtodos bindParam requieren dos parmetros obligatorios y permiten otros dos opcionales. El primero de ellos posicion indica la posicin en la sentencia SQL del ? al que alude. Las posiciones se cuentan a partir de uno y de izquierda a derecha. El sealado como $variable es el nombre de una variable previamente definida que contiene el valor que ha de sustituir al? aludido. Hemos de tener en cuenta que ha de incluirse siempre un nombre de variable y que si tratramos de sustituirlo por un cadena que contenga su valor se producir un error.

El parmetro tipo tiene carcter opcional e indicara el tipo de contenido de la variable. Puede tener como valoresPDO::PARAM_STR o PDO::PARAM_INT (sin comilla). En el primer caso indicara que la variable es de tipo cadena y en el segundo que es de tipo entero. Cuando el tipo es PDO::PARAM_STR puede incluirse longitud que indicara el nmero de caracteres de la cadena. El mtodo execute producira los resultados ya comentados. Veamos dos ejemplos. El primero de ellos utiliza el mtodo bindParam( mientras que el segundo no lo hace.
Con bindParam Ver cdigo fuente Sin bindParam Ver cdigo fuente

Como habrs podido observar el uso de bindParam impidi la inyeccin del cdigo maligno. Desde las pginas oficiales de PHP se recomienda utilizar este mtodo en la situaciones en la que se prevean riesgos de este tipo. El mtodo bindParam permite algunas modificaciones tales como estas: $actuacion= $objeto->prepare('SELECT * FROM tabla WHERE (Nombre=:campo_nombre and Apellido1=:campo_apellido) ') $actuacion-> bindParam(':campo_nombre' , $variable,tipo, longitud); $actuacion-> execute() Hemos sustituido cada ? de la sentencia SQL por una palabra cualquiera precedida de : y tambin el nmero de posicion (en la llamada al mtodo bindParam) por una cadena (fjate que va entre comillas) que incluye exactamente el mismo nombre con los : obligatorios incluido en la sentencia SQL. Puedes verlo en el ejemplo.
Ver nuevo ejemplo Ver cdigo fuente

An disponemos de otra posibilidad alternativa a la anterior. Sera esta: $actuacion= $objeto->prepare('SELECT * FROM tabla WHERE (Nombre=:campo_nombre and Apellido1=:campo_apellido) ') $actuacion-> execute(array(':campo_nombre'=>$variable)) En este caso hemos omitido la llamada al mtodo bindParam y cmo alternativa hemos incluido en la llamada al mtodo execute un array asociativo al que asignmos como ndices los palabras de la sentencia (siempre precedidas por los dos puntos) y como valor los nombres de la variable que los contiene. Si en la sentencia utilizramos ? el array habra de ser de tipo escalar. Puedes verlo en los ejemplos.
Ver nuevo ejemplo Ver cdigo fuente Ver nuevo ejemplo Ver cdigo fuente

Como habrs podido observar el filtro de seguridad ha funcionado en todos estos ejemplos. Los intentos de visualizar nombre mediante el cdigo ' or '34=34 han fracasado.

La extensin MySQLi La extensin MySQLI


Aunque no ofrece ninguna novedad respecto a otras interfaces de gestin de bases de datos MySQL mediante PHP, la extensinMySQLi, o como a veces se le conoce, la extensin de MySQL mejorada, viene incluida en las versiones PHP 5 y posteriores y se desarroll para aprovechar las nuevas funcionalidades que incluyen las versiones de MySQL posteriores a la 4.1.3. Desde la pgina oficial de PHP se nos sugiere su uso argumentando que Esta es la opcin recomendada, ya que utilizando el controlador nativo de MySQL resulta en un mejor rendimiento y permite el acceso a funciones que no estn disponibles cuando se utiliza la biblioteca de cliente MySQL. Comparada con la extensin MySQL ofrece las siguientes mejoras: Interfaz orientada a objetos Soporte para Declaraciones Preparadas Soporte para Mltiples Declaraciones Soporte para Transacciones

Mejoradas las opciones de depuracin Soporte para servidor empotrado Conocido el manejo de las bases de datos MySQL y el manejo de las mismas mediante PDO o la librera mysql la utilizacin de esta nueva opcin no va a plantearnos demasiadas dificultades. Lo iremos comprobando en los epgrafes siguientes.

Instalacin y configuracin de MySQLi


El uso del interface MySQLi requiere tener activa la extensin de PHP del mismo nombre.Bajo Windows, hemos de usar la extensinextension=php_mysqli.dll. Como siempre en estos casos, habremos de editar el fichero php.ini, buscar esa extensin, descomentarlarla (quitar el punto y coma que llevan delante), guardar los cambios y reiniciar el servidor. Cuando se trata de Ubuntu es preciso realizar la siguiente instalacin:

sudo apt-get install php5-mysqli con lo cual, en cualquiera de los dos casos, una vez reiniciado el servidor la pgina http://localhost/info.php debera mostrarnos una informacin similar a esta:

Gestin de bases de datos MySQL mediante MySQLi


Cuando se utiliza esta librera existen dos posibilidades de gestin de las bases de datos MySQL o MariaDB. Por un lado, la gestin que podemos llamar clsica que guarda una gran similitud con la ya conocida de la gestin por procesos de MySQL y, como opcin alternativa, el estilo orientado a objetos que ya hemos manejado al tratar del PDO. En pginas anteriores hemos tratado ambos formas de proceder. Por ello en este caso intentaremos concretar en paralelo ambas formas de proceder. Interaremos ir describiendo ambas formas de sintaxis y los sucesivos epgrafes y trataremos tambin de ir desarrollando ejemplos, con los mismos resultados, en ambas modalidades de programacin.

Creacin de bases y/o acceso a bases de datos

MySQLi no es un servidor de bases de datos nuevo o distinto de MySQL. Es nicamente una extensin PHP para acceder a ese tipo de bases de datos. Por tanto, los elementos propios de MySQL: ficheros, tablas, tipos de datos, ndices y sentencias son exactamente los ya comentados en las pginas cuyos enlaces hemos incluido en este prrafo. Desarrollaremos todos los ejemplos atendiendo a la existencia de un fichero al que llamaremos mysqli.inc.php cuyo contenido es el siguiente:

<?php; $cfg_servidor="localhost"; $cfg_usuario="pepe"; $cfg_password="pepa"; $cfg_basephp1="ejemplosMySQLi"; ?>


De esta forma podremos automatizar el proceso de conexin y evitar repeticiones innecesarias de algunas lneas de cdigo.

Conexin/desconexin al servidor de bases de datos MySQL


Estilo por procesos
La sintaxis no difiere demasiado de la ya conocida. Cunado utilizemos la programacin mediante procesos la sintaxis ser la clsica de MySQL utilizando ahora la funcin mysqli_connec en vez de mysql_connec. La instruccin sera: $conexion= mysqli_connect(host,usuario, contrasea )

dnde $conexion es el identificador de la conexin y host, usuario y contrasea los respectivos nombres del servidor, usuario y contrasea que estn recogidos en la variables incluidas en el fichero mysqli.inc.php al que hemos hecho alusin en prrafos anteriores. Cuando se trata de cerrar la conexin es necesaria ejecutar mysqli_close de forma similar a la ya conocida. Ahora deberemos escribir: mysqli_close($conexion)

Estilo orientado a objetos


$objeto= new mysqli ( servidor, usuario, contrasea )

dnde $objeto es el identificador de un nuevo objeto, y servidor, usuario y contrasea los respectivos nombres del servidor, usuario y contrasea que coinciden con las ya mencionadas variables incluidas en el fichero mysqli.inc.php. El cierre de la conexin requiere invocar el mtodo close() y por lo tanto escribir algo como: $objeto->close()

Este es un ejemplo de utilizacin sucesiva de ambas modalidades de programacin.


Ejecutar ejemplo Ver cdigo fuente

Gestin de errores de conexin


Cuando se trata de mysqli la gestin de errores se realiza a dos niveles. Los errores de conexin utilizan recursos de dignostico distintos de otros errores de utilizacin de MySQL. El cdigo de error se identifica en el caso de la programacin por procesos mediante la funcin: mysqli_connect_errno() y la descripcin de ese error se objetiene mediante mysqli_connect_error().

Si estamos utilizando objetos los eventuales cdigos de error de conexin y sus descripciones los obtendramos de las propiedades$objeto->mysqli_connect_errno y span class="cursiva1">$objeto->mysqli_connect_error. Podrs observar que, a diferencia del caso de programacin por procesos, aqu errorno y error no van seguidos de parntesis.
Mediante procesos Ver cdigo fuente Mediante objetos Ver cdigo fuente

Creacin de bases de datos y errores en sentencias


Las sentencias MySQL no difieren en absoluto de las ya comentadas para el caso de utilizacin de la librera mysql o del PDO. Por tanto son vlidas las sentencias ya conocidas: CREATE DATABASE nombre_de_la_base y CREATE DATABASE IF NOT EXISTS La ejecucin de estas sentencias requiere las siguientes sintaxis:

Estilo por procesos


Requiere haber realizado una conexin previa y su correspondiente identificador de conexin. En esas condiciones la instruccin PHP sera: $sentencia=CREATE DATABASE nombre_de_la_base mysqli_query($conexion, $sentencia) o tambin $sentencia=CREATE DATABASE IF NOT EXISTS nombre_de_la_base mysqli_query($conexion, $sentencia)

en este ltimo supuesto evitaramos la generacin de errores como consecuencia de intentar crear ya base de datos preexistente.

Cuidado! Fjate en el orden en el que se incluyen los parmetros. En el caso de mysqli la funcin mysqli_query lleva como primer parmetro es el indentificador de conexin y la sentencia propiamente dicha se incluye en segundo lugar. Esto es justo lo inverso de lo utilizado cuando se trabaja con el interface mysql y la funcin mysql_query.

Estilo orientado a objetos


Cuando trabajemos bajo esta modalidad de programacin se requerir la creacin previa de un objeto conexin a servidor y la ejecucin de la sentencia MySQL a travs del mtodo query(). La sintaxis sera: $sentencia=CREATE DATABASE nombre_de_la_base $objeto->query($sentencia) o tambin $sentencia=CREATE DATABASE IF NOT EXISTS nombre_de_la_base $objeto->query($sentencia)

Informacin sobre errores


La gestin de errores en la ejecucin de sentencias es distinta a la ya comentada para las conexiones. En este nuevo supuesto los mensajes de error podremos optenerlos de la funcin mysqli_error($conexion) en el caso de procesos y cuando se trate de programacin orientada a objetos usaremos la propiedad $objeto->error.

Cuando se trata de conocer los cdigos de error habra que utilizar mysqli_errno($conexion) o $objeto->errno dependiendo del mtodo de programacin que estemos utilizando. En estos ejemplos tienes los procesos de creacin de una base de datos y la gestin de esos errores.
Mediante procesos Ver cdigo fuente Mediante objetos Ver cdigo fuente

Borrar bases de datos MySQL


Estas sentencias tampoco difieren de las ya comentadas para el caso de utilizacin de la librera mysql o del PDO. Por tanto son vlidas: DROP DATABASE nombre_de_la_base y DROP DATABASE IFEXISTS La ejecucin de estas sentencias requiere las siguientes sintaxis:

Estilo por procesos


Requiere haber realizado una conexin previa y su correspondiente identificador de conexin. En esas condiciones la instruccin PHP sera: $sentencia=DROP DATABASE nombre_de_la_base mysqli_query($conexion, $sentencia) o tambin $sentencia=DROP DATABASE IF EXISTS nombre_de_la_base mysqli_query($conexion, $sentencia)

en este ltimo supuesto evitaramos la generacin de errores como consecuencia de intentar borrar una base de datos inexistente.

Estilo por procesos


Una vez dispongamos un objeto conexin a servidor la ejecucin de la sentencia MySQL a travs del mtodo query(). La sintaxis sera: $sentencia=DROP DATABASE nombre_de_la_base $objeto->query($sentencia) o tambin $sentencia=DROP DATABASE IF EXISTS nombre_de_la_base $objeto->query($sentencia)
Mediante procesos Ver cdigo fuente Mediante objetos Ver cdigo fuente

Base de datos ejemplos


Utilizaremos una nueva base de datos con nombre ejemplosMySQLi nombre coincidente con el que hemos asignado a la variable$cfg_basephp1 en el fichero mysqli.inc.php. Como es lgico resulta indiferente utilizar cualquiera de los mtodos de desarrollo del script. Tanto utilzando procesos como por medio de objetos el resultado sera idntico.
Ver cdigo fuente

Creacin de tablas usando MySQLi Tipos de tablas

La mayora de los contenidos de esta pgina son pura transcripcin del contenido de esta otra. Hay algunas diferencias de tratamiento que sealaremos para facilitarte la opcin de comparacin de los diferentes interfaces MySQL permite usar diferentes tipos de tablas tales como: ISAM, MyISAM o InnoDB. Las tablas ISAM (Indexed Sequential Access Method) son las de formato ms antiguo. Estn limitadas a tamaos que no superen los 4 gigas y no permite copiar tablas entre mquinas con distinto sistema operativo. Las tablas MyISAM son el resultado de la evolucin de las anteriores adaptadas por MySQL durante mucho tiempo como el formato por defecto para sus servidores de bases de datos. En las versiones ms recientes de MySQL est cambiando es criterio y empiezan a verse versiones que incluyen InnoDB como formato por defecto. Las tablas del tipo InnoDB (desarrolladas por la compaa finlandesa InnoBase a la que deben su nombre) tienen una estructura distinta a la de MyISAM, ya que utilizan un slo archivo por tabla en ver de los tres habituales en los tipos anteriores. Incorporan dos de ventajas muy importantes: permiten realizar transacciones y definir reglas de integridad referencial. Hablaremos ms adelante de ello. La definicin de uno u otro formato (MyISAM o InnoDB) debe hacerse en el momento de la creacin de tabla y solo reguiere agregarType=MyISAM Type=InnoDB a la sentencia MySQL encargada de crearla.

Creacin de tablas
Las tablas son elementos de las base de datos. Por esa razn nos resultar imposible crear una tabla sin tener creada yseleccionada una base de datos. Es por eso que para la creacin de una tabla se necesitan los siguientes requisitos: Tener abierta una conexin con el servidor MySQL. Tener seleccionada una base de datos.

Conexin con el servidor


La hemos comentado en la pgina anterior. Recuerda que requera la funcin: $conexion = mysqli_connect ( servidor, usuario, contrasea ) (no confundir el mysqli_connect utilizado aqu con mysql_connect que es el manejado en pginas anteriores)y que esa conexin ha de ser establecida antes de cualquier otra intervencin relacionada con accesos a bases de datos y tablas.

Seleccin de la base de datos


Dado que podemos manejar bases de datos distintas es preciso decir a MySQL con qu base queremos trabajar. mysqli_select_db(nombre_base_datos, $conexion)

donde nombre_base_datos es el nombre de la base de datos (puede ser una cadena entrecomillada o el nombre de una variable previa que contenga ese nombre). En este ltimo caso, como es habitual, el nombre de la variable no llevara comillas. El segundo parmetro$conexion es el identificador de conexin. Es decir, la variable creada al establecer la conexin con MySQL. Este valor debe insertarse siempre. La razn es que MySQL permite mantener abiertas varias, de forma simultnea, varias conexiones (podramos manejar ms de un servidor de bases de datos) y en esas condiciones no pueden darse ambigedades respecto a la base que pretendemos usar. Tambin es conveniente tener muy presente que en este caso hay que diferenciar tambin mysqli_select_db de mysql_select_db(observa que se diferencian nicamente en una i). Este proceso puede simplicarse incluyendo el nombre de la base de datos como cuarto parmetro de la funcin mysqli_connect. Mediante esta opcin $conexion = mysqli_connect ( servidor, usuario, contrasea, nombre_base_datos) estaremos seleccionando la base de datos nombre_base_datos a la vez que establecemos la conexin. Si hemos optado por la programacin orientada a objetos la seleccin de la base de datos puede incluirse en la llamada al constructor de la clase. La forma de hacerlo es similar a esta:

$objeto = new mysqli ( servidor, usuario, contrasea, nombre_base_datos)

Creacin de una tabla


En todas las transacciones PHP MySQL habremos de utilizar instrucciones de ambos lenguajes. La forma habitual hay algunas excepciones en la que PHP se comunica con MySQL. Para utilizar el interface mysqli es necesario utilizar la funcin genrica: mysqli_query($conexion, $sentencia ); donde la variable $sentencia contiene las instrucciones propias de MySQL y $conexion sigue siendo la variable que contiene el identificador de conexin. En el mbito de la programacin orientada a objetos la ejecucin de este tipo de sentencias (una vez creado el objeto y establecida satisfactoriamente la conexin) utiliza siempre la misma sintaxis: $objeto->query( $sentencia) Las variables aludidas como $sentencia en los prrafos anteriores ha de contener una de estas cadenas: CREATE TABLE IF NOT EXISTS tabla (campo1, campo2,... ) Type=tipo o CREATE TABLE tabla (campo1, campo2,... )) Type=tipo

donde tabla es una cadena que contiene el nombre de la tabla que pretendemos crear, dnde campo1, campo2, etc. son las definiciones de los campos que pretendemos que contenga la tabla y tipo puede ser MyISAM o InnoDB segn el tipo de tabla que queramos crear. La nica diferencia entre ambas opciones es que la segunda dara un error si tratramos de crear una tabla preexistente (deberamos recurrir al procedimiento que hemos visto cuando crebamos bases de datos) mientras que la primera no da ese mensaje de error.

Definicin de campos en una tabla MySQL


Cada uno de los campos que vayamos a crear en una tabla requiere una definicin que debe contener lo siguiente: nombre del campo

Es una palabra cualquiera distinta para campo de la tabla y que normalmente suele elegirse aludiendo al contenido. Por ejemplo,fecha_nacimiento, nombre_del_perro, etctera. No va entre comillas nunca y MySQL diferencia maysculas/minsculas. Para utilizar como nombres de campo palabras reservadas del lenguaje MySQL por ejemplo, create debemos escribirlas entre ` `. Observa que no son comillas sino acentos graves. Lo ms aconsejable es evitar esta situacin. tipo y dimensiones

Los tipos de campos los hemos visto en la pgina anterior tienen que ajustarse a uno de los soportados por MYSQL. El tipo de campo se escribe a continuacin del nombre sin otra separacin que un espacio y requieren la sintaxis estricta correspondiente a cada tipo. Cuando se establezca una dimensin como parmetro opcional de un campo deben tenerse en cuenta algunos detalles: Su valor se escribe entre parntesis y se incluye despus del nombre del campo. Si en un campo numrico introdujramos valores que exceden los lmites, su valor no se registrara en la tabla sino el valor dellmite ms prximo correspondiente a ese tipo de campo.

Supongamos un campo tipo TINYINT que permite valores comprendidos entre -128 y 127. Si asignramos en uno de sus registros un valor igual a 234 se escribira en la tabla 127 (el lmite superior) y si ponemos -834 escribira el lmite inferior, es decir, -128. En caso de cadenas, si el valor introducido sobrepasara la longitud mxima permitida, la cadena sera recortada y nicamente se registrara el nmero mximo de caracteres permitidos. flags del campo ( son opcionales) Puede utilizarse cualquiera de los permitidos para cada tipo de campo. Puedes verlos encerrados, entre corchetes, al lado de cada tipo de campo. Cuando sea necesario incluirlo han de escribirse inmediatamente despus del nombre del campo o de la dimesin (en los casos en que se incluya).

Ejemplo de creacin de una tabla


Este ejemplo con campos idnticos a los de uno incluido en pginas anteriores podemos ver las dos opciones de creacin de tablas en una base de datos. Dependiendo del valor pasado como tipo en la llamada al script se ejecutar una u otra de las opciones.

<?php /* crearemos antes una variable que recoja toda la sentencia y ser luego cuando la ejecutemos Definiremos una varable llamada $crear e iremos aadiendo cosas */ # la primera parte de la instruccin es esta (espacio final incluido $crear="CREATE TABLE IF NOT EXISTS "; # aadiremos el nombre de la tabla que ser ejemplo1 # fijate en el punto (concatenador de cadenas) que permite # ir aadiendo a la cadena anterior $crear .="ejemplo1 "; #ahora pongamos el parntesis (con un espacio delante) #aunque el espacio tambin podra detrs de ejemplo1 $crear .="( "; # insertemos el primer campo y llamemoslo num1 # hagamoslo de tipo TINYINT sin otras especificamos # sabiendo que solo permitira valores numricos # comprendidos entre -128 y 127 $crear .="num1 TINYINT , "; # LOS CAMPOS SE SEPARAN CON COMAS por eso # la hemos incluido al final de la instruccin anterior # ahora num2 del mismo tipo con dimensin 3 y el flag UNSIGNED # Y ZEROFILL que: cambiar los lmites de valores # al intervalo 0 - 255, y rellenar con ceros por la izquierda # en el caso de que el nmero de cifras significativas # sea menor de 3. # Fijate que los flags van separado unicamente por espacios $crear .="num2 TINYINT (3) UNSIGNED ZEROFILL, "; # en num3 identico al anterior aadiremos un valor por defecto # de manera que cuando se aadan registros a la tabla # se escriba automaticamente ese valor 13 en el caso # de que no le asignemos ninguno a ese campo # por ser numrico 13 no va entre comillas $crear .="num3 TINYINT (7) UNSIGNED ZEROFILL DEFAULT 13, "; # ahora un nmero decimal num4 tipo REAL con 8 digitos en total # de los cuales tres sern decimales y tambin rellenaremos con ceros # Pondremos como valor por defecto 3.14 $crear .="num4 REAL (8,3) ZEROFILL DEFAULT 3.14, "; # aadamos una fecha $crear .="fecha DATE, "; /* una cadena con un limite de 32 carcter con BINARY para que diferencie Pepe de PEPE */ $crear .="cadena VARCHAR(32) BINARY, "; /* un ultimo campo opcion del tipo ENUM que solo admita

como valores SI, NO, QUIZA fijate en las comillas y en el parentesis cuidado...!! aqui no ponemos coma al final es el ltimo campo que vamos a insertar y no necesita ser separado. Si la pones dar un ERROR */ $crear .="opcion ENUM('Si','No','Quiza') "; # solo nos falta aadir el parntesis conteniendo toda la instruccin $crear .=")Type=MyISAM"; /* tenemos completa la sentencia MYSQL solo falta ejecutarla crear la conexin y ejecutarla */ /*incluimos los parmetros de conexin */ include('mysqli.inc.php'); /* incluimos dos opciones de proceso y de programacion orientada a objetos. Podemos ejecutar los ejemplos pasado mediante el metodo GET el tipo elegido. */ if(!empty ($_GET['tipo'])){ $tipo_script=$_GET['tipo']; }else{ $tipo_script="objetos"; } /*En caso de tipo proceso utilizaramos esto */ if ($tipo_script=="proceso"){ /****** Programacin mediante procesos ***********/ #conexion, seleccin de tabla y verificacion de errores segun ejemplos anteriores $conexion=@mysqli_connect ($cfg_servidor,$cfg_usuario,$cfg_password,$cfg_basephp1); if(!mysqli_connect_errno()==0){ print "<br>No ha podido realizarse la conexin mediante procesos<br>"; print "Error nmero: ". mysqli_connect_errno()." equivalente a: ". mysqli_connect_error(); exit(); } # gestion de la base de datos. Los parmetros requieren el ordn aqu indicado if(mysqli_query($conexion,$crear)){ print "La tabla ha sido CREADA"; }else{ print "<br>No ha podido crearse la base de datos mediante procesos<br>"; print "Error : ". mysqli_error($conexion); exit(); } mysqli_close($conexion); } /* en caso de programacion orientada a objetos */ if ($tipo_script=="objetos"){ /****** Programacin mediante objetos ***********/ #conexion, seleccin de tabla y verificacion de errores segun ejemplos anteriores $objeto=@new mysqli ($cfg_servidor,$cfg_usuario,$cfg_password,$cfg_basephp1); if(!$objeto->connect_errno==0){ print "<br>No ha podido realizarse la conexin mediante objetos<br>"; print "Error nmero: ". $objeto->connect_errno." equivalente a: ". $objeto>connect_error; exit(); } # gestion de la base de datos. Los parmetros requieren el ordn aqu indicado if($objeto->query($crear)){ print "La tabla ha sido CREADA";

}else{ print "<br>No ha podido crearse la tabla mediante objetos<br>"; print "Error : ". $objeto->error; exit(); } $objeto->close(); } ?>
Mediante procesos Mediante objetos

Ver y modificar estructuras (usando MySQLi) Visualizar la estructura de una tabla (estilo por procesos)
Ver la estructura de una tabla utilizando MySQL
La sentencia MySQL que permiten visualizar la estructura de una tabla es la siguiente: SHOW FIELDS from nombre de la tabla

Lectura de resultados de sentencias MySQL


La sentencia SHOW FIELDS como prcticamente ocurre con todas las sentencias MySQL no devuelve los resultados en un formatolegible. Los valores devueltos requieren ser convertidos a un formato que sea interpretable por PHP. Esa traduccin se realiza de la siguiente forma: El resultado devuelto por MySQL a travs de una llamada mysqli_query() es recogido en una variable, de la forma siguiente:$resultado=mysqli_query($conexion, $sentencia) El resultado recogido en la variable $resultado, est estructurado en lneas. Por medio de la funcin: $linea =mysqli_fetch_row ($resultado) se recoge en una variable ($linea) el contenido de la primera lnea situndose el puntero interno al comienzo de la lnea siguiente. Por esta razn la lectura completa del contenido de la variable $linea requiere llamadas sucesivas a mysqli_fetch_rowhasta que haya sido leda la ltima de las lneas del resultado de la llamada a MySQL. La variable $linea tiene estructura de array escalar siendo cero el primero de sus ndices. Cuando el puntero interno demysql_fetch_row() alcance el final de la ltima lnea del resultado devolver como resultado FALSE. Por esa razn, la visualizacin de los resultados de una sentencia MySQL suele requerir dos bucles. Este es el esquema de la lectura: $resultado=mysqli_query($conexion,$sentencia); while($linea=mysqli_fech_row($resultado){ foreach ($linea as $valor){ print $valor; } }

tambin cabra usar una sintaxis alternativa similar a esta: $resultado=mysqli_query(sentencia,$conexion); while($linea=mysqli_fech_row($resultado)){ $matriz[]=$linea; }

con lo que estaramos creando un array bidimensional con el contenido de los resultados de cada lnea. En este caso el primer ndicedel array $matriz sera un escalar que empezara en cero y se ira autoincrementando en una unidad en cada uno de los ciclos del buclewhile. El ejemplo tiene desarrollados ambos procedimientos.

<?php # incluimos una variable con el nombre de la tabla $tabla="ejemplo1"; # incluimos los datos de la conexin y la base de datos para include("mysqli.inc.php"); # establecemos la conexin con el servidor y seleccionamos la base de datos $conexion=mysqli_connect ($cfg_servidor,$cfg_usuario,$cfg_password,$cfg_basephp1); $sentencia="SHOW FIELDS from ".$tabla; #ejecutamos mysql_query llamando a la sentencia SHOW FIELDS $resultado=mysql_query($conexion,$sentencia); # ejecutamos los bucles que comentamos mas arriba while($linea=mysqli_fetch_row ($resultado)){ foreach($linea as $valor) { print $valor."<br>"; } } #tenemos que VOLVER a EJECUTAR LA SENTENCIA MySQL porque el puntero est # AL FINAL de la ultima lnea de los resultados print("<BR> Los nuevos resultados son <br>"); $resultado=mysql_query($conexion,$sentencia); while($linea=mysqli_fetch_row ($resultado)){ $matriz[]=$linea; } # leemos ahora el array bidimensional foreach ($matriz as $indice=>$mi_linea){ foreach ($mi_linea as $indice2=>$valor){ print "<i>Indice</i>: ".$indice." <i>Indice2</i>: ".$indice2." <i>Valor</i>: ".$valor."<br>"; } } # cerramos la conexion con el servidor mysqli_close($conexion); ?>
ejemplo566.php

El procedimiento anterior nos facilita informacin sobre la estructura de la tabla pero quiz no lo haga con toda la claridad que fuera de desear. Para mejorar las prestaciones de la anterior existe una funcin alternativa que es: $matriz =mysqli_fetch_array($resultado)

idntica en cuanto a requerimientos pero recogiendo en un array los resultados de la sentencia. Ese array tiene adems la peculiaridad de incluye cada uno de los valores en dos ndices distintos. Uno de los ndices es de tipo escalar. El otro es de tipo asociativo y sus ndices son los valores del campo de la tabla del que se han extraido los resultadosativos. En este ltimo caso incorporan como ndice el nombre del campo de la tabla del que se han extrado los resultados. $matriz =mysqli_fetch_array($resultado, MYSQL_NUM)

idntica a la anterior.La inclusin del parmetro MYSQL_NUM (sin comillas )limita sus resultado a los elementos del array de ndice escalar.

$matriz =mysqli_fetch_array($resultado, MYSQL_ASSOC)

Tambin idntica a las anteriores. La inclusin del parmetro MYSQL_ASSOC (sin comillas )limita ahora los resultado a los elementos del array asociativo.

<?php # incluimos una variable con el nombre de la tabla $tabla="ejemplo1"; # incluimos los datos de la conexin y la base de datos para include("mysqli.inc.php"); # establecemos la conexin con el servidor y seleccionamos la base de datos $conexion=mysqli_connect ($cfg_servidor,$cfg_usuario,$cfg_password,$cfg_basephp1); $sentencia="SHOW FIELDS from ".$tabla; #ejecutamos mysql_query llamando a la sentencia SHOW FIELDS $resultado=mysqli_query($conexion,$sentencia); print("<br> Los resultados con mysqli_fech_array<br><br>"); while ($linea=mysqli_fetch_array($resultado)){ # leemos el array de resultados de cada una de las lineas extraidas del resultado foreach($linea as $indice=>$valor) { print ("El indice es: ".$indice." y el valor es: ".$valor."<br>"); } } /* vamos a separar los elementos escalares de los asociativos comprobando si es numrico el indice de cada array */ print "<br>Los elementos de array con indice numrico son estos<br>"; $resultado=mysqli_query($conexion,$sentencia); while ($linea=mysqli_fetch_array($resultado,MYSQL_NUM)){ /* leemos el array de resultados de cada una de las lineas extraidas del resultado e insertamos un texto que nos ayude a ver lo contenidos de cada linea en la pantalla */ print "<br>Nueva lnea<br>"; foreach($linea as $indice=>$valor) { print ("El indice es: ".$indice." y el valor es: ".$valor."<br>"); } } /* visualizamos los resultados cuando el indice es NO NUMRICO */ print "<br>Los elementos de array con indice no numrico son estos<br>"; $resultado=mysqli_query($conexion,$sentencia); while ($linea=mysqli_fetch_array($resultado, MYSQL_ASSOC)){ /* leemos el array de resultados de cada una de las lineas extraidas del resultado e insertamos un texto que nos ayude a ver lo contenidos de cada linea en la pantalla */ print "<br>Nueva lnea<br>"; foreach($linea as $indice=>$valor) { print ("El indice es: ".$indice." y el valor es: ".$valor."<br>"); } } mysqli_close($conexion); ?>
ejemplo567.php

Como habrs podido observar al ejecutar el ejemplo SHOW FIELDS nos permite conocer los propiedades de cada uno de los campos de la tabla: Field (nombre del campo), Type (incluye el tipo, el tamao y los flags), Null (especificara si el campo permite

o no permite valores nulos), Key (especificara si ese campo es o es un ndice de la tabla) y Default (que incluira los eventuales valores asignados por defecto al campo).

Visualizar la estructura de una tabla (estilo orientado a objetos)


Ver la estructura de una tabla utilizando MySQL
La sentencia MySQL que permiten visualizar la estructura de una tabla sigue siendo: SHOW FIELDS from nombre de la tabla

Lectura de resultados de sentencias MySQL


La sentencia SHOW FIELDS como prcticamente ocurre con todas las sentencias MySQL no devuelve los resultados en un formatolegible. Los valores devueltos requieren ser convertidos a un formato que sea interpretable por PHP. Esa traduccin se realiza de la siguiente forma: El resultado devuelto por MySQL a travs de una llamada al mtodo query() en un objeto mysqli es recogido en una variable, de la forma siguiente: $resultado=$objeto->query($sentencia) El resultado recogido en el nuevo objeto $resultado, est estructurado en lneas. Por medio del mtodo: $linea =$resultado->fetch_row () se recoge en una variable ($linea) el contenido de la primera lnea situndose el puntero interno al comienzo de la lnea siguiente. Por esta razn la lectura completa del contenido de la variable $linea requiere llamadas sucesivas a mysqli_fetch_rowhasta que haya sido leda la ltima de las lneas del resultado de la llamada a MySQL. La variable $linea tiene estructura de array escalar siendo cero el primero de sus ndices. Cuando el puntero interno demysql_fetch_row() alcance el final de la ltima lnea del resultado devolver como resultado FALSE. Por esa razn, la visualizacin de los resultados de una sentencia MySQL suele requerir dos bucles. Este es el esquema de la lectura: $resultado=$objeto_mysqli->query($sentencia); while($linea=$resultado->fech_row(){ foreach ($linea as $valor){ print $valor; } }

tambin cabra usar una sintaxis alternativa similar a esta: $resultado=$objeto_mysqli->query(sentencia); while($linea=$resultado->fech_row()){ $matriz[]=$linea; }

con lo que estaramos creando un array bidimensional con el contenido de los resultados de cada lnea. En este caso el primer ndicedel array $matriz sera un escalar que empezara en cero y se ira autoincrementando en una unidad en cada uno de los ciclos del buclewhile. El ejemplo tiene desarrollados ambos procedimientos.

<?php # incluimos una variable con el nombre de la tabla $tabla="ejemplo1"; # incluimos los datos de la conexin y la base de datos para include("mysqli.inc.php"); # creamos el objeto conexin con el servidor y seleccionamos la base de datos

$objeto_mysqli=new mysqli ($cfg_servidor,$cfg_usuario,$cfg_password,$cfg_basephp1); $sentencia="SHOW FIELDS from ".$tabla; #ejecutamos mysql_query llamando a la sentencia SHOW FIELDS $resultado=$objeto_mysqli->query($sentencia); # ejecutamos los bucles que comentamos mas arriba while($linea=$resultado->fetch_row ()){ foreach($linea as $valor) { print $valor."<br>"; } } #tenemos que VOLVER a EJECUTAR LA SENTENCIA MySQL porque el puntero est # AL FINAL de la ultima lnea de los resultados print("<BR> Los nuevos resultados son <br>"); $resultado=$objeto_mysqli->query($sentencia); while($linea=$resultado->fetch_row ()){ $matriz[]=$linea; } # leemos ahora el array bidimensional foreach ($matriz as $indice=>$mi_linea){ foreach ($mi_linea as $indice2=>$valor){ print "<i>Indice</i>: ".$indice." <i>Indice2</i>: ".$indice2." <i>Valor</i>: ".$valor."<br>"; } } # cerramos la conexion con el servidor $objeto_mysqli->close(); ?>
ejemplo568.php

El procedimiento anterior nos facilita informacin sobre la estructura de la tabla pero quiz no lo haga con toda la claridad que fuera de desear. Para mejorar las prestaciones de la anterior existe una mtodo alternativa que es: $matriz =$resultado->fetch_array()

idntica en cuanto a requerimientos pero recogiendo en un array los resultados de la sentencia. Ese array tiene adems la peculiaridad de incluye cada uno de los valores en dos ndices distintos. Uno de los ndices es de tipo escalar. El otro es de tipo asociativo y sus ndices son los valores del campo de la tabla del que se han extraido los resultadosativos. En este ltimo caso incorporan como ndice el nombre del campo de la tabla del que se han extrado los resultados. $matriz =$resultado->fetch_array(MYSQL_NUM)

idntica a la anterior.La inclusin del parmetro MYSQL_NUM (sin comillas )limita sus resultado a los elementos del array de ndice escalar. $matriz =$matriz =$resultado->fetch_array(MYSQL_ASSOC)

Tambin idntica a las anteriores. La inclusin del parmetro MYSQL_ASSOC (sin comillas )limita ahora los resultado a los elementos del array asociativo.

<?php # incluimos una variable con el nombre de la tabla $tabla="ejemplo1"; # incluimos los datos de la conexin y la base de datos para include("mysqli.inc.php");

# creamos el nuevo objeto conexin con el servidor y seleccionamos la base de datos $objeto_mysqli=new mysqli ($cfg_servidor,$cfg_usuario,$cfg_password,$cfg_basephp1); $sentencia="SHOW FIELDS from ".$tabla; #ejecutamos mysql_query llamando a la sentencia SHOW FIELDS $resultado=$objeto_mysqli->query($sentencia); print("<br> Los resultados con fech_array<br><br>"); while ($linea=$resultado->fetch_array()){ # leemos el array de resultados de cada una de las lineas extraidas del resultado foreach($linea as $indice=>$valor) { print ("El indice es: ".$indice." y el valor es: ".$valor."<br>"); } } /* vamos a separar los elementos escalares de los asociativos comprobando si es numrico el indice de cada array */ print "<br>Los elementos de array con indice numrico son estos<br>"; $resultado=$objeto_mysqli->query($sentencia); while ($linea=$resultado->fetch_array(MYSQL_NUM)){ /* leemos el array de resultados de cada una de las lineas extraidas del resultado e insertamos un texto que nos ayude a ver lo contenidos de cada linea en la pantalla */ print "<br>Nueva lnea<br>"; foreach($linea as $indice=>$valor) { print ("El indice es: ".$indice." y el valor es: ".$valor."<br>"); } } /* visualizamos los resultados cuando el indice es NO NUMRICO */ print "<br>Los elementos de array con indice no numrico son estos<br>"; $resultado=$objeto_mysqli->query($sentencia); while ($linea=$resultado->fetch_array( MYSQL_ASSOC)){ /* leemos el array de resultados de cada una de las lineas extraidas del resultado e insertamos un texto que nos ayude a ver lo contenidos de cada linea en la pantalla */ print "<br>Nueva lnea<br>"; foreach($linea as $indice=>$valor) { print ("El indice es: ".$indice." y el valor es: ".$valor."<br>"); } } $objeto_mysqli->close(); ?>
ejemplo569.php

Manipulacin de tablas
Borrar tablas
Las sentencias MySQL que permiten borrar una tabla son las siguientes: DROP TABLE IF EXISTS from nombre_de_la_tabla o DROP TABLE from nombre_de_la_tabla

la diferencia entre ambas radica en que usando la primera no se generara ningn error en el caso de que tratramos de borrar una tabla inexistente.

Aqu tienes el cdigo fuente de dos ejemplos que utilizan las distintas opciones de programacin.
Ver cdigo fuente mediante procesos Ver cdigo fuente mediante objetos

Borrar uno de los campos de una tabla


La sentencia MySQL que permite borrar uno de los campos de una tabla es la siguiente: ALTER TABLE nombre_de_la_tabla DROP nombre_del_campo

Es posible modificar la estructura de una tabla -en este caso borrar un campo- siguiendo un procedimiento similar a los anteriores. La nica diferencia estriba en utilizar la sentencia MySQL adecuada. Resulta obvio que el campo debe existir para que pueda ser borrado y si no existiera, es obvio tambin que se producira un error. Aqu tienes el cdigo fuente de dos script que borran uno de los campos de una tabla.
Ver cdigo fuente mediante procesos Ver cdigo fuente mediante objetos

Aadir un nuevo campo a una tabla


Las sentencia MySQL que permite aadir un nuevo campo a una tabla es la siguiente: ALTER TABLE nombre_de_la_tabla ADD nombre del campo tipo [flags]

La sintaxis es similar a la de la creacin de tablas: el nombre del campo debe ir seguido del tipo sin otra separacin que el espacio. Aqu tienes el cdigo fuente de dos script que aadem uno de los campos de una tabla.
Ver cdigo fuente mediante procesos Ver cdigo fuente mediante objetos

Aadir registros e ndices (usando MySQLi) Aadir registros a una tabla


La sentencia MySQL que permite aadir registros a una tabla es la siguiente: INSERT tabla (campo1,campo2,..) VALUES (valor1,valor2,..)

Transcribimos el desarrollo un ejemplo anterior de creacin de una tabla e insercin de registros utilizando diversos mtodos. La nica diferencia entre lo que tratemos aqu y lo que hemos visto aqu ser la forma de comunicacin entre PHP y MySQL. El proceso es el siguiente:

Creacin de la tabla
Empezaremos creando una tabla a la que llamaremos demo4 y que contendr los siguientes campos:

Contador, que ser de tipo TINYINT(8) (nmero entero con un mximo de 8 dgitos) que contenga solo valores positivos, que se rellene automticamente con ceros por la izquierda y que se autoincremente cada vez que aadimos un registro. DNI, destinado a recoger valores de nmeros de DNI y que debe poder contener un mximo de ocho caracteres. Lo definiremos de tipo CHAR porque sus valores, pese a ser numricos, nunca van a requerir ningn tratamiento aritmtico. Nombre, Apellido1 y Apellido2 sern tres campos tipo VHAR de tamaos mximos respectivos de 20, 15 y 15 caracteres. Su finalidad la evidencian los nombres de campo. Les asignaremos el flag NOT NULL aunque no sea totalmente correcto dado que existen pases en los que se utiliza un solo apellido. Nacimiento ser un campo tipo DATE al que asignaremos como valor por defecto el de 1970-12-21. Recuerda que MySQL trata las fechas en ese orden (ao-mes-dia) y que admite como separadores tanto - como / por lo que son vlidas entradas con cualquiera de estos formatos: 1970-12-21 1970/12/21, aunque esta segunda es convertida automaticamente al primer formato por MySQL. Hora ser un campo tipo TIME al que asignaremos como valor por defecto el de 00:00:00. Recuerda que MySQL trata las horas en ese orden (hh:mm:ss) y que slo admite como separador :. Este campo est destinado a recoger la hora de nacimiento que aunque no tiene demasiado sentido es una buena excusa para introducir este tipo de campo. Sexo ser un campo tipo ENUM que tendr dos opciones: M (masculino) y F(femenino) y al que asignaremos M como valor por defecto. Fumador ser un campo tipo CHAR(0) que por su estructura -cadena de longitud cero- tendr dos nicas opciones de valor: NULL "", que, como veremos, son valores distintos para MySQL. Idiomas ser un campo tipo SET definido para los valores: Castellano, Francs, Ingls, Alemn, Blgaro y Chino y que podr contener, como ocurre con los campos de este tipo, ninguno, uno o varios de los valores de la lista. ndice primario ser tratado como tal el campo DNI ya que se trata de un valor nico para cada persona y que, como tal, no puede tener duplicados. ndices auxiliares. Para ejemplificar su tratamiento consideraremos el campo Contador como ndice secundario. El cdigo fuente del fichero que genera esta tabla puedes verlo aqu debajo
Ver cdigo fuente

Aadir un registro
Cuando se aade un registro en una tabla los valores pueden aadirse en la propia sentencia MySQL o ser recogidos de los valores de variables PHP previamente definidas. En este ejemplo tienes el cdigo fuente del primero de los casos, en el que se aade a la tabla anterior un registro cuyos valores son:
DNI Nombre Apellido1 Apellido2 Nacimiento Sexo Hora Fumador Idiomas

1234 Lupicinio Servidor Servido 1954-11-23 M


Ver cdigo fuente mediante procesos Ver cdigo fuente mediante objetos

16:24:52 NULL

Presta atencin a los siguientes aspectos: En la sentencia no se alude al campo Contador. La razn es que se trata un campo AUTOINCREMENTAL y en ese tipo de campos los valores de los registros se escriben automticamente cada vez que se aade uno nuevo. El registro no se aadira si el valor de DNI coincidiera con otra ya existente en la tabla. Recuerda que habamos definido ese campo como ndice primario. Si no hubiramos incluido el aviso de error no tendramos ninguna referencia sobre el xito de la insercin y no detectaramos el problema de duplicidad. Sencillamente ocurrira que el registro no se aadira pero no nos enteraramos de tal circunstancia. Si en los valores de nombre y apellidos hubiramos insertado textos ms largos del tamao establecido para ellos al crear la tabla, las cadenas se recortaran y slo se aadiran -de izquierda a derecha- los n primeros caracteres de la cadena.

Si en la fecha de nacimiento hubiramos introducido una cadena vaca nos habra puesto el valor por defecto, pero si hubiramos introducido un valor no vlido nos habra escrito 0000-00-00. Seran valores no vlidos en este caso: Los que tuvieran como valor de mes alguno no perteneciente al intervalo [1,12]. Los que tuvieran como valor de da un valor no vlido en concordancia con el mes y el ao. Admitira 29 en un mes defebrero slo en el caso de que el ao fuera bisiesto. Cuando la secuencia no coincidiera con esta AAAA-MM-DD. Cuando los separadores no fueran (-) o (/). En el campo Sexo si hubiramos introducido una cadena vaca nos habra puesto M (valor por defecto) pero si hubiramos intentado introducir un valor que no fuera M ni F nos habra insertado una cadena vaca. El campo hora se comportara de idntica forma al de fecha salvo que aqu la secuencia es: hh:mm:ss, que la hora debe pertenecer al intervalo [0,23], los minutos y los segundos a [0,59] y que el nico separador vlido en este caso es (:). El campo Fumador requiere particular atencin ya que se trata de un campo CHAR(0) que slo admite dos valores: NULL ocadena vaca, que como recordars son distintos para MySQL. Para introducir el valor NULL utilizando el procedimiento de insercin de este ejemplo tienes que escribir NULL, sin ponerlo entre comillas, tal como lo he hecho en el ejemplo . Para introducir una cadena vaca en este campo bastara con que pusieramos '' (ojo no es una comilla doble es la comilla sencilla (') repetida dos veces! Date cuenta de que si pusiramos comillas dobles tendramos un error ya que hay unas comillas dobles delante delINSERT que se cierran al final de la sentencia MySQL y que no podemos volver a escribirlas entre ambas para evitar unfalso cierre de la cadena que contienen. En este caso el valor del campo Idiomas puede contener valores decimales comprendidos entre 0 y 64 o entre sus equivalentes binarios que son 0 y 111111. El valor 64 lo justifica el hecho de que son seis los elementos que puede contener el campo (hemos definido: Castellano, Francs, Ingls, Alemn, Blgaro y Chino que son seis y que el caso de insertarlos todos requerira el nmero binario 111111, cuyo valor decimal es precisamente 64. El valor 3 significa lo mismo que su equivalente binario (11) o mejor (000011) lo cual quiere decir que, como el primer carcter de la derecha es uno el campo toma el primer elemento de la lista (Castellano), como el segundo (de derecha a izquierda) tambin esuno tomar tambin el segundo elemento de la lista (Francs) y por ser cero todos los dems no tomar ningn otro valor de la lista, con lo que la cadena resultante sera en este caso Castellano, Francs. Fjate tambin en que el valor 3 no lo hemos puesto entre comillas porque se trata de una expresin decimal. Qu ocurra si hubiera puesto 11? Lo habra interpretado como once (decimal) o como tres (binario)?. La solucin es simple: '11' (entre comillas) sera interpretado como binario, sin comillas como decimal. No es necesario introducir valores en todos los campos, es decir, que la lista de campos de la sentencia INSERT puede no contenerlos a todos. No es necesario escribir el nombre de los campos en el mismo orden en el que fueron creados pero si es imprescindible quecampos y valores estn escritos en la sentencia INSERT exactamente en el mismo orden y tambin que en esa sentencia elnmero de campos y el nmero de valores sea el mismo. Recuerda que los values tipo numricono se incluyen entre comillas, mientras que los no numricos tienen que estar contenidos entre comillas incluso en el caso de no se inserten directamente sino a travs de una variable PHP.

Aadir un registro a partir de datos contenidos en variables


Tambin es posible aadir registros a partir de valores contenidos en variables PHP. Esta opcin es, sin ninguna duda, la ms utilizada, ya que lo habitual ser escribir el contenido a aadir en un form y despus -a travs del method (POST o GET)pasar al script de insercin esos valores como variables PHP. Aqu tienes el cdigo fuente de un ejemplo con la tabla anterior.
Ver cdigo fuente mediante procesos Ver cdigo fuente mediante objetos

Quiz te resulten de alguna utilidad estos comentarios:

Observa en el cdigo fuente que al insertar las variables en los VALUES de la sentencia MySQL ponemos cuando se trata de valores tipo cadena '$variable' (el nombre de la variable entre comillas) y cuando se trata de valores nmericos sin comillas. Si quieres introducir el valor NULL en un campo tipo VAR(0) define la variable as: $variable="NULL" y si quieres introducir unacadena vaca defnela de este otro modo:$var="''" -comillas dobles (") seguidas de dos comillas sencillas (') y para terminar otras comillas dobles (") y cuando hagas alusin a esa esta variable como un VALUE en la sentencia de insercin no la pongas entre comillas.

Variantes de la sentencia INSERT


La sentencia INSERT cuya sintaxis se indica ms arriba como: INSERT tabla (campo1,campo2,..) VALUES (valor1,valor2,..)

permite algunos modificadores opciones tales como: INSERT [LOW_PRIORITY | DELAYED] [IGNORE] tabla (campo1,campo2,..) VALUES (valor1,valor2,..)

de ellos LOW_PRIORITY y DELAYED son incompatibles por lo que solo cabe uno u otro pero no ambos. Veamos su utilidad. La insercin de registros y la lectura de una tabla son procesos incompatibles, pero cabe la posibilidad de que se intenten ejecutar simultneamente. No olvides que estamos en Internet y es perfectamente posible que desde dos ordenadores distintos, dos personas distintas estn accediendo a la misma tabla simultneamente y que uno de los accesos sea de escritura, es decir: aadir,modificar o borrar campos en la tabla. Quin tiene preferencia de paso? Quien tiene que esperar?. Si la opcin LOW_PRIORITY est activada, el proceso de escritura esperar a que terminen los procesos de lectura activos, pero si est activa la opcin DELAYED el proceso de lectura se interrumpir automticamente para ceder el paso al de escritura. Respecto a la opcin IGNORE tiene utilidad cuando se trata de realizar una secuencia de inserciones. Si no est activa en el momento en el que aparezca una clave duplicada se interrumpir el proceso de insercin, por el contrario, si estuviera activa el proceso de insercin continuar con los siguientes registros de la secuencia, aunque -como es lgico- seguirn sin insertarse los registros con clave duplicada.

Nmero de resgistros afectados por una sentencia


Cuando se usa el interface de MySQLi es posible cuantificar el nmero de registros afectados por la ejecucin de una sentencia. A tal fin y para el caso de programar mediante procesos disponemos de la funcin mysqli_affected_rows($conexion)

que devuelve el nmero de registros afectados por la ejecucin de la ltima instruccin mysqli_query que utiliz el identificador de conexin $conexion. En el caso de que la programacin de nuestros scripts est orientada a objetos disponemos de la propiedad: $objeto->affected_rows

cuyo valor es nmero de registros afectados por la ltima ejecucin del mtodo $objeto->query(). En los ejemplos siguientes hay ejemplos de utilizacin de este cuantificador.

Tablas para pruebas


Aqu tienes comentado un script que permite agregar aleatoriamente y de forma automtica registros a la tabla demo4. Dado que en las pginas siguientes trataremos de consultas, va a resultarnos muy cmodo poder rellenarlas de forma automtica.
Ver cdigo fuente Ver cdigo fuente

mediante procesos

mediante objetos

Aadir a travs de formularios (MySQLi) Los valores de SELECT MULTIPLE


Los contenidos de esta pgina son una copia de los que hay aqu adaptados a las peculiaridades requeridas para el uso del interface MySQLi. La opcin SELECT MULTIPLE dentro de un form tpico de HTML permite elegir ninguno, uno o varios de los elementos de la lista. Basta con pulsar con el ratn sobre cada uno de los valores elegidos manteniendo pulsada la tecla Ctrl, es decir, puro Windows. Para recoger los valores de esa opcin se define -dentro de la etiqueta SELECT- un name tipo array. Bastara con escribir: SELECT MULTIPLE name=variable[ ] SIZE=6>

Como ves, variable es el nombre de la variable (esta vez sin $ delante, recuerda que no estamos en PHP sino en HTML) y va seguidode [ ] precisamente para indicar que es un array. Lo que respecta a SIZE=6 no es otra cosa que el parmetro que indica cuntos elementos de la lista de opciones queremos que se visualicen simultneamente en la pgina. El elemento ms importante son los values de cada option dentro de ese select. Los hemos escrito as: <option value=1>Castellano <option value=2>Francs <option value=4>Ingls <option value=8>Alemn <option value=16>Blgaro <option value=32>Chino

Fjate que hemos mantenido exactamente el mismo orden en el que han sido definidos en el campo SET de la tabla. Observa tambin los valores: 1, 2, 4, 8, 16 y 32 que son precisamente las potencias de 2: 2 ,2 ,2 ,2 ,2 ,2 ,y2
0 1 2 3 4 5 6

Al ir seleccionando valores, van aadindose al array. Por ejemplo. Si seleccionamos Francs y Blgaro el array sera este: var[0]=2,var[1]=16 Si sumamos esos valores (2 + 16) el resultado sera 18, y al convertir a binario este valor, resultar: 010010 que es como decirle a MySQL (mirando la cadena de derecha a izquierda, lo recuerdas?) que incluya los valores segundo (Francs) y quinto (Blgaro) del SELECT MULTIPLE que corresponden a las posiciones en las que la cadena binaria contiene un uno.

Creacin del formulario


El caso ms frecuente -casi el nico- es que los registros de una tabla se aadan utilizando un formulario y enviando desde l los datos a un script PHP que ejecute la opcin de aadir. Si no recuerdas el funcionamiento de este mtodo, pulsa aqu En el ejemplo hemos desarrollado un formulario para aadir registros a la tabla demo4 con las siguientes peculiaridades: Para los campos DNI, nombre y apellidos hemos utilizado input tipo texto y hemos recogido mediante la opcin name cada uno de los campos en una variable independiente. Para los campos Fecha de nacimiento y hora de nacimiento hemos utilizado tres opciones select en cada una de ellas. La finalidad de estas opciones no es otra que impedir la introduccin de fechas no vlidas (en realidad no lo impedimos totalmente ya que, tal como est confeccionado, podra introducirse 31 de febrero, o 31 de abril). Ese aspecto es mejorable, pero para hacerlo desde el propio formulario tendramos de recurrir a un lenguaje del lado del cliente (JavaScrpt por ejemplo).

Los valores de esos tres campos (tanto en fecha como en hora) los recogemos en variables que son elementos de dos array escalares. El campo sexo la recogemos en input tipo radio y les asignamos valores M F que coinciden con los valores del campo ENUM de la tabla. Con el campo Fumador -opcin Fumador/No fumador - hacemos exactamente lo mismo, pero asignndoles valores 1 o 0 ya que el formulario no permite la opcin NULL cadena vacia. En el script posterior ser cuando modifiquemos los valores de esas variables. Para el campo Idiomas utilizamos una opcin select de tipo mltiple y para los values un pequeo truco que describimos aqu la izquierda. Pues bien, aqu tienes, cdigo fuente del formulario que hemos diseado
Ver cdigo fuente

Aadir nuevo registro con datos del formulario


Como recordars, cuando se enva el contenido de un formulario mediante el method=POST y se indica como action un fichero PHPlos valores enviados son recogidos en este ltimo fichero en variables de PHP que tienen como nombre $_POST['var'] donde cada una de los ndices asociativos de los array (var) coinciden con los name de los diferentes campos del formulario. A partir de ah, bastara con depurar los valores recibos, recoger en variables los valores depurados e incluirlos en la sentencia MySQL INSERT -la hemos visto en la pgina anterior- para aadirlos a la tabla correspondiente. Aqu tienes comentados los scripts en ambas modalidades de programacin:
Ver codigo fuente mediante procesos Ver codigo fuente mediante objetos

En realidad, tal como habrs podido ver en el cdigo fuente, la depuracin ha sido la siguiente: Hemos creado un valor de fecha y hora en formatos MySQL vlidos de la forma que describimos un poco ms arriba. Hemos sumado todos los valores numricos recibidos en el array obtenido del SELECT MULTIPLE y hemos asignado el resultado a la variable depurada que recoge el valor a escribir en el campo Idiomas. La justificacin de esa suma la tienes al margen. La variable Fumador es la que tiene un poquito ms de complicacin. Vemosla con calma: Los valores que recibimos desde formulario son 1 o 0 y hemos de transformarlos en una cadena vaca o en NULL. Hemos insertado un operador condicional (un if... else) para convertir eso valores en: $var="'\N'" (comilla doble, comilla simple, barra invertida, N, comilla simple y comilla doble) $var="''" (comillas dobles, dos comillas simples y unas comillas dobles) Asignados los nuevos valores tenemos que recurrir a un pequeo truco. Venimos repitiendo que en la sentencia INSERT losnombres de las variables no numricas que contienen los values hay que escribirlos dentro de comillas simples, pero en el caso de un campo tipo CHAR(0) hemos de hacer una excepcin que sera no poner esas comillas al nombre de la variable. Al hacerlo as, se escribiran como valores en la sentencia de insercin uno de estos: ='\N' o =' ' (los valores de la variable) que al contenercomillas ya son interpretados por MySQL como una cadena.

Consultas simples y mltiples (MySQLi) Sintaxis MySQL de seleccin de registros


Las sentencias de seleccin de registros requieren utilizar entre otras palabras clave como las que enumeramos a continuacin. Observa que las hay dos tipos: obligatorias y opcionales. Observa tambin que algunas de las palabras clave son alternativas y por lo tanto, incompatibles en una misma sentencia. La insercin ha de hacerse respetando un orden tal y como se enumera aqu debajo. Si alterramos ese orden (p. ejemplo: colocando GROUP BY antes de WHERE) se producira un error y dejara de ejecutarse la sentencia. Los prrafos siguientes estn organizados a dos niveles. Las intrucciones del primero de ellas tienen carcter obligatorio en la sentencia de consulta. Las del segundo, sealadas con letra cursiva, son opcionales. SELECT Es la primera palabra de la sentencia de bsqueda y tiene carcter obligatorio.

SQL_BIG_RESULT Es una clusula opcional que se usa para indicar al optimizador que el resultado va a tener una gran cantidad de registros. En ese caso, MySQL utilizar tablas temporales cuando sea necesario para optimizar la velocidad de gestin de la informacin. Esta clusula tambin puede ser utilizada dentro de GROUP BY. SQL_BUFFER_RESULT Es opcional y su finalidad es la de forzar a MySQL a tratar el resultado en un fichero temporal. Ese tratamiento ayuda a MySQL a liberar recursos ms rpidamente y es de gran utilidad (siempre desde el punto de vista de la rapidez) cuando es necesario un largo proceso de clculo antes de enviar los resultados al cliente. HIGH_PRIORITY Esta clusula, opcional da prioridad al comando SELECT sobre otros comandos que simultneamente pudieran estar intentando acceder a la tabla para escribir en ella (aadir o modificar registros). Si esta opcin est activa, los intentos de escritura que pudieran producirse de forma simultnea deberan esperar al final de este proceso para ejecutarse. campo1, campo2, ... Tienen carcter obligatorio y sealan los campos de la tabla que deben incluirse en la consulta. La consulta slo devolver informacin de aquellos campos que estn enumerados aqu. Si se desea incluir a todos campos bastar con excribir * en esta posicin. En este caso *tiene la condicin de carcter comodn cuyo significado es todos los campos. Los campos numricos pueden llevar asociadas funciones MySQL que devuelven informacin estadstica. La sintaxis de algunas de esas funciones es la siguientes: MAX(campo) Devuelve el mayor de los valores de ese campo de entre todos los registros de la la consulta. Los registros comparados puedes ser todos o una parte de ellos. Si la sentencia incluye la condicin GROUP BY, en cuyo caso devolver el mximo de cada grupo y si incluye la opcin WHERE solo sern comparados los registros que cumplan tal condicin. MIN(campo) Idntica a la anterior en cuanto a criterios de seleccin, esta funcin devuelve el manorde los valores del campo en el mbito establecido por las evuntuales condiciones que pueda incluir la sentencia. AVG(campo) Devuelve el valor promedio de todos los registros numricos seleccionados con los mismos criterios del caso anterior. SUM(campo) Devuelve la suma de todos los valores del campo seleccionado y en el mbito establecido por los parmetros de la consulta. STDDEV(campo) Devuelve la estimacin de la desviacin tpica de la poblacin formada por los valores del campo. COUNT(campo) Cuenta los valores no nulos del campo indicado. Cuando se aplica una de estas funciones el resultado de la consulta contiene una sola lnea, salvo que se incluya opcinGROUP BY, en cuyo caso devolver tantas lneas como grupos resulten. FROM tabla Esta expresin indica a MySQL el nombre de la tabla en la que debe efectuarse la consulta. WHERE definicion Esta instruccin tiene carcter opcional y su utilidad es la de filtrar la consulta estableciendo los criterios de seleccin de losregistros que debe devolver. Si se omite WHERE, la consulta devolver todos los registros de la tabla. En la tabla de ejemplos tienes informacin sobre las formas de definir los criterios de seleccin de esta opcin. GROUP BY definicion Tiene carcter opcional y su finalidad es la de presentar los resultados de la consulta agrupados segn el criterio establecido en su definicin. Resulta de gran utilidad cuando se pretende obtener valores estadsticos de los registros quecumplen determinadas condiciones (las condiciones del agrupamiento). ORDER BY definicion Tambin tiene carcter opcional y su utilidad es la de presentar la informacin de la consulta ordenada por los contenidos de uno o varios campos. Siempre tiene como opcin complementaria de que en cada campo utilizado para la ordenacinpuede establecerse uno de estos criterios ASC (ascendente, es el valor por defecto) o DESC (descendente). Si no se establece ningn orden los resultados de la consulta aparecern en el mismo orden en el que fueron aadidos los registros. LIMIT m, n Esta clusula es opcional y permite establecer cuntos y cules registros han de presentarse en la salida de la consulta. Por ejemplo: LIMIT 4, 8 indicara a MySQL que la consulta debera mostrar OCHO registros contados a partir del quinto (s, el quinto porque LIMIT considera el primer registro como CERO). El criterio lmite se aplica sobre los resultados de la salida, es decir, sobre los resultados seleccionados, ordenados yfiltrados siguiendo los criterios establecidos por las clusulas anteriores. Si se escribe

como un solo parmetro (LIMIT k), MySQL lo interpretar como que k es el segundo de ellos y que el primero es CERO, es decir: LIMIT 0, k

Algunos ejemplos de consultas simples


Las consultas de los datos y registros contenidos en una tabla ofrecen un amplsimo abanico de posibilidades a partir de las opciones descritas anteriormente. Veamos algunas de las posibilidades.

La consulta ms simple
Si utilizamos la sentencia SELECT * FROM tabla

obtendremos informacin sobre todos los campos (*) y la salida estar en el mismo orden en el que fueron aadidos los datos. Si visualizas este ejemplo, vers que aparecen ordenados por el valor autonumrico del campo Contador lo cual, como ves, resulta coherente con la afirmacin anterior.
Consulta mediante procesos Ver cdigo fuente Consulta mediante objetos Ver cdigo fuente

Consultando slo algunos campos


Ahora utilizaremos la sentencia SELECT campo1,campo2, ... FROM tabla

y tendremos como resultado una lista completa, por el mismo orden que la anterior, pero slo mostrando los campos indicados.
Consulta mediante procesos Ver cdigo fuente Consulta mediante objetos Ver cdigo fuente

Consultando slo algunos campos y limitando la salida a n registros


Ahora utilizaremos la sentencia SELECT campo1,campo2, ... FROM tabla LIMIT (n, m)

y tendremos como resultado una lista que contendr m registros a partir del n+1, por el mismo orden que la anterior, y mostrando los campos indicados.
Consulta mediante procesos Ver cdigo fuente Consulta mediante objetos Ver cdigo fuente

Consultando slo algunos campos y ordenando la salida


Utilizaremos la sentencia MySQL de esta forma SELECT campo1,campo2, ... FROM tabla ORDER BY campo_n [ASC|DESC], campo_m [ASC|DESC]

y tendremos como resultado una lista ordenada por el primero de los campos indicados en ORDER BY, y en caso de coincidencia de valores en ese campo, utilizaramos el criterio de ordenacin sealado en segundo lugar.
Consulta mediante procesos Ver cdigo fuente Consulta mediante objetos Ver cdigo fuente

Consulta seleccionando registros


Utilizaremos la sentencia MySQL de esta forma SELECT campo1, ... FROM tabla WHERE condicin

que nos devolver la lista de registros que cumplen la condicin indicada. Aqu tienes un ejemplo muy sencillo.
Consulta mediante procesos Ver cdigo fuente Consulta mediante objetos Ver cdigo fuente

Los resultados de la sentencia SELECT


El manejo de los resultados obtenidos mediante mysqli_query o $objeto->query ofrece varias posibilidades. El bloque de informacin resultante de una consulta y recogido en $resultado est organizado en filas que pueden manejadas de diversas formas. Una primera informacin que puede resultar muy til e interesante es: $num_resultados=mysqli_num_rows($resultado) o $num_resultados=$resultado->num_rows En ambos casos la variables $num_resultados recoger el nmero de registros (filas) obtenidos como resultado de la consulta. La primera de las opciones se utiliza cuando se gestiona la consulta mediante procesos mientras que es segundo corresponde a consultas mediante objetos. Los valores contenidos en cada fila de los resultados pueden leerse mediante $array=mysqli_fetch_row($resultado) o $array=$resultado->fetch_row()

dnde $array es un array escalar que contiene los valores del registro actual (aquel que seala el puntero interno). Los ndices de este array van asociados al orden en el que estn escritos los nombres de los campos dentro de la sentencia select. Si no se indica otra cosa el puntero comienza un recorrido por el primer registro del resultado (fila 0) y en las sucedsivas llamadas a mtodo fetch_row se va desplazando a la siguiente fila. Por eso, mediante un bucle while podemos recorriendo los diferentes registros del resultado y convirtiendo cada uno de ellos en un array escalar. Aqu tienes un ejemplo
Consulta mediante procesos Ver cdigo fuente Consulta mediante objetos Ver cdigo fuente

Los valores contenidos en cada fila de los resultados tambin pueden leerse mediante

$array=mysqli_fetch_assoc($resultado) o $array=$resultado->fetch_assoc()

dnde $array es un array asociativo que contiene los valores del registro actual (aquel que seala el puntero interno). Los ndices de este array son los nombres de los campos dentro de la sentencia select. Si no se indica otra cosa el puntero comienza un recorrido por el primer registro del resultado (fila 0) y en las sucedsivas llamadas a mtodo fetch_assoc se va desplazando a la siguiente fila. Por eso, mediante un bucle while podemos recorriendo los diferentes registros del resultado y convirtiendo cada uno de ellos en un array asociativo. Aqu tienes un ejemplo
Consulta mediante procesos Ver cdigo fuente Consulta mediante objetos Ver cdigo fuente

Una tercera opcin para ir leyendo los valores contenidos en cada fila de los resultados es la que utiliza $objeto=mysqli_fetch_object($resultado) o $objeto=$resultado->fetch_object()

dnde $objeto es un objeto cuyas propiedades son los nombres de los campos incluidos en la sentencia select y el valor el resultante de la consulta para ese campo en la fila actual (aquella a la que apunta el puntero interno). Si no se indica otra cosa el puntero comienza un recorrido por el primer registro del resultado (fila 0) y en las sucesivas llamadas a mtodo fetch_object se va desplazando a la siguiente fila. Por eso, mediante un bucle while podemos recorriendo los diferentes registros del resultado y convirtiendo cada uno de ellos en un objeto con las propiedades descritas. Aqu tienes un ejemplo
Consulta mediante procesos Ver cdigo fuente Consulta mediante objetos Ver cdigo fuente

En esta nueva opcin se realiza un lectura nica del contenido de todas las filas $array_bidimensional=mysqli_fetch_all($resultado) o $array_bidimensional=$resultado->fetch_all()

dnde $array_bidimensional es un array cuyo primer ndice coincide con el nmero de orden (empezando por cero) de cada una de las filas del resultado y cuyo segundo ndice es el nmero de columna entendiendo como tales cada uno de los campos incluidos en la sentencia SELECT por el orden de inclusin enla misma y contados a partir de cero. La extraccin de los diferentes valores requerira un doble bucle de lectura. El primero nos ira posicionando en cada una de las filas del resultado (el primer ndice) y el segundo bucle recorrera todos de aquella fila. Aqu tienes un ejemplo
Consulta mediante procesos Ver cdigo fuente Consulta mediante objetos Ver cdigo fuente

Hay situaciones en las que puede resultarnos de inters conocer nicamente los valores de alguno o algunos de los registros incluidos en el resultado de una consulta. Puede, por ejemplo, que nos interese conocer el nicamente el primer registro (o el ltimo, o el que ocupa la posicin 38) tal como aparecen en el resultado de la ejecucin de la funcin mysqli_query o del mtodo query() si se trata de objetos. Tanto la funcin mysql_fech_row() como el mtodo fetch_row() extreaen aquel registro (fila de datos) al que seala el apuntador. Para posicionar de forma arbitrarie el apuntador de resgistros mysqli dispone las siguientes funciones:

mysqli_data_seek($resultado, posicion)

dnde $resultado es el objeto resultante de una consulta realizada por medio de la funcin mysqli_query() y posicin es un nmero entero que explicita la posicin (la prima posicin se identifica mediante cero) a la que pretendemos orientar el apuntador de lectura demysqli_fetch_row. El proceso podra ser similar a este: $resultado=mysqli_query($identificador,sentencia_MySQL); // realiza la consulta y recoge el resultado en la variable $resultado mysqli_data_seek($resultado,posicion); //Sita el apuntador en la fila sealada por posicin $fila=mysqli_fetch_row($resultado); //Lee el registro (fila) que seala en apuntador anterior y recogiendo el resultado en el array $fila

Cuando se trata de que la programacin est orientada a objetos el mtodo que debemos utilizar es el siguiente: $resultado->data_seek(posicion)

dnde $resultado es el objeto resultante de una consulta realizada por medio del mtodo $objeto->query() y posicin es un nmero entero que explicita la posicin (la prima posicin se identifica mediante cero) a la que pretendemos orientar el apuntador de lectura que usar el posterior mtoco fetch_row. El proceso podra ser similar a este: $resultado=$objeto->query(sentencia_MySQL); // el mtodo query realiza la consulta y recoge el resultado en el nuevo objeto $resultado $resultado->data_seek(posicion); //Sita el apuntador en la fila sealada por posicin $fila=$resultado->fetch_row(); //Lee el registro (fila) que seala en apuntador anterior y recogiendo el resultado en el array $fila

Como es lgico tambin pueden usuarse fetch_object fetch_assoc en lugar del fetch_row del pseudocdigo anterior.

Consultas condicionadas
La clasula WHERE permite un variado abanico de condiciones, que trataremos de resumir aqu. Algunos de ellas son los siguientes:
Programacin Progamacin por orientada a procesos objetos Cdigo Ver Cdigo fuente ejemplo fuente Selecciona los registros que contienen en el campo un valor igual a num Selecciona los registros que contienen en el campo una cadena idntica a cadena(*) Selecciona los registros que contienen en el campo un valor menor a num Selecciona los registros que contienen en el campo una cadena cuyos n primeros caracteres son menores que los de la cadena, siendo n el nmero de caracteres que contiene cadena. (**) Selecciona los registros que contienen en el campo un valor menor O igual a num Ver Ver Ver Probar Probar Probar Ver Ver Ver Ver ejemplo Probar Probar Probar

Operador

Tipo Sintaxis de campo

Descripcin

= = < < <=

Numrico WHEREcampo=num Cadena WHEREcampo="cadena"

Numrico WHEREcampo<num

Cadena

WHEREcampo<"cadena"

Ver

Probar

Ver

Probar

Numrico WHEREcampo<=num

Ver

Probar

Ver

Probar

<=

Cadena

WHEREcampo<="cadena"

Selecciona los registros que contienen en el campo una cadena cuyos n primeros caracteres son menores que los de la cadena, siendo n el nmero de caracteres que Ver contiene cadena y aade respecto al caso anterior la opcin de que en caso de que ambos valores fueran iguales tambin los presentara (**) Selecciona los registros que contienen en el campo un valor mayor a num Selecciona los registros que contienen en el campo una cadena cuyos n primeros caracteres son mayores que los de la cadena, siendo n el nmero de caracteres que contiene cadena. (**) Ver

Probar

Ver

Probar

> >

Numrico WHEREcampo>num

Probar

Ver

Probar

Cadena

WHEREcampo>"cadena"

Ver

Probar

Ver

Probar

>=

Numrico WHEREcampo>=num

Selecciona los registros que contienen en el campo un valor mayor o igual a num

Ver

Probar

Ver

Probar

>=

Cadena

WHEREcampo>="cadena"

Selecciona los registros que contienen en el campo una cadena cuyos n primeros caracteres son mayores que los de la cadena, siendo n el nmero de caracteres que Ver contiene cadena y aade respecto al caso anterior la opcin de que en caso de que ambos valores fueran iguales tambin los presentara (**) Selecciona los registros que contienen en el campo valores que coinciden con alguno de los especificados dentro del parntesis. Cuando se trata de valores no numricoz han de ir entre comillas Ver

Probar

Ver

Probar

IN

Numrico WHERE campoIN o (valor1,valor2..) Cadena

Probar

Ver

Probar

Numrico

BETWEEN o
Cadena

WHERE campoBETWEEN valor1 AND valor2

Selecciona los registros en los que los valores contenidos en el camposeleccionado estn comprendidos en el intervalo valor1 (mnimo) valor2(mximo) incluyendo en la seleccin ambos extremos. Ver Cuando los contenidos de los campos son cadenas sigue los mismos criterios que se indican para los dems operadores de comparacin Selecciona los registros en los que los valores contenidos en el camposeleccionado son NULOS Selecciona los registros en los que los valores contenidos en el camposeleccionado son NO NULOS Ver Ver

Probar

Ver

Probar

IS NULL IS NOT NULL

Cadena Cadena

WHERE campo IS NULL WHERE campo IS NOT NULL

Probar Probar

Ver Ver

Probar Probar

(*) Cuando se trata de cadenas de caracteres, el concepto menor que significa anterior en la ordenacin de los caracteres segn su cdigo ASCII y mayor quesignifica posterior en esa misma ordenacin. (**) La discriminacin de Maysculas/Minsculas depender del tipo de campo. Recuerda que los tipo BLOB hacen esa discriminacin, mientras que los de tipo TEXT son insensibles a Maysculas/Minsculas.

Cuando se trata de comparar cadenas MySQL dispone de una potente instruccin (LIKE) que permite establecer los criterios de seleccin a toda o parte de la cadena. Su sintaxis contempla distintas posibilidades utilizando dos comodines>: % (que se comporta de forma similar al (*) en las bsquedas de Windows) y _ (de comportamiento similar a (?) en Windows). Aqu tienes algunas de sus posibilidades:
Progamacin por procesos Cdigo fuente Ver Ver Ver Ver Ver ejemplo Probar Probar Probar Probar Programacin orientada a objetos Cdigo fuente Ver Ver Ver Ver Ver ejemplo Probar Probar Probar Probar

Sintaxis

Descripcin

WHERE campoLIKE '%cadena%' WHERE campoLIKE 'cadena%' WHERE campoLIKE '%cadena' WHERE campoLIKE '_cadena%'

Selecciona todos los registros que contengan la cadena en el campo indicado sea cual fuere su posicin Selecciona todos los registros en los que el campo indicado que contengan la cadena exactamente alprincipio del campo Selecciona todos los registros en los que el campo indicado que contengan la cadena exactamente al final del campo Selecciona todos los registros en los que el primer caracter del campo puede ser cualquiera pero los siguientes han de ser exactamente los indicados en cadena pudiendo ir seguidos de cualesquiera otros caracteres

El comodn (_) puede ir tanto al principio como al final y puede repetirse tantas veces como sea necesario. Por tanto sera correctoLIKE '___es%' y tambin LIKE 'a___es%' as como: LIKE '%a___es'. La clasula WHERE aun tiene ms opciones. Acepta mltiples condiciones vinculadas por los operadores lgicos AND, OR, NOT o sus sintaxis equivalentes: &&, || y !. El comportamiento de estos operadores es idntico al descrito para sus homnimos de PHP en esta pgina

Utilizando funciones sobre campos


Por medio de la sintaxis

SELECT MAX(campo1), MIN (campo2), ... FROM tabla

obtendramos UNA SOLA FILA cuyos valores seran los resultados de la aplicacin de las funciones a todos los registros del campo indicado. Aqu tienes un ejemplo que determina todos los valores de esos estadsticos aplicados al campo Contador de nuestra tabla demo4.
Consulta mediante procesos Ver cdigo fuente Consulta mediante objetos Ver cdigo fuente

Aplicando la opcin GROUP BY


Tal como sealamos al margen, las funciones anteriores pueden aplicarse a grupos de registros seleccionados mediante un criterioGROUP BY (nombre del campo) En este ejemplo obtendremos los mismos parmetros estadsticos que en el anterior, pero ahora agrupados por sexo, lo que significara que obtendremos dos filas de resultados. Aqu tienes el ejemplo
Consulta mediante procesos Ver cdigo fuente Consulta mediante objetos Ver cdigo fuente

<

Manejo de fechas en las consultas


MySQL dispone de algunas clusulas de gestin de fechas que pueden tener una gran utilidad a la hora de gestionar consultas. Son las siguientes: DATE_FORMAT( campo,formato)

Las diferentes opciones de formato las tienes en la tabla. Es importante tener en cuenta que la sintaxis correcta es %Y (sin espacio) ya que si hubiera un espacio % Y interpretara la letra Y como un texto a incluir. CURDATE()

Dentro de DATE_FORMAT se puede incluir -en vez del nombre del campo- una cadena en la que se indique una fecha en formatoYYYY-MM-DD hh:mm:ss. Puedes verlo en los ejemplos. De igual modo es posible sustituir el nombre del campo -o la cadena- por la funcinCURDATE() que recoge la fecha actual del sistema (nicamente da, mes y ao). A efectos de horas, minutos y segundos CURDATE() va a tomar el medioda de la fecha actual. CURTIME()

Se comporta de forma similar a CURDATE(). Devuelve la hora actual del sistema que alberga el servidor MySQL en formato hh:mm:ss CURRENT_TIMESTAMP()

Se comporta de forma similar a CURDATE(). Devuelve la fecha y hora actual del sistema en formato YYYY-MM-DD hh:mm:ss NOW()

Es un alias de CURRENT_TIMESTAMP().

Formato

Descripcin

Sentencia MySQL

Progamacin por procesos Cdigo fuente Ver Ver Ver Ver Ver Ver Ver Ver Ver Ver Ver Ver Ver Ver Ver ejemplo Probar Probar Probar Probar Probar Probar Probar Probar Probar Probar Probar Probar Probar Probar

Programacin orientada a objetos Cdigo fuente Ver Ver Ver Ver Ver Ver Ver Ver Ver Ver Ver Ver Ver Ver Ver ejemplo Probar Probar Probar Probar Probar Probar Probar Probar Probar Probar Probar Probar Probar Probar

%d %e %D %m %c %M %b %y %Y %w %W %W %j %U %u

Da del mes en formato de dos dgitos Da del mes en formato de uno dos dgitos Nmero de da seguido del sufijo en ingls Nmero del mes en formato de dos dgitos Nmero del mes en formato de uno o dos dgitos Nombre del mes (en ingls) Nombre del mes abreviado (en ingls) Nmero del ao en formato de dos dgitos

DATE_FORMAT(Nacimiento,'%d') DATE_FORMAT(Nacimiento,'%e') DATE_FORMAT(Nacimiento,'%D') DATE_FORMAT(Nacimiento,'%m') DATE_FORMAT(Nacimiento,'%c') DATE_FORMAT(Nacimiento,'%M') DATE_FORMAT(Nacimiento,'%b') DATE_FORMAT(Nacimiento,'%y')

Nmero del ao en formato de cuatro dgitos DATE_FORMAT(Nacimiento,'%Y') Nmero de da de la semana 0=Domingo ... 6=Sbado Nombre del da de la semana (en ingls) Nombre abreviado del da de la semana (en ingls) Nmero de da del ao en formato de 3 dgitos Nmero de semana del ao considerando el DOMINGO como primer da de la semana (dos dgitos) Nmero de semana del ao considerando el LUNES como primer da de la semana (dos dgitos)

DATE_FORMAT(Nacimiento,'%w') DATE_FORMAT(Nacimiento,'%W') DATE_FORMAT(Nacimiento,'%W') DATE_FORMAT(Nacimiento,'%j') DATE_FORMAT(Nacimiento,'%U') DATE_FORMAT(Nacimiento,'%u')

Ver

Probar

Ver

Probar

La fecha para los ejemplos siguientes la extraemos de una variable del tipo: $fecha="2005-10-12 14:23:42" ya que la tabla no contiene campos de fecha que incluyan horas, minutos y segundos %H %k %h %I %i %s %r %T % texto %p
Hora con dos dgitos (formato 0 a 24 horas) Hora con uno dos dgitos (formato 0 a 24 horas) Hora con dos dgitos (formato 0 a 12 horas) Hora con uno dos dgitos (formato 0 a 12 horas) Minutos con dos dgitos Segundos con dos dgitos

DATE_FORMAT($fecha,'%H') DATE_FORMAT($fecha,'%k') DATE_FORMAT($fecha,'%h') DATE_FORMAT($fecha,'%I') DATE_FORMAT($fecha,'%i') DATE_FORMAT($fecha,'%s')


Ver Probar Ver Probar

Hora completa (HH:mm:ss) en formato de 12 DATE_FORMAT($fecha,'%r') horas indicando AM PM Hora completa (HH:mm:ss) en formato de 24 DATE_FORMAT($fecha,'%T') horas Incluye el texto que se indica detrs del % Aade AM PM dependiendo de la Hora

DATE_FORMAT($fecha,'% texto') DATE_FORMAT($fecha,'%p')

Se pueden combinar a voluntad varias opciones utilizando una sintaxis de este tipo: '% Hoy es: %d - %m - %Y % es %W % estamos en el mes de %M % <br>y van transcurridos %j % dias de este ao.<br>Son las %r'

Setencias mltiples
Cuando usamos mysqli podemos ejecutar mltiples sentencias en una sola instruccin. Para ello debemos empezar encadenando las sucesivas sentencias incluyndolas una a continuacin de otra y separndolas mediante un punto y coma (;). SELECT * FROM tabla1 ; SELECT campo1 FROM tabla2 ; DROP TABLE IF EXISTS tabla3

La ejecucin de este tipo de sentencias requiere la utilizacin de la funcin: mysqli_multi_query($conexion,sentencia_multiple)

dnde, en el caso de programacin mediante procesos, $conexion es el identificador de la conexin y sentencia_multiple el una sentencia mltiple en el formato comentado en el prrafo anterior. Devuelve un valor booleano (true o false). Cuando se trata de programacin orientada a objetos es preciso recurrir al mtodo multi_query que mediante la sintaxis: $objeto->multi_query(sentencia_multiple) en la que sentencia_multiple es una sentencia mltiple en el formato comentado anteriormente. Devuelve un valor booleano (true o false).

Cuidado! Los mensajes de error slo se visualizan en le caso de producirse este en la ejecucin de la primera de las sentencias

Sentencias que no devuelven valores


Cuando se trata de crear, borrar o modificar tablas, lo habitual es que se realice el proceso sin necesidad de visualizar ningn resultado. Esos casos, aparentemente los ms simples, podran tratarse mediante de la forma que puedes ver en el cdigo fuente de estos dos ejemplos de creacin de tres tablas.
Cdigo fuente mediante procesos Cdigo fuente mediante objetos

Pese a incluir un condicional para advertirnos de eventuales errores solo se activara el mensaje de error en el caso de que este se produjese en la primera de las sentencias.

Sentencias que devuelven valores


Cuando se trata de sentencias que devuelven valores como ocurre con las consultas es necesario utilizar algunas de las funciones o mtodos que comentamos a continuacin $resultado=mysqli_store_result($conexion) o $resultado=$objeto->store_result()

Transfiere a $resultado el conjunto de resultados de la ltima consulta en la conexin de base de datos. En el primer caso (usando procesos) se requiere el parmetro $conexion. En el segundo supuesto (orientado a objetos) el mtodo no requiere ningn parmetro. $resultado=mysqli_use_result($conexion) o $resultado=$objeto->use_result()

Se utiliza para iniciar la recuperacin de un conjunto de resultados de la ltima consulta ejecutada. Aunque a primera vista pueda parecer muy similar a lo anterior hay una importantsima diferencia dado que no se transfiere el conjunto completo de resultados y por lo tanto no se pueden utilizar funciones como mysqli_data_seek () para pasar a un registro en particular dentro del conjunto. Cuando cualquiera de las opciones (store o use) se ejecuta inmediatamente despus de la ejecucin de un multi_query recoger los resultado de la primera de las sentencias que contiene. mysqli_free_result($resultado) o $resultado->free()

Liberan la memoria ocupada por los resultados. Como en casos anteriores la primera sentencia se utiliza cuando se programa por procesos y la segunda cuando se hace por objetos. No es estrictamente necesario utilizarlos dado que toda la memoria utilizada por los resultados asociados se libera automticamente al finalizar la ejecucin del script. Slo tiene utilidad prctica en aquellos casos en los que las consultas devuelven una cantidad de datos muy grande. mysqli_more_results($conexion) o $objeto->more_results() Comprueba si hay algn resultado ms de una consulta mltiple. Devuelve un valor booleano mysqli_next_result($conexion) o $objeto->next_result() Prepara siguiente conjunto de resultados de una llamada previa a mysqli_multi_query (), que pueden ser recuperados por mysqli_store_result () o mysqli_use_result ().
Consulta mediante procesos Consulta mediante procesos Ver cdigo fuente Ver cdigo fuente Consulta mediante objetos Consulta mediante objetos Ver cdigo fuente Ver cdigo fuente

Creacin de tablas a partir de la consulta de otra tabla


Es frecuente -podra decirse que es lo habitual- relacionar tablas mediante campos con idntico contenido. Supongamos que entre los individuos de nuestra tabla demo4 se pretende establecer un proceso de seleccin para elegir entre ellos un nmero determinado deastronautas, pongamos por caso. Supongamos tambin, que la seleccin va a constar de tres pruebas que sern juzgadas y calificadas por tres tribunales distintos. Una primera opcin sera crear tres tablas una para cada tribunal e incluir en ellas todos los datos de cada uno de los individuos. Esa opcin es factible pero no es ni la ms cmoda, ni tampoco es la ms rpida ni la que menos espacio de almacenamiento necesita. No debemos olvidar que una tabla puede tener una enorme cantidad de registros. Una opcin alternativa sera crear tres nuevas tablas que slo contuvieran dos campos cada una. Por ejemplo el campo DNI y el campo Calificacin. Como quiera que el campo DNI ha de contener los mismos valores en las cuatro tablas y adems es un campo nicopodran crearse las nuevas tablas y luego copiar en cada una de ellas todos los DNI de la tabla original. Nos garantizara que no habra errores en los DNI y adems nos garantizara que se incluyeran todos los aspirantes en esas nuevas tablas. Aqu tienes el cdigo fuente de un script que crea esas tres tablas (a las que hemos llamado demodat1, demodat2 y demodat3). Como podrs observar hemos utilizado una sentencia mltiple para crear las tablas y posteriormente hemos hecho las inserciones de datos en cada una de ellas.
Cdigo fuente mediante procesos Cdigo fuente mediante objetos

Una consulta conjunta de varias tablas


MySQL permite realizar consultas simultneas en registros situados en varias tablas. Para ese menester se usa la siguiente sintaxis:

SELECT tabla1.campo1, tabla2.campo2, ... FROM tabla1, tabla2

en la que, como ves, modificamos ligeramente la sintaxis ya que anteponemos el nombre de la tabla al del campo correspondiente separando ambos nombres por un punto, con lo cual no hay posibilidad de error de identificacin del campo incluso cuando campos de distinta tabla tengan el mismo nombre. Otra innovacin -respecto a los ejemplos anteriores- es que detrs de la clusula FROM escribimos los nombres de todas las tablas que est usando SELECT. A partir de ah se pueden establecer todo tipo de relaciones para las sentencias WHERE, ORDER BY y GROUP BY utilizando para ellocampos de cualquiera de las tablas sin otra particularidad ms que poner cuidado al aludir a los campos utilizando siempre la sintaxisnombre_tabla.nombre_campo. A modo de ejemplo hemos procurado comentarlo lnea a lnea aqu tienes un script PHP que hace una consulta conjunta de las tablasdemo4, demodat1, demodat2 y demodat3 y nos presenta una tabla con los datos personales y las puntuaciones de las tres pruebas as como las suma de puntos de las tres y, adems, ordena los resultados -de mayor a menor- segn la suma de las tres puntuaciones.
Consulta mediante procesos Ver cdigo fuente Consulta mediante objetos Ver cdigo fuente

Consultas preparadas (MySQLi) Declaraciones preparadas (Prepare statement)


Mediante MySQLi disponemos de una nueva alternativa de consultas que conviene conocer. Requiere realizar el proceso de consulta en los dos pasos siguientes: $actuacion=mysqli_prepare($conexion,SENTENCIA) o $actuacion= $objeto->prepare(SENTENCIA)

El mtodo prepare prepara la SENTENCIA para su ejecucin devolviendo el resultado como un objeto $actuacion. Este mtodo no ejecuta la sentencia, solo la prepara. mysqli_stmt_execute($actuacion) o $actuacion-> execute()

El mtodo execute es propio de los objetos resultantes $actuacion de la preparacin una sentencia. Devuelve el objeto resultado de la ejecucin de esa sentencia. Este objeto permite extraer los resultados mediante: $resultado=mysqli_stmt_get_result($actuacion) o $resultado=$actuacion->get_result()

El mtodo get_result() cuando se trata de objetos o su equivalente mysqli_stmt_get_result producen un bloque de informacin idntico al que se podra obtener mediante el mtodo query o su equivalente mysqli_query. Por tanto es susceptible de ser leido mediante cualquiera de los procedimientos comentados en el epgrafe Los resultados de la sentencia SELECT de la pgina anterior. Aqu tienes un ejemplo en ambas versiones.
Consulta mediante procesos Ver cdigo fuente Consulta mediante objetos Ver cdigo fuente

Existe una opcin alternativa de lectura del objeto resultante de la ejecucin del mtodo execute. Se trata de utilizar una de las siguientes funciones: mysqli_stmt_bind_result($actuacion, $var1, $var2, $var3, ...) o $actuacion->bind_result($var1, $var2, $var3, ...)

dnde $actuacion es el nombre del objeto resultante del mtodo execute (o de mysqli_execute) $var1, $var2, $var3,.. son nombres vlidos cualesquiera de variables PHP a travs de las que se vincularn los campos de la consulta. Han de crearse obligatoriamente tantas variables como campos intervengan en la consulta. Las funciones anteriores organizan los resultados de la consulta por registros (filas) que pueden ser leidas secuencialmente de una en una y a travs de llamadas reiterativas por medio de una de estas funciones: mysqli_stmt_fetch($actuacion) o $actuacion->fetch() que irn asignando a las variables $var1, $var2, $var3,.. los valores de los campos correspondientes al registro contenido en la fila actual. La lectura comienza por el primer registro resultante de la consulta y contina secuencialmente (la lectura completa requiere la realizacin de un bucle tal como puedes ver en los ejemplos) en las sucesivas llamadas a estas funciones. Como es obvio, en cada iteracin se modificarn los valores de las variables $var1, $var2, $var3,... Las pginas oficiales de PHP justifican la utilizacin de este procedimiento cuando se trate de ahorrar recursos de memoria (el resultado de la consulta no es almacenado en ningn buffer) y, a la vez, admiten una mayor lentitud en el procesamiento de la informacin
Consulta mediante procesos Ver cdigo fuente Consulta mediante objetos Ver cdigo fuente

A la sintaxis ya conocida: $actuacion= $objeto->prepare(SENTENCIA) $actuacion-> execute()

puede hacrsele una modificacin incluyendo entre ambas un nuevo mtodo (bind_param) que tiene como finalidad enlazar el valor de una variable con un identificador incluido en la sentencia SQL. Una sintaxis como esta: $actuacion=mysqli_prepare($conexion,'SELECT * FROM tabla WHERE (Nombre=? and Apellido1=? and edad=?)') mysqli_stmt_bind_param($actuacion,'ssi', $var1, $var2, $var3); $var1='Jose'; $var2='Alonso'; $var3=25; mysqli_stmt_execute($actuacion) o $actuacion= $objeto->prepare('SELECT * FROM tabla WHERE (Nombre=? and Apellido1=? and edad=?)') $actuacion-> bind_param('ssi', $var1, $var2, $var3); $var1='Jose'; $var2='Alonso'; $var3=25; $actuacion-> execute()

en la que hacemos las siguientes modificaciones: En la sentencia SQL sustituimos por ? lo que anteriormente eran cadenas o nombres de variables (entre comillas por su condicin de cadenas alfanumricas) del tipo '$nombre' y '$apellido' y nmeros o variables del tipo $edad (sin comillas por su condicin de valor numrico). Agregamos una llamada al mtodo bind_param con los siguientes parmetros obligatorios:

El primero de ellos es una cadena formada por identificadores de tipo de los valores que habrn de reemplazar a los signos de interrogacin. Los identificadores de tipo (la cadena debe incluir tantos como signos de interrogacin contenga la sentencia MySQL) son los siguientes: i La variable es de tipo entero d La variable es numrica double s La variable es de tipo cadena b La variable es de tipo blob Los sealados como $var1, $var2, $var3, etctera son los nombres de las variables que habrn de estar definidas antes de invocar el mtodo execute y que contienen los valores que ha de sustituir a los sucesivos ? de la sentencia. Hemos de tener en cuenta que han de incluirse siempre tantos nombres de variable como interrogantes existan en la sentencia. El mtodo execute producira los resultados de la ejecucin de la sentencia despus de haber reemplazado los ? por los valores de la variable. Veamos un primer ejemplo en el que las variables son de tipo numrico
Consulta mediante procesos Ver cdigo fuente Consulta mediante objetos Ver cdigo fuente

En este otro ejemplo ya hemos incluido variables tanto numricas como cadena y dnde conjugamos el uso de bind_param con el de bind_result.
Consulta mediante procesos Ver cdigo fuente Consulta mediante objetos Ver cdigo fuente

Modificar registros (MySQLi) Sintaxis MySQL de modificacin de registros


Las sentencias MySQL que permiten la modificacin de registros en las tablas son idnticas a ls ya comentadas con anterioridad y tal como decamos entonces pueden incluir algunas de las siguientes clusulas que, al igual que ocurra en casos anteriores, pueden tener categora de obligatorias u opcionales. El orden en que deben estar indicadas ha de seguir la misma secuencia en la que estn descritas aqu. UPDATE Tiene carcter obligatorio, debe ser la primera palabra de la sentencia e indica a MySQL que vamos realizar una modificacin. LOW_PRIORITY Es opcional e indica a MySQL espere a que se terminen de hacer las consultas que en ese momento pudiera haber en proceso antes realizar la actualizacin. IGNORE Es opcional. Cuando se incluye en una sentencia el proceso de actualizacin no se interrumpe si aparece un conflicto de clave duplicada en uno de los registros en proceso. Simplemente ignora ese registro y contina con los siguientes Si no se incluye, el proceso de modificacin se interrumpe en el momento en que encuentre un conflicto de clave duplicada. Tanto con ignore como sin esa clusula, en el caso de duplicidad de clave NUNCA se efectan las modificaciones. tabla Es obligatoria y contiene el nombre de la tabla que pretendemos modificar. SET Tiene carcter obligatorio y debe estar delante de las definiciones de campo y valor. campo1 = valor1 Es obligatoria al menos una definicin. Indica el nombre del campo a modificar (campo1) y el valor que se asignar a ese campo. Si se pretende modificar ms de un campo se repetir esta definicin tantas veces como sea necesario, separando cada una de ellas por una coma. WHERE Es un campo opcional y su comportamiento es idntico al sealado al mencionar el proceso de consultas.

ORDER BY Tiene idntica funcionalidad a la descrita al referirnos a consultas

Modificar un campo en todos los registros de una tabla


La sentencia MySQL, que permite modificar uno o varios campos en todos los registros de una tabla, es la siguiente: UPDATE tabla SET campo1=valor1, campo2=valor2

Cuidado! Hay que tener muy presente que con esta sentencia en la que no aparece WHERE se modificarn TODOS LOS REGISTROS DE LA TABLA y por lo tanto los campos modificados tendrn el mismo valor en todos los registros.

Algunas consideraciones sobre la sintaxis


Siempre que manejes PHP y MySQL debes tener muy presente lo siguiente: MySQL requiere SIEMPRE que los valores tipo cadena que incluyen campos de fecha vayan entre comillas. Por el contrario, losnumricos no deben llevar comillas. Presta mucha atencin a esto cuando escribas los valores directamente en la sentencia MySQL. Cuando pases valores desde una variable PHP debes tener muy en cuenta las consideraciones anteriores y si el contenido de la variable es una cadena que va a ser tratada como tal por MySQL tienes dos opciones para evitar el error: Definir la variable as: $variable ="'valor'" (comillas dobles, comilla simple al principio y comilla simple, comilla doble al final) y poner en la sentencia MySQL el nombre de la variable sin entrecomillar, o Definir la variable PHP as: $variable ="valor" y al escribir el nombre de esa variable en la sentencia MySQL escribirlo entre comillas sencillas, es decir, as: '$variable' No pienses que es caprichoso el orden que hemos puesto en las comillas. Recuerda que al llamar a la sentencia MySQL, el contenido de la sentencia va entre comillas (que por costumbre son comillas dobles, por esa razn todo entrecomillado que vaya dentro de esa sentencia ha de usar comillas simples para evitar un error seguro). De ah que al definir una variable PHP en la forma $variable ="'valor'" las comillas dobles exteriores indican a PHP que se trata de una cadena, por lo que, al pasar la variable a MySQL ste recibir el contenido de la cadena que es, logicamente: 'valor' y en este caso las comillas forman parte del valor, razn por el que no es necesario escribir -en la sentencia MySQL- el nombre de la variable entrecomillado. En este primer ejemplo, hemos incluido una actualizacin de tablas que pondr puntuacin 7 en la primera de las pruebas a todos losaspirantes a astronautas de nuestro ejemplo. Es un caso de actualizacin sin la condicin WHERE y tiene el cdigo comentado.
Consulta mediante procesos Ver cdigo fuente Consulta mediante objetos Ver cdigo fuente

Recuento de resultados
El recuento de los resultados de la ejecucin de una sentencia tiene dos opciones que dependen del tipo de esta. Cuando se trata de sentencias que no producen modificacin en los contenidos (caso de las consultas) el recuento de resultados utiliza las funciones y sintaxis ya conocidas de $num_resultados=mysqli_num_rows($resultado) o $num_resultados=$resultado->num_rows En ambos casos la variables $num_resultados recoger el nmero de registros (filas) obtenidos como resultado de la consulta. La primera de las opciones se utiliza cuando se gestiona la consulta mediante procesos mientras que es segundo corresponde a consultas mediante objetos.

Cuando se trata de sentencias que s producen modificacin en los contenidos (altas, modificaciones o borrado de registros) el recuento de resultados requiere de esta sintaxis: $cuenta_resultados=mysqli_affected_rows($conexion) o $cuenta_resultados=$objetoMySQLi->affected_rows En el primer caso programacin mediante procesos se utiliza la funcin mysqli_affected_rows con el parmetro identificador de conexin: $conexion En el segundo supuesto programacin orientada a objetos se utiliza la propiedad affected_rows que es la que contiene el valor de ese resultado.

Seleccin y modificacin de un solo registro


Es una de las opciones ms habituales. Es el caso en el que mediante un formulario asignamos una condicin a WHERE y simultneamente asignamos los nuevos valor del campo o campos elegidos. Requiere la siguiente sintaxis: UPDATE tabla SET campo1=valor1, campo2=valor2 WHERE condicin

La condicin es fundamental en esta opcin y normalmente aludir a un campo ndice (clave principal o nica), de modo que sea un solo registro el que cumpla la condicin. Podra ser el caso, en nuestro ejemplo, del campo DNI que por su unicidad garantizara que la modificacin solamente va a afectar a uno solo de los registros. El ejemplo siguiente nos permitir hacer modificaciones de este tipo en la tabla deomodat2. Observa el cdigo fuente y vers que mediante un simple recurso JavaScript, el script que realiza la modificacin nos reenva al formulario con un mensaje de confirmacin de la modificacin. En este primer caso utilizaremos las instrucciones de modificacin mediante procesos
Ejecutar la modificaccin Ver cdigo formulario Ver cdigo script

Aqu tienes el mismo ejemplo del supuesto anterior modificando a programacin mediante objetos el tratamientos de las instrucciones de gestin de la base de datos
Ejecutar la modificaccin Ver cdigo formulario Ver cdigo script

Modificacin simltanea de un campo en cualquiera de los registros


Aqu tienes un ejemplo que permite visualizar el valor actual de todas las puntuaciones de la prueba 2 de los astronautas as como sus nombres y apellidos y DNI y en la cual se pueden modificar ninguno, uno, varios o todos los valores y posteriormente actualizarlos todos con los nuevos valores. Igual que en el caso anterior, en este primer ejemplo efectuaremos las modificaciones tratando mysqli mediante procesos mientra que en el segundo supuesto lo hacemos mediante programacin orientada a objetos.
Ejecutar la modificaccin Ejecutar la modificaccin Ver cdigo formulario Ver cdigo formulario Ver cdigo script Ver cdigo script

Imgenes en tablas (MySQLi) Imgenes en tablas


Peculiaridades de las tablas
Las tablas que han de contener imgenes deben tener campos del tipo BLOB, MEDIUMBLOB o LONGBLOB, (recuerda sus tipos) pudiendo elegir aquel de ellos que ms se adecue al tamao, en bytes, de las imgenes que se desean guardar en la tabla.

En el ejemplo hemos incluido un campo BLOB para incluir la imagen, insertando tambin campos para recoger su nombre, su tamao (en bytes), su formato (el tipo de fichero transferido) as como un campo autoincremental. No es otra cosa que el ejemplo incluido en esta pgina adaptado la nueva extensin de comunicacin entre PHP y MySQL.

<?php #definimos una variable con el NOMBRE QUE QUEREMOS DAR A LA TABLA $tabla="fotos"; /* incluimos los datos de conexin al servidor MySQL */ include("mysqli.inc.php"); /****** Programacin por procesos ***********/ #conexion y seleccion de base de datos $conexion=@mysqli_connect($cfg_servidor,$cfg_usuario,$cfg_password,$cfg_basephp1); #escribimos la sentencia que crea la tabla $crear="CREATE TABLE IF NOT EXISTS $tabla ("; $crear.="num_ident INT(10) unsigned NOT NULL AUTO_INCREMENT,"; $crear.="imagen BLOB NOT NULL, "; $crear.="nombre VARCHAR(255) NOT NULL DEFAULT '',"; $crear.="tamano VARCHAR(15) NOT NULL DEFAULT '',"; $crear.="formato VARCHAR(10) NOT NULL DEFAULT '',"; $crear.="PRIMARY KEY (num_ident))type=MyISAM"; #Creamos la cadena, comprobamos si esa instruccin devuelve # VERDADERO o FALSO # y dependiendo de ellos insertamos el mensaje de exito o fracaso if(mysqli_query ($conexion,$crear)) { echo "<h2> Tabla $tabla creada con EXITO </h2><br>"; }else{ echo "<h2> La tabla $tabla NO HA PODIDO CREARSE</h2><br>"; }; # cerramos la conexin... y listo... mysqli_close($conexion); ?>
Aqu tiene el cdigo fuente que te permitira crear la tabla fotos e insertar automticamente algunas imgenes de ejemplo.
Mediante procesos Mediante objetos

Transferencia de la imagen
El formulario para realizar la transferencia de la imagen no tiene particularidades. Es un formulario habitual para transferencia de ficheros. Lo nico reseable sera incluir un campo oculto en el que pudiera especificarse una restriccin en cuanto al tamao mximo permitido para cada imagen y que debe estar acorde con el tipo de campo utilizado en la tabla.

<FORM ENCTYPE="multipart/form-data" ACTION="ejemplo707.php" METHOD="post"> <INPUT type="hidden" name="lim_tamano" value="65000"> <p><b>Selecciona la imagen a transferir<b><br> <INPUT type="file" name="foto"><br> <p><b>Ttulo la imagen<b><br> <INPUT type="text" name="titulo"><br></p> <p><INPUT type="submit" name="enviar" value="Aceptar"></p> </FORM>
Ejemplo de transferencia de imagen

Comprobacin del tipo de imagen

Al transferir imgenes jpg png el type MIME que reciba el servidor es distinto segn el navegador que se utilice para hacer la transferencia. Aqu debajo, en el cdigo fuente del script que actualiza la base de datos, tienes los nombres de esos tipos asociados a los navegadores ms usuales.

<?php $foto_name= $_FILES['foto']['name']; $foto_size= $_FILES['foto']['size']; $foto_type= $_FILES['foto']['type']; $foto_temporal= $_FILES['foto']['tmp_name']; $lim_tamano= $_POST['lim_tamano']; $foto_titulo= $_POST['titulo']; /* limitamos los formatos de imagen admitidos a: png que segun del navegador que ulicemos puede ser: en IE image/x-png en Firefox y Mozilla image/png jpg que puede tener como tipo en IE image/pjpeg en Firefox y Mozilla image/jpeg gif que tiene como tipo image/gif en todos los navegadores Mira los comentarios al margen sobre la variable $extensin */ if ($foto_type=="image/x-png" OR $foto_type=="image/png"){ $extension="image/png"; } if ($foto_type=="image/pjpeg" OR $foto_type=="image/jpeg"){ $extension="image/jpeg"; } if ($foto_type=="image/gif" OR $foto_type=="image/gif"){ $extension="image/gif"; } # condicionamos la insercin a que la foto tenga nombre, # un tamao distinto de cero y menor de lmite establecido # en el formulario y que la variable extensin sea no nula if ($foto_name != "" AND $foto_size != 0 AND $foto_titulo !='' AND $foto_size<=$lim_tamano AND $extension !=''){ /*reconversion de la imagen para meter en la tabla abrimos el fichero temporal en modo lectura "r" binaria"b"*/ $f1= fopen($foto_temporal,"rb"); #leemos el fichero completo limitando # la lectura al tamao de fichero $foto_reconvertida = fread($f1, $foto_size); #anteponemos \ a las comillas que pudiera contener el fichero # para evitar que sean interpretadas como final de cadena $foto_reconvertida=addslashes($foto_reconvertida); # abrimos la base de datos y escribimos las intrucciones de insercin # en el campo BLOB insertaremos la foto_reconvertida $tabla="fotos"; include("mysqli.inc.php"); $conexion=@mysqli_connect($cfg_servidor,$cfg_usuario,$cfg_password,$cfg_basephp1); $meter="INSERT INTO ".$tabla; $meter .=" (num_ident, imagen, nombre, tamano, formato) "; $meter .=" VALUES('','$foto_reconvertida','$foto_titulo',"; $meter .= "$foto_size, '$extension')"; if (@mysqli_query($conexion,$meter)){ print "Foto guardada en la tabla"; }else{ print "Ha habido un error al guardar la foto"; } }else{ echo "<h2>No ha podido transferirse el fichero</h2>";

} mysqli_close($conexion); ?>
Hay otro aspecto a tener en cuenta. Esa discriminacin de tipos se plantea nicamente cuando Apache recibe una transferencia. Cuando se visualiza un contenido las cabeceras tipo de contenido (header("content-type: xx")) pueden ser las mismas para todos los navegadores. Esa es la razn por la que a la hora de incluir el formato en la tabla utilizamos image/jpg, image/gif o image/png.

Cmo guardamos la imagen?


La informacin recibida a travs del formulario requiere un ligero retoque antes de incluirla en le campo BLOB de la tabla. Esa reconversin requiere abrir la imagen en modo binario (rb) -parece que solo en el caso de Windows leer el fichero completo y aadirle \ antes de las comillas mediante addslashes. Una vez hecho el retoque ya puede guardarse sin ms problema.

PNG con transparencias en Internet Explorer


Internet Explorer no permite visualizar de forma automtica las transparencias de las imgenes con formato png. Existen en la redalgunos recursos que permiten solventar ese problema. Hemos elegido uno de ellos pngfix.js- que puedes ver en este enlace. Se trata de un fichero JavaScript que basta incluir en la cabecera HMTL de la pgina de la forma que ves en el ejemplo. Cuando un navegador IE es detectado se ejecuta una funcin contenida en ese fichero que analiza la pgina, busca imgenes con extensin png y les aplica la transparencia adecuada. Por esa razn, es probable que inicialmente (al cargar la pgina) se visualice la imagen opaca y que, posteriormente, adquiera la transparencia.

Visualizacin de imgenes
La lectura de una imagen utiliza solo dos instrucciones. Incluir la cabecera Header en el que se indica el tipo de contenido (el famoso nombre MIME de la imagen) y luego imprimir el contenido del campo. Pero (por aquello de que header debe ir incluida en el script antes que cualquier otra salida) si pretendemos incluir en una pgina algo ms que una imagen tendremos que invocar esas dos funciones, de forma independiente, para cada una de ellas. Por esa razn al desarrollar el ejemplo que permite visualizar todas las imgenes de la tabla hemos tenido que incluir un script que va leyendo la tabla que contiene las imgenes para extraer los campos informativos y a la hora de ver la imagen hemos de recurrir a la misma tcnica que se utilizaba para ver las imgenes dinmicas. Es decir, poner una etiqueta de imagen de las de HTML pero -en vez de escribir el nombre de la imagen- poniendo incluyendo como nombre el del script que las visualiza y pasndole el nmero (valor del campo autoincremental) de la imagen que pretend visualizar.

<?php $numero=$_REQUEST['n']; $tabla="fotos1"; include("mysqli.inc.php"); $conexion=@mysqli_connect($cfg_servidor,$cfg_usuario,$cfg_password,$cfg_basephp1); $sacar = "SELECT * FROM ".$tabla." WHERE (num_ident=$numero)" ; $resultado = mysqli_query($conexion,$sacar); while ($registro = mysqli_fetch_assoc($resultado)){ $tipo_foto=$registro['formato']; header("Content-type: $tipo_foto"); echo $registro['imagen']; } mysqli_close($conexion); ?>
Ver imgenes guardadas

El problema de los PNG en IE

El JavaScript que asigna la transparencia a las imgenes en formato png las identifica buscando la coincidencia de los tres ltimos caracteres del nombre de la imagen con la extensin png. Cuando se trata de imgenes dinmicas el nombre de la imagen coinciden con el nombre de la llamada al script que se utiliza para su visualizacin. Por eso, para advertir a JavaScript de que se trata de una imagen png hemos incluido el condicional que puedes ver en el ejemplo. De esa forma, cuando se trata de una imagen en este formato incluimos en la peticin una variable con el valor png de forma que pueda ser reconocida por pngfix.js y aplicada la transparencia requerida. Script para leer la base de datos

<html> <head> <!-- al margen te comentamos la razn por la que --> <!-- se incluyen estas lneas en rojo --> <!--[if IE ]> <script type="text/javascript" src="pngfix.js"></script> <![endif]--> </head> <body> <? $base="ejemplos"; $tabla="fotos1"; include("mysqli.inc.php"); $conexion=mysqli_connect($cfg_servidor,$cfg_usuario,$cfg_password,$cfg_basephp1); $sacar = "SELECT * FROM ".$tabla; $resultado = mysqli_query($conexion,$sacar); while ($registro = mysqli_fetch_assoc($resultado)){ print "<center>Titulo de la imagen: ".$registro['nombre']."<br>"; /* la inclusin de este condicional obedece a los problemas que plantea la visualizacin de las transparencias de las imgenes png en Internet Explorer. Al margen justificamos las razones de su inclusin */ if($registro['formato']=="image/png"){ print "<img src='ver_foto.php?n=".$registro['num_ident']."&v=png'><br>"; }else{ print "<img src='ver_foto.php?n=".$registro['num_ident']."'><br>"; } print "Tamao de la imagen: ".$registro['tamano']." bytes </center>"; } mysql_close(); ?> </body> </html>
Ver imgenes guardadas

Tablas InnoDB (MySQLi) Las tablas InnoDB


Creacin de una tabla InnoDB
La creacin de tablas de este tipo no presenta ninguna dificultad aadida. El proceso es idntico a las tablas habituales sin ms que aadir Type=InnoDB despus de cerrar el parntesis de la sentencia de creacin de la tabla. Este script crea una tabla InnoDB con idnticos campos a los utilizados en el caso de la tabla MyISAM que hemos visto en pginas anteriores. La sintaxis, muy similar a la utilizada all es esta:

<?php #definimos (en minusculas) el nombre de la nueva tabla $tabla="demoinno";

# escribimos la cadena que contiene la sentencia de creacin de la nueva tabla $crear="CREATE TABLE $tabla ("; $crear.="Contador TINYINT(8) UNSIGNED ZEROFILL NOT NULL AUTO_INCREMENT,"; $crear.="DNI CHAR(8) NOT NULL, "; $crear.="Nombre VARCHAR (20) NOT NULL, "; $crear.="Apellido1 VARCHAR (15) not null, "; $crear.="Apellido2 VARCHAR (15) not null, "; $crear.="Nacimiento DATE DEFAULT '1970-12-21', "; $crear.="Hora TIME DEFAULT '00:00:00', "; $crear.="Sexo Enum('M','F') DEFAULT 'M' not null, "; $crear.="Fumador CHAR(0) , "; $crear.="Idiomas SET(' Castellano',' Francs','Ingls', ' Alemn',' Blgaro',' Chino'), "; $crear.=" PRIMARY KEY(DNI), "; $crear.=" UNIQUE auto (Contador)"; $crear.=")"; # esta es la nica diferencia con el proceso de # creacin de tablas MyISAM $crear.=" Type=InnoDB"; /* tenemos completa la sentencia MYSQL solo falta ejecutarla crear la conexin y ejecutarla */ /*incluimos los parmetros de conexin */ include('mysqli.inc.php'); /* incluimos dos opciones de proceso y de programacion orientada a objetos. Podemos ejecutar los ejemplos pasado mediante el metodo GET el tipo elegido. */ if(!empty ($_GET['tipo'])){ $tipo_script=$_GET['tipo']; }else{ $tipo_script="objetos"; } /*En caso de tipo proceso utilizaramos esto */ if ($tipo_script=="proceso"){ /****** Programacin mediante procesos ***********/ #conexion, seleccin de base de datos y verificacion de errores segun ejemplos anteriores $conexion=@mysqli_connect ($cfg_servidor,$cfg_usuario,$cfg_password,$cfg_basephp1); if(!mysqli_connect_errno()==0){ print "<Mbr>No ha podido realizarse la conexin mediante procesos<br>"; print "Error nmero: ". mysqli_connect_errno()." equivalente a: ". mysqli_connect_error(); exit(); } # Creacin. Los parmetros requieren el orden aqu indicado al revs del caso mysql if(mysqli_query($conexion,$crear)){ print "La tabla ha sido CREADA"; }else{ print "<br>No ha podido crearse la base de datos mediante procesos<br>"; print "Error : ". mysqli_error($conexion); exit(); } mysqli_close($conexion); } /* en caso de programacion orientada a objetos */

if ($tipo_script=="objetos"){ #conexion, seleccin de base de datos y verificacion de errores segun ejemplos anteriores $objeto=@new mysqli ($cfg_servidor,$cfg_usuario,$cfg_password,$cfg_basephp1); if(!$objeto->connect_errno==0){ print " No ha podido realizarse la conexin mediante objetos<br>"; print "Error nmero: ". $objeto->connect_errno." equivalente a: ". $objeto>connect_error; exit(); } if($objeto->query($crear)){ print "La tabla ha sido CREADA"; }else{ print "<br>No ha podido crearse la tabla mediante objetos<br>"; print "Error : ". $objeto->error; exit(); } $objeto->close(); } ?> Cuidado! Bajo Windows, al crear una base de datos o tabla InnoDB el nombre de la misma aparecer en minsculas independientemente de la sintaxis que hayamos utilizado en su creacin. Para prever posibles conflictos al ejecutar los scripts en diferentes plataformas utilizaremos minsculas para los nombres de tablas.

Una vez creadas, las tablas InnoDB se comportan a efectos de uso exactamente igual que las que hemos venido utilizando en las pginas anteriores. No es preciso hacer ningn tipo de modificacin en la sintaxis. Por tanto, es totalmente vlido todo lo ya comentado respecto a: altas, modificaciones, consultas y bajas.

Las transacciones
Uno de los riesgos que se plantean en la gestin de bases de datos es que pueda producirse una interrupcin del proceso mientras se est actualizando una o varias tablas. Pongamos como ejemplo el cobro de nuestra nmina. Son necesarias dos anotaciones simultneas: El cargo en la cuenta del organismo pagador y el abono en nuestra cuenta bancaria. Si se interrumpiera fortuitamente el proceso en el intermedio de las dos operaciones podra darse la circunstancia de que apareciera registrado el pago sin que se llegaran a anotar los haberes en nuestra cuenta. Las transacciones evitan este tipo de situaciones ya que los datos se registran de manera provisional y no se consolidan hasta que una instruccin confirme que esas anotaciones tienen carcter definitivo. Hemos de tener muy presente que para utilizar este tipo de opciones es imprescindible que las tablas sean del tipo InnoDB.

Sintaxis de las transacciones


Hay dos palabras que son claves para este tipo acciones. Commit, cuya traduccin puede ser ejecutar y rollback que significa algo como no ejecutar. Cuando se trata de la extensin mysqli hay que tomar en consideracin una tercera palabra, tambin clave, que esautocommit cuyo significado podra ser algo parecido a ejecutar de forma autmatica y que es configuracin por defecto de la extensin mysqli. Una buena opcin es conocer el estado actual de la opcin autocommit. Si su valor es TRUE significa que cualquier llamada amysql_query, $obejeto->query, mysqli_stmt_execute o $actuacion-> execute() se ejecutara de forma inmediata e irreversible. Por el contrario, si su valor fuera FALSE las instrucciones anteriores se ejecutaran de forma provisional pero no seran confirmadas hasta que se incluyera una orden commit o fueran descartadas por medio de una orden rollback. Para conocer el estado actual de autocommit hemos de ejecutar la sentencia MySQL siguiente:

SELECT @@autocommit

qu siguiendo el tratamiento clsico de las consultas nos devolver el valor TRUE (1) o FALSE (0) de su estado actual. Su valor por defecto es TRUE y las eventuales modificaciones que podamos hacer en nuestros script solo persisten hasta la finalizacin de la ejecucin del mismo. La modificacin de su estado requiere de una de estas funciones: mysqli_autocommit($conexion,BOOLEANO ) o $objeto->autocommit(BOOLEANO )

Siendo $conexion el identificador de conexin (programacin mediante procesos) y $objeto el identificador del objeto mysqli (programacin orientada a objetos. El valor BOOLEANO puede ser TRUE o FALSE. Como es lgico para poder utilizar las transacciones es necesario que ese valor sea FALSE. Una vez configurado autocommit como false las sucesivas sentencias, sean simples, mltiples como preparadas, no se registrarn en la tabla hasta que no se incluya una orden explcita de hacerlo. Esa orden requiere el uso de una de ests dos funciones: mysqli_commit($conexion ) o $objeto->commit()

sentencias que advierte a MySQL (en modo procesos y objetos respectivamente) que ha finalizado la transaccin y que S debe hacer efectivos todos los cambios incluidos en ella. Si se optara por NO hacer efectivos los cambios habra que utilizar: mysqli_rollback($conexion ) o $objeto->rollback()

Precauciones a tener en cuenta


Cuando se utilizan campos autoincrementales en tablas InnoDB los contadores se van incrementando al aadir registros (incluso de forma provisional) con lo cual si se aborta la inclusin con un ROLLBACK ese contador mantiene el incremento y en inserciones posteriores partir de ese valor acumulado. Por ejemplo. Si partimos de una tabla vaca y hacemos una transaccin de dos registros (nmero 1 y nmero 2 en el campo autoincremental) y la finalizamos con ROLLBACK, no se insertarn pero en una insercin posterior el contador autoincremental comenzar a partir del valor 2.

Cuidado! Cuando una instruccin modifica la condicin de autocommit ese valor no recupera su valor por defecto (true) hasta que no se incluya una modificacin explcita de su valor o hasta que finalice la ejecucin del script actual.

Aqu tienes unos ejemplos de uso de transacciones


Ejecutar Modo procesos Ver cdigo fuente Modo procesos Ejecutar Orientado a objetos Ver cdigo fuente Orientado a objetos

La integridad referencial
Elementos necesarios para la integridad referencial

La integridad referencial ha de establecerse siempre entre dos tablas. Una de ellas ha de comportarse como tabla principal (suele llamarse tabla padre y la otra sera la tabla vinculada tabla hijo. Es imprescindible: Que la tabla principal tenga un ndice primario (PRIMARY KEY) Que la tabla vinculada tenga un ndice (no es necesario que sea ni nico ni primario) asociado a campos de tipo idntico a los que se usen para ndice de la tabla principal. Si observas el cdigo fuente del ejemplo que tienes aqu debajo podrs observar que utilizamos el nmero del DNI (nico para alumno) como elemento de vinculacin de la tabla de datos personales con la que incluye las direcciones.

Integridad referencial en tablas InnoDB


Cuando se trabaja con varias tablas que tienen algn tipo de vnculo resulta interesante disponer de mecanismos que protejan o impidan acciones no deseadas. Supongamos, como veremos en los ejemplos posteriores que pretendemos utilizar una tabla con datos de alumnos y otra tabla distinta para las calificaciones de esos alumnos. Si no tomamos ninguna precaucin (bien sea mediante los script o mediante el diseo de las tablas) podra darse la circunstancia de que incluyramos calificaciones a alumnos inexistentes, en materias de las que no estn matriculados, etctera. Tambin podra darse la circunstancia de que diramos de baja a un alumno pero que se mantuvieran las calificaciones vinculadas a l. Todas estas circunstancias suelen producir efectos indeseados y las tablas InnoDB pueden ser diseadas para prever este tipo de situaciones.

Sintaxis para la vinculacin de tablas


Los vnculos entre tablas suelen establecer en el momento de la creacin de la tabla vinculada. CREATE TABLE tabla (campo1, campo2,... KEY nombre (campo de vinculacion ), FOREIGN KEY (campo de vinculacion) REFERENCES nombre_de la tabla principal (Indice primario de la tabla principal) ) Type=InnoDB

donde el campo de vinculacion ha de ser un ndice (no es necesario que sea PRIMARY KEY ni UNIQUE) y donde Indice primario de la tabla principal ha de ser un ndice primario (PRIMARY KEY) de la tabla principal. Debe haber plena coincidencia (tanto en tipos como contenidos) entre ambos ndices.

<?php $tabla1="principal"; $tabla2="vinculada"; /*incluimos los parmetros de conexin */ include('mysqli.inc.php'); /****** Programacin mediante procesos ***********/ #conexion, seleccin de base de datos y verificacion de errores segun ejemplos anteriores $conexion=@mysqli_connect ($cfg_servidor,$cfg_usuario,$cfg_password,$cfg_basephp1); # creacin de la tabla principal type InnoDB $crear="CREATE TABLE IF NOT EXISTS $tabla1 ("; $crear.="DNI CHAR(8) NOT NULL, "; $crear.="Nombre VARCHAR (20) NOT NULL, "; $crear.="Apellido1 VARCHAR (15) not null, "; $crear.="Apellido2 VARCHAR (15) not null, "; # el indice primario es imprescindible. Recuerda que debe # estar definido sobre campos NO NULOS $crear.=" PRIMARY KEY(DNI) "; $crear.=")"; $crear.=" Type=InnoDB"; # creamos la tabla principal comprobando el resultado if(@mysqli_query ($conexion,$crear)){ print "La tabla ".$tabla1." ha sido creada<br>"; }else{ print "No se ha creado ".$tabla1." ha habido un error<br>";

} # crearemos la tabla vinculada $crear1="CREATE TABLE IF NOT EXISTS $tabla2 ("; $crear1.="IDENTIDAD CHAR(8) NOT NULL, "; $crear1.="calle VARCHAR (20), "; $crear1.="poblacion VARCHAR (20), "; $crear1.="distrito VARCHAR(5), "; # creamos el ndice (lo llamamos asociador) para la vinculacin # en este caso no ser ni primario ni nico # Observa que el campo IDENTIDAD de esta tabla CHAR(8) # es idntico al campo DNI de la tabla principal $crear1.=" KEY asociador(IDENTIDAD), "; #establecemos la vinculacin de ambos ndices $crear1.=" FOREIGN KEY (IDENTIDAD) REFERENCES $tabla1(DNI) "; $crear1.=") TYPE = INNODB"; # creamos (y comprobamos la creacin) la tabla vinculada if(@mysqli_query ($conexion ,$crear1)){ print "La tabla ".$tabla2." ha sido creada<br>"; }else{ print "No se ha creado ".$tabla2." ha habido un error<br>"; } mysqli_close($conexion); ?>
Aqu tienes el ejemplo en ambas modalidades
Ejecutar Modo procesos Ver cdigo fuente Modo procesos Ejecutar Orientado a objetos Ver cdigo fuente Orientado a objetos

Modificacin de estructuras
La modificacin de estructuras en tablas vinculadas puede hacerse de forma idntica a la estudiada para los casos generales de MySQL siempre que esas modificaciones no afecten a los campos mediante los que se establecen las vinculaciones entre tablas. Aqu tienes un ejemplo en se borran y aaden campos en ambas tablas. Como puedes ver la sintaxis es exactamente la misma que utilizamos en temas anteriores.
Ver cdigo fuente Modo procesos Ver cdigo fuente Orientado a objetos

Modificacin o borrado de campos vinculados


Las sentencias MySQL que deban modificar o eliminar campos utilizados para establecer vnculos entre tablas requieren de un parmetro especial (CONSTRAINT) puede ser distinto en cada una de las tablas que es necesario conocer previamente. La forma de visualizarlo es ejecutar la sentencia: SHOW CREATE TABLE nombre tabla que devuelve como resultado un array asociativo con dos ndices. Uno de ellos -llamado Table- que contiene el nombre de la tabla y el otro -Create Table- que contiene la estructura con la que ha sido creada la tabla, pero incluyendo el parmetro CONSTRAINT seguido de su valor. Ese valor es precisamente el que necesitamos para hacer modificaciones en los campos asociados de las tablas vinculadas. En estos podrs ver el cdigo fuente y ejecutar los scripts que permiten visualizar el valor de de CONSTRAINT.
Ejecutar Modo procesos Ver cdigo fuente Modo procesos Ejecutar Orientado a objetos Ver cdigo fuente Orientado a objetos

Conocido el valor de parmetro anterior el proceso de borrado del vnculo actual requiere la siguiente sintaxis: ALTER TABLE nombre de la tabla DROP FOREIGN KEY parametro

Cuando se trata de aadir un nuevo vnculo con una tabla principal habremos de utilizar la siguiente sentencia: ALTER TABLE nombre de la tabla ADD [CONSTRAINT parametro] FOREIGN KEY parametro REFERENCES tabla principal(clave primaria)

El parmetro CONSTRAIT (encerrado en corchetes en el prrafo anterior) es OPCIONAL y solo habra de utilzarse en el caso de que existiera ya una vinculacin previa de esa tabla. En estos ejemploS determinaremos el valor de CONSTRAINT borraremos un campo asociado de una tabla vinculada y posteriormente crearemos un nuevo campo idntico al eliminado.
Ejecutar Modo procesos Ver cdigo fuente Modo procesos Ejecutar Orientado a objetos Ver cdigo fuente Orientado a objetos

Aadir registros a la tabla vinculada


Agregar nuevos registros a una tabla vinculada como la de los ejemplos anteriores no requiere ningn tratamiento especial. El proceso es ya comentado en pginas anteriores. El nico problema que podra plantearse sera cuando se intentar aadir un registro y se produjera un error n 1452. Cannot add or update a child row: a foreign key constraint fails (`ejemplos`.`vinculada`, CONSTRAINT `vinculada_ibfk_1` FOREIGN KEY (`IDENTIDAD`) REFERENCES `principal` (`DNI`)). Esto ocurrir si intentamos aadir un registro a la tabla vinculada sin que en el campo DNI de la tabla principal exista otro registro con un valor igual al que pretendemos introducir en la tabla vinculada. Hemos de aadir, y por este orden, un registro a la tabla principal con el DNI requerido y posteriormente ya podremos ejecutar -sin errores- el script que inserta datos en la tabla vinculada. Y podremos ejecutarlo tantas veces como queramos ya que -el campo IDENTIDAD est definido como KEY y por tanto permite duplicados- no hemos establecido la condicin de ndice PRIMARIO UNICO.

Borrar o modificar registros en la tabla principal


El borrado de registros tambin requiere ejecutarse en el orden adecuado. En este caso hemos de empezar borrando los registros de la tabla vinculada para, posteriormente, hacerlo con la tabla principal. Sin intentamos borrar un registro de la tabla principal antes de eliminar todos los vinculados a l se producir un error n 1451 que corresponde a: Cannot delete or update a parent row: a foreign key constraint fails (`ejemplos`.`vinculada`, CONSTRAINT `vinculada_ibfk_1` FOREIGN KEY (`IDENTIDAD`) REFERENCES `principal` (`DNI`)) advirtindonos de que no se realiza el borrado porque existen registros en la tabla vinculada con valores asociados al ndice del campo que pretendemos borrar y, de permitir hacerlo, se rompera la integridad referencial ya que quedaran registros hurfanos en la tabla vinculada. Lo mismo ocurir sin tratamos de modificar un registro de la tabla principal y la modificacin afecta al ndice que realiza la asociacin con la tabla (o tablas) vinculadas se producira -por las mismas razones y en las mismas circunstancias- un error 1451 que corresponde a: Cannot delete or update a parent row: a foreign key constraint fails (`ejemplos`.`vinculada`, CONSTRAINT `vinculada_ibfk_1` FOREIGN KEY (`IDENTIDAD`) REFERENCES `principal` (`DNI`)) que impedira la modificacin. El borrado o modificacin de un registro de la tabla principal requiere siempre que no existieran en la tabla (o tablas) vinculada registros asociados con l.

Borrado de tablas vinculadas


Si pretendemos eliminar una tabla principal sin haberlo hecho previamente con sus tablas vinculadas recibiremos un mensaje de error y no se producir el borrado.

Las tablas vinculadas s permiten el borrado y una vez que stas ya han sido eliminadas (o quitada la vinculacin) ya podrn borrarse sin problemas las tablas principales. El orden de borrado (si ambas pretenden borrarse desde el mismo script)es importante. Primero se borra la vinculada y luego la principal.

Opciones adicionales de FOREIGN KEY


La clasula FOREIGN KEY permite aadirle detrs de la definicin ya comentada y sin poner coma separndola de ella los parmetros ON DELETE y ON UPDATE en las que se permite especificar una de las siguientes opciones: ON DELETE RESTRICT

Esta condicin (es la condicin por defecto de MySQL y no es preciso escribirla) indica a MySQL que interrumpa el proceso de borrado y d un mensaje de error cuando se intente borrar un registro de la tabla principal cuando en la tabla vinculada existan registros asociados al valor que se pretende borrar. ON DELETE NO ACTION

Es un sinnimo de la anterior. ON DELETE CASCADE

Cuando se especifica esta opcin, al borrar un registro de la tabla principal se borrarn de forma automtica todos los de la tabla vinculada que estuvieran asociados al valor de la clave fornea que se trata de borrar. Con ello se conseguira una actualizacin automtica de la segunda tabla y se mantendra la identidad referencial. ON DELETE SET NULL

Con esta opcin, al borrar el registro de la tabla principal no se borraran los que tuviera asociados la tabla secundaria pero tomaran valor NULL todos los ndices de ella coincidentes con la clave primaria de la tabla principal. Para el caso de ON UPDATE las opciones son estas: ON UPDATE RESTRICT ON UPDATE CASCADE ON UPDATE SET NULL

Su comportamiento es idntico a sus homnimas del caso anterior.

Cuidado! El uso de la opcin SET NULL requiere que el campo indicado en FOREIGN KEY permita valores nulos. Si est definido con flag NOT NULL (como ocurre en los ejemplos que tienes aqu) dara un mensaje de error. Al incluir ON DELETE y ON UPTADE (si se incluyen ambas) han de hacerse por este mismo orden. Si se cambiara este orden dara un mensaje de error y no se ejecutaran.

Automatizacin de procesos
En estos ejemplos haremos un proceso partiendo de cero. Borraremos las eventuales tablas preexistentes, crearemos dos tablas vinculadas, insertaremos algunos datos y posteriorme realizaremos una actualizacin en cascada.
Ejecutar Ver cdigo fuente Ejecutar Ver cdigo fuente

Modo procesos

Modo procesos

Orientado a objetos

Orientado a objetos

Seguridad con MySQLi Inyeccin de cdigo


El hecho de utilizar los recursos de MySQLi no excluye los riesgos de seguridad derivados de lo que llambamos inyeccin de cdigocuando tratbamos de MySQL. Todo lo argumentado all respecto a los riesgos y vulnerabilidades sigue teniendo plena vigencia tal como puedes ver en estos ejemplos.
Ejecutar consulta Mediante procesos Ver cdigo fuente Mediante procesos Ejecutar consulta Mediante objetos Ver cdigo fuente Mediante objetos

Como habrs podido observar una consulta con el cdigo adecuado WHERE Nombre='' or '34=34' muestra la vulnerabilidad y devuelve todos los registros contenidos en la tabla por las mismas razones ya comentadas al estudiar MySQL. Para evitar la posibilidad de ese efecto indeseado (inyeccin de cdigo) cuando utilizamos MySQLi, PHP dispone de las funcin: mysqli_real_escape_string($conexion,cadena) o $objeto->real_escape_string(cadena) que hace una llamada a la librera MySQL del mismo nombre y para que escape los caracteres especiales contenidos en lacadena de forma que sea mucho ms seguro su uso a travs de mysql_query(). Los caracteres que son escapados son los siguientes:\x00, \n, \r, \, ', " y \x1a. Se convertiran en: \\x00, \\n, \\r, \\\, \', \" y \\x1a con lo cual la cadena ' or '34=34 se convertira en \' or \'34=34 y la clasula anteriormente comentada se convertira en WHERE (Nombre='\' or \'34=34') con lo cual ya no se producira el efecto indeseado y se evitara el riesgo de uso inadecuado.
Ejecutar consulta Mediante procesos Ver cdigo fuente Mediante procesos Ejecutar consulta Mediante objetos Ver cdigo fuente Mediante objetos

Cuidado! El uso de la funcin mysqli_real_escape_string() requiere como parmetro un identificador de conexin. Por lo tanto es imprescindible que antes de utilizarla se haya establecido una conexin con el servidor MySQL. De igual manera, cuando se trata de programacin orientada a objetos, real_escape_string() es un mtodo y en consecuencia es requisito inprescindible la preexistencia del objeto antes de su utilizacin.

Aunque los desarrolladores de PHP anuncian su prxima desaparicin, en la actualidad hay en el fichero php.ini una directiva llamadamagic_quotes_gpc cuyo valor por defecto es Off. Si cambiramos esa directiva a On (o si usramos un servicio externo que la tuviera configurada de esta forma) todos los datos recibidos por medio de los mtodos GET o POST seran tratados por la funcin: addslashes(cadena) que devuelve la cadena despus de haber escapado los carcteres ',", \ y NUL (el byte NULL). La accin de addslashes puede deshacerse utilizando la funcin stripslashes(cadena_escapada) que quita los carcteres de escape aadidos por addslashes devolviendo la cadena original. Para comprobar como est configurada la directiva magic_quotes_gpc disponemos de la funcin: get_magic_quotes_gpc() que devuelve un valor booleano. True si est configurada como On y False en caso de estarlo como Off.

Filtrado de cdigo
Mediante un proceso como el que puedes ver en el cdigo fuente que se incluye a continuacin puede realizarse un filtrado de los eventuales intentos de inyeccin de cdigo. Su funcionamiento es el siguiente: Leemos toda la informacin que se recibe en las variables superglobales $_GET y $_POST. Recorremos los arrays que recogen esos resultados sustituyendo sus valores por los obtenidos de la aplicacin de una funcin que realiza el filtrado. La funcin que realiza el filtrado comprueba el estado de magic_quotes. Caso de estar configuradas con On revierte los caracteres escapados para impedir que se dupliquen los carcteres de escape. Comprueba si es numrico el valor recibido y en caso de serlo lo devuelve sin ninguna modificacin. Si el valor recibido no es numrico aplica la funcin mysqli_real_escape_string y devuelve el resultado dentro de unas comillas simples. De esta forma podramos despreocuparnos de poner comillas al valor de la variable en la clasula WHERE. Si se trata de un nmero no las requiere y si se trata de una cadena el valor recibido ya las incluye.

<?php if(is_array($_GET)){ foreach ($_GET as $_GET_indice=>$_GET_valor){ $_GET[$_GET_indice]=filtro_seguridad($_GET_valor); } } if(is_array($_POST) ){ foreach ($_POST as $_POST_indice=>$_POST_valor){ $_POST[$_POST_indice]= filtro_seguridad($_POST_valor); } } function filtro_seguridad($valor){ /* comprueba si estn activas las magic_quotes y, en caso de estarlo revierte su accin mediante stripslashes */ if (get_magic_quotes_gpc()) $valor = stripslashes($valor); /* Abrimos una conexin con MySQL requerida para aplicar mysqli_real_escape_string */ $conexion=mysqli_connect("localhost","pepe","pepa"); /* con la certeza de que estamos ante la cadena original aplicamos la funcin mysql_real_escape_string a todas las cadenas no numricas */ if (!is_numeric($valor)) $valor = "'" .mysqli_real_escape_string($conexion,$valor) . "'"; /* cerramos la conexion y devolvemos el resultado*/ mysqli_close($conexion); return $valor; } ?>
Este es un ejemplo de utilizacin de procedimiento anterior
Ejecutar consulta Mediante procesos Ver cdigo fuente Mediante procesos

En el caso de optar por la programacin orientada a objetos el script anterior debera tener esta sintaxis:

<?php if(is_array($_GET)){ foreach ($_GET as $_GET_indice=>$_GET_valor){ $_GET[$_GET_indice]=filtro_seguridad($_GET_valor); } } if(is_array($_POST) ){ foreach ($_POST as $_POST_indice=>$_POST_valor){ $_POST[$_POST_indice]= filtro_seguridad($_POST_valor); } }

function filtro_seguridad($valor){ /* comprueba si estn activas las magic_quotes y, en caso de estarlo revierte su accin mediante stripslashes */ if (get_magic_quotes_gpc()) $valor = stripslashes($valor); /* Abrimos una conexin con MySQL requerida para aplicar mysqli_real_escape_string */ $objeto_filtro=new mysqli("localhost","pepe","pepa"); /* con la certeza de que estamos ante la cadena original aplicamos la funcin mysql_real_escape_string a todas las cadenas no numricas */ if (!is_numeric($valor)) $valor = "'" .$objeto_filtro->real_escape_string($valor) . "'"; /* cerramos la conexion y devolvemos el resultado*/ $objeto_filtro->close(); return $valor; } ?>
Este es un ejemplo de utilizacin de procedimiento anterior
Ejecutar consulta Mediante objetos Ver cdigo fuente Mediante objetos

Cambios de aspecto de una pgina Modificacin de los contenidos de una pgina


Cuando se trata de modificar parcialmente los contenidos de una pgina tenemos dos posibilidades. La ms cutre seguramente sera cargar nuevamente toda la pgina despus de haber realizado las modificaciones requeridas en el servidor. En este supuesto seguiramos movindonos en el entorno de los lenguajes del lado del servidor, es decir, en el entorno de PHP. La solucin ms ptima, pensando siempre en modificaciones parciales, sera mantener todo el contenido no modificble y realizar nicamente los cambios en los elementos de que los requieran. De esa forma, adems de lograr una continuidad grfica en la pantalla estaramos reduciendo el tiempo de ejecucin de eso cambios. En este segundo supuesto ser necesario el concurso de un lenguaje del lado del cliente que permita ejecutar aquellas modificaciones que sean susceptibles de hacerse en modo local y/o recabar del servidor datos concretos que pueden ser requeridos. Trataremos el asunto en el entorno de JavaScript complementndolo cuando sea necesario con AJAX (Asynchronous JavaScript And XML) y accediendo al los datos del servidor mediante el objeto XMLHttpRequest soportado e incluido en la mayora de los navegadores actuales.

Elementos con nombre


Sin meterme en grandes profundidades del JavaScript ni de los llamados DOM (Document Object Model) y BOM (Browser Object Model) vamos a intentar encontrar algunas recetas prcticas que nos permitan identificar indubitativamente los elementos de un documento. Consideremos el documento con una familia numerosa en la que conviven una cantidad inusual de hijos. En el mbito familiar la solucin es fcil. Para cada hijo se elige un nombre del agrado de sus progenitores con las restricciones establecidas en el artculo 54 de la Ley del Registro Civil (espaol) que establece que No puede imponerse al nacido el mismo nombre que ostente uno de sus hermanos.... Con un criterio similar podremos bautizar los diferentes elementos de un documento. Para ello bastara con incluir en las etiquetas del lenguaje HTML algo como esto: id="nombre_unico". De esta forma podremos ya podremos llamar a cada cosa por su nombre, es decir, por su id aunque algunos elementos, body por ejemplo, al ser nicos no necesitan de ningn id. En los ejemplos vamos a probar con varias de las etiquetas habituales en HTML tales como: <div>, <tr>, <td>, <li> o <img> y tambin con Los <OBJECT> de los tipos: img/gif, text/html o application/x-shockwave-flash as como con los diferentes elementos utilizados por los formularios. De esa forma podramos crear una pgina como esta que puedes ver en el ejemplo
Ver pgina Ver cdigo fuente

Como podrs observar hemos intentado incluir una pequea miscelnea de elementos HTML utilizando estilos CSS en algunos casos. Las nicas novedades (si es que lo son para t) son las nuevas formas de utilizacin la etiqueta <object> que parece tener una gran proyeccin futura ya que este tipo de elemento permite utilizar una sintaxis similar para los diferentes elementos. Compatible con las mayora de los navegadores modernos (la estandarizacin en trminos absolutos me temo que es una gran utopa) y utilizando <object data="ruta_nombre_y_extension" type="tipo_mime"> De esta forma, <object id="foto_objeto" data="./images/bocadillo.gif" type="image/gif"></object>> nos permite incluir una imagen de forma alternativa a la clsica de: <img id="foto_objeto" src="./images/bocadillo.gif" />. De igual forma y tan slo modificando el tipo de objeto hemos incluido una animacin flash usando <object type="application/x-shockwave-flash" data="./videos/trubia.swf"> y tambin un sonido por medio de <object type="audio/x-wav" data="data/test.wav"></object> e incluso hemos podido utilizar, como opcin alternativa al clsicoIFRAME el objeto <object id="web" data="http://www.rinconastur.com" type="text/html"></object> ahora con tipo text/html. Como quiera que existen una gran variedad de tipos MIME en este enlace tiene una chuleta en la que se incluyen una buena parte de las extensiones de ficheros existentes y los tipos MIME asociados.

Cuidado! He vuelto atrs para corregir el ejemplo anterior y a la vez advertirte de algo de relativa importancia. Parece que la estadarizacin es algo absolutamente imposible. Los quebraderos de cabeza son continuos y muchas veces nos obligan a recurrir a algunas chapuzas. Una de ellas sera tener la precaucin de incluir dentro de una etiqueta div losobject destinados a contener pginas web. Es decir, en vez de escribir algo como: <object id="web" data="http://www.rinconastur.com" type="text/html"></object> procura escribir esto: <div id="chapuza_para_IE"> <object id="web" data="http://www.rinconastur.com" type="text/html"></object> </div> Puede parecer (o ser) ridculo pero no encontr una opcin mejor para resolver un problema que se me plante un poco ms adelante. Misterios de la informtica! Me hizo recordar un pseudodespido del que fu vctima hace ya unos cuantos aos. Tard ms de un mes en darme cuenta que en una opcin de QuarkXpress no era lo mismo 90 que la suma algebraica (-90+180)!Misterios ...!

Cmo identifica JavaScript cada uno de los elementos?


Lo primero que tenemos que considerar es la forma en la que JavaScript identifica cada una de las partes de nuestra pgina web. Para JavaScript todo son objetos. Algo bastante parecido, al menos en el concepto, a lo que ocurra con los objetos PHP. Y como ocurra all cada objeto pueden contener otros objetos y disponer de mtodos y tambin de propiedades. Cuandos se trata de documentos HMTL o XML tenemos que recurrir al DOM (Document Model Objects) algo as como Objetos para la representacin de Documentos que puede sonar algo raro pero vers que, al menos en lo que vamos a necesitar, no resulta nada complicado una vez que le hayamos cogido el tranquillo. Hemos aprendido que cada vez que abrimos el navegador lo que estamos haciendo es abrir una ventana y como ventana en raro se escribe window pues ya tenemos un objeto Javascript, el objeto window que por decirlo de alguna manera es como el gran contenedor de todo lo dems. Dentro de window est todo lo dems. Los objetos que contiene, sus mtodos y sus propiedades. En PHP la sintaxis era $objeto->metodo() o $objeto->propiedad. En el caso de JavaScript -> es sustituido por el caracter punto (.) En este enlace tiene una pgina en la que por medio de un script de JavaScript puedes ver la informacin correspondiente al objeto window y a algunos de los objetos que contiene.

Cuidado! La normalizacin o estandarizacin parece ser una utopa en el mundo de los navegadores y el JavaScript. Si abres la pgina del prrafo anterior aqu est el enlace con distintos navegadores podrs observar que los resultados de pulsar sobre los enlaces que contiene son distintos en cada uno de ellas. Podrs ver, por ejemplo, que en Internet Explorer no van a aparecerte alusiones a los mtodos que incluyen los objetos. Tambin podrs observar que las propiedades, en incluso los objetos contenidos en cada uno de los objetos, no son exactamente los mismos. La

compatibilidad entre los diferentes navegadores sigue requiriendo autntico encaje de bolillos. Quiz algn da... se normalizarn los navegadores.

Para nuestros fines uno de los objetos ms importantes es window.document.body como todos los objetos JavaScript que vayamos manejando incluye una serie de propiedades y mtodos que puedes ver enumeradas en el enlace de igual nombre que hay en este documento. El objeto window.document.body incluye otro objeto llamado window.document.body.style cuyas propiedades son las diferentes opciones de estilos aplicables al body. Cuales son esas propiedades? La lista es larga y bastante similar a la utilizada en las hojas de estilo pero cuidado! que la sintaxis no es la misma. Por ejemplo lo que en CSS (las hojas de estilo en cascada) se define como background-color se corresponde con una propiedad del objeto style de JavaScript llamada backgroundColor. Para facilitarte las cosas en este enlacetienes la lista de las diferentes propiedades relacionadas con los estilos. Veamos ahora un poco de cdigo JavaScript relacionado con este asunto. En PHP el cdigo lo delimitamos mediante <?php y ?>. En JavaScript es bastante similar aunque aqu se delimita por medio de las etiquetas <script type="text/javascript"> y </script> El tratamiento de las propiedades de los objetos es similar al que usamos en PHP con la diferencia que las -> son reemplazadas aqu. y que, a diferencia de PHP hay una serie de objetos (body entre ellos) que no hace falta instanciar porque se crean de forma automtica. Por tanto para modificar una propiedad bastara con escribir algo as: window.document.body.style.backgroundColor="nuevo_color". Eso es lo que puedes ver en estos ejemplos. Pero fjate en los dos primeros. Tambin aqu el navegador hace una lectura secuencial del documento y si instanciamos un objeto que an no ha sido creado (es lo que ocurre en el primer ejemplo) no habr manera de que se modifique la pretendida propiedad.

<html> <head> <title>Pruebas del body</title> <script type="text/javascript"> window.document.body.style.backgroundColor="#ffff00"; </script> </head> <body> Te has precipidado. Me mandaste cambiar el color del body antes de que el body existiera. </body> </html>
Ver ejemplo

<html> <head> <title>Pruebas del body</title> </head> <body> <script type="text/javascript"> window.document.body.style.backgroundColor="#ffff00"; </script> Ahora si me pondr amarillo. Las cosas en su sitio. Los javascript tambin. </body> </html>
Ver ejemplo

Vamos un poco a salto de mata pero como todos los lenguajes tienen una gran similitud pienso que no resulta difcil de entender este nuevo ejemplo. Tambin existen funciones en JavaScript, tambin la sintaxis es: function nombre_de_la_funcion(){ .... ... instrucciones .... .... }

Como ocurre en PHP y en todos los dems lenguajes las funciones no se ejecutan hasta que no son invocadas (eso permite incluirlas en cualquier parte del documento) y tambin aqu se invocan escribiendo nombre_de_la_funcion(). Hay una diferencia (puedes verla en el ejemplo) y es que en el caso de JavaScript la ejecucin de la funcin puede asociarse a un evento. Un evento no es otra cosa segn la RAE que un acaecimiento, una cosa que sucede. Y ese es su significado. Cuando acaece que se carga el body de la pgina (onLoad) es cuando se ejecuta automticamente la funcin.

<html> <head> <title>Pruebas del body</title> <script type="text/javascript"> function cambia_fondo(){ window.document.body.style.backgroundColor="#ffff00"; } </script> </head> <body onLoad="cambia_fondo()"> Ahora me es dicho: cuando cambies cargues el body (onLoad) ejecuta la funcin cambia_fondo. Soy obediente y lo hago </body> </html>
Ver ejemplo

Los ejemplos anteriores aluden al objeto style contenido en body. Pero body tiene, adems sus propiedades (algunas modificables otras no) que tambin se pueden acceder de forma fcil. Aqu tienes un ejemplo en el que hemos incluido una novedad. Ahora la funcin se ejecuta pulsando un enlace clsico en el que hemos sustituido el nombre de la nueva pgina (lo habitual en los enlaces) por esto otro:javascript:nombre_de_la_funcion(). Ahora, cuando pulsemos en el enlace se ejecutar la funcin. Podrs ver como la funcin alert() abre una ventanita informativa sobradamente conocida en la que puede leerse el valor de lo contenido en su parntesis.

<html> <head> <title>Pruebas del body</title> <script type="text/javascript"> function informame(){ alert(window.document.body.clientWidth); } </script> </head> <body> Si <a href="javascript:informame()">pulsas aqu</a> podrs conocer el ancho de esta ventana. Si modificas su tamao y vuelves a pulsar vers que la medida cambia. </body> </html>
Ver ejemplo

La identificacin de cada uno de los elementos de una pgina podra complicarse a medida que la pgina va incluyendo contenidos. JavaScript ha ido evolucionando a lo largo del tiempo. Los primeros navegadores con JavaScript permitan acceder slo a ciertos tipos de objetos del contenido del documento que son conocidos como colecciones y que se identifican como document.anchors (anclas),document.forms (formularios), document.images (imgenes), document.links (enlaces), doc ument.applets (applets) y document.embeds(objetos incrustados), estos dos ltimos ya han caido en absoluto desuso. Como quiera que en un mismo documento puede haber varios objetos de la misma coleccin (varias imgenes o varios formularios por poner un ejemplo) la forma de referirse a ellos era (y sigue siendo ya que los navegadores actuales mantienen esta forma de acceso a estos tipos de objetos) utilizar lo que en PHP llamaramos un ndice escalar de forma que sintaxis del tipo document.images[0] odocument.images[4] haran alusin a la primera (empieza a numerar desde cero) y la quinta (por la misma razn) de las imgenes contenidas en el documento contadas, como se deca en lo crditos de las pelculas, por orden de aparicin.

Tambin es factible aludir a los diferentes elementos por medio de id de modo que si en la etiqueta de una imagen incluimos algo como: <img id="la_foto" src="...." /> javaScript la identificar cuando escribamos document.images['la_foto'] (fjate en las comillas que van dentro del corchete). En este ejemplo tienes algunas muestras de como hacer estas llamadas.
Ver ejemplo Ver cdigo fuente

Afortunadamente, nuestro ya famoso id pude suplir con creces las limitaciones de las colecciones. Ser la referencia utilizaremos en adelante. Bastar con que escribamos en JavaScript algo as como window.document.getElementById('identificador') para referirnos a el elemento HMTL cuya etiqueta de apertura incluya id="identificador". Para que JavaScript no tenga dudas bastar, tal como hemos comentado ya al principio de esta pgina, con que no repitamos los nombres de los identificadores a lo largo nuestro documento. Igual que ocurra con body, cada uno de los objetos window.document.getElementById('identificador') contiene un objeto style al que nos podremos referir utilizando la sintaxis: window.document.getElementById('identificador').style Si preferimos utilizar una sintaxis un poco menos farragosa podremos recurrir a objetos intermedios con denominaciones ms fciles. Por ejemplo: var variable1= window.document.getElementById('identificador'); y var variable2=variable1.style podramos hacer alusin mediante la variable variable1 al objeto cuyo id es identificador y a sus estilos mediante variable2. Probablemente resultara ms cmodo y ms corto.

Cambios de aspecto de los elementos de una pgina


Al comienzo de este documento hemos incluido un ejemplo en que utilizbamos una muestra de los diferentes elementos HTML asignndoles un nombre identificador creanod con ellos una pgina (hasta el momento esttica). A partir de ese documento con sus elementos identificados por medio de sus respectivos id ya estaremos en condiciones de recurrir a JavaScript para hacer cambios de forma autmatica. Pienso que una forma de hacerlo con determinado mtodo sera clasificar los cambios en dos tipos: aspecto y contenido. Empezamos por el aspecto lo primero de todo es decidir dnde hacer el cambio y, luego, ver que cambio pretendemos hacer. Al primero de los ejemplos de esta pgina le agregaremos una funcin JavaScript como esta:

<script type="text/javascript"> function cambia_aspecto(elemento, propiedad, valor){ if (elemento=="body"){ comando="document."+elemento+".style."+propiedad+"='"+valor+"'"; eval(comando); alert("Se ha ejecutado:\n\r"+comando); }else{ comando="document.getElementById('"+elemento+"').style."+propiedad+"='"+valor+"'"; eval(comando); alert("Se ha ejecutado:\n\r"+comando); } } </script>

Veamos su comportamiento. La llamada a la funcin incluye tres valores: elemento, propiedad y valor. Como elemento incluiremos el nombre del id cuya apariencia queremos modificar. Como propiedad pondremos el nombre de una de las propiedades de los objetos styleque tenemos enumeradas en este enlace y como valor incluiremos una cadena con el nuevo valor que pretendamos asignar a la propiedad.

En cualquiera de las opciones del condicional if (fjate que la sintaxis es idntica a la de PHP con la diferencia de que en JavaScript los nombres de variable no empiezan por $) hay una variable llamada comando que concatena textos entrecomillados con valores de variables. Podrs observar que en este caso el concatenador no es el . como ocurra en PHP sino el signo +. Con esa sintaxis la variable comando recogera cadenas tales como las que vas a poder leer al ejecutar el ejemplo. Una vez creada la variable ejemplo es necesario aplicarle la funcin JavaScript eval() que es quien realmente ejecuta la intruccin JavaScript contenida en la cadena comando. Hemos incluido una llamada a la funcin alert para poder visualizar el comando ejecutado por javascript. Es evidente que resulta innecesario desde un punto de vista prctico. Por ltimo quiz no est de ms aludir al condicional if. Cuando el objeto cuyo estilo que deseamos cambiar es body el objeto que recoge su estilo es: window.document.body.style cuando se trata de otros elementos que pueden no pertener a colecciones el objeto se identificara de forma distinta ya que habra que recurrir a:window.document.getElementById('nombre_del_elemento').style. La variable elemento nos permitir elegir uno u otro camino dependiendo del valor que contenga.

Cuidado! Cuando se trata de una misma ventana es indiferente utilizar la sintaxis window.document document. Habr otras situaciones en las que ser necesario tomar en consideracin ese asunto.

Una vez incluida la funcin en el documento solo nos faltara poner algn elemento que permita ejecutar esa funcin. En el ejemplo lo hemos hecho mediante los enlaces comentados anteriormente y cuya sintaxis podra ser similar a esta: <a href="javascript:cambia_aspecto('capa1','width','300px');">Cambiar ancho de la capa</a> De esta forma ya estaremos en condiciones de modificar el estilo de cualquier elemento de una pgina web tal como puedes comprobar en este ejemplo.
Ver ejemplo Ver cdigo fuente

Cuidado! La compatibilidad entre navegadores parece ser algo as como la cuadratura del crculo. Si ejecutas el ejemplo anterior en Internet Explorer vers que si cambia el color de fondo del radio. En otros navegadores no ocurrir lo mismo. Es cierto que la mayora de las opciones de estilo son compatibles entre navegadores pero... siempre hay algn pero en algn lugar que rompe la racha de compatibilidad.

La sintaxis de la funcin anterior tiene una alternativa mucho ms cmoda y simple que puedes visualizar aqu debajo:

function cambia_aspecto(elemento, propiedad, valor){ if(elemento=='body'){ window.document.body.style[propiedad]=valor; }else{ window.document.getElementById(elemento).style[propiedad]=valor; } }


Como vers se trata evitar la construccin de la cadena de texto (un poco liosa por aquello de concatenar textos y variables) y utilizar directamente la llamada al objeto escribiendo la variable identificadora dentro del parntesis y colocando un corchete pegado a style para incluir la variable propiedad.

Cuidado! Fjate que los nombres de las variables se incluyen sin comillas tanto en el parntesis como en el corchete. Si prentendemos incluir valores directamente dentro de esos elementos (parntesis y corchete) deberemos ponerlos entre comillas.

Como es lgico, el uso de una u otra funcin no altera para nada el resultado final. Aqu tienes la prueba.

Ver ejemplo

Ver cdigo fuente

Una alternativa ms
Los objetos window.document.body.style y window.document.getElementById(nombre_del_elemento) disponen de otros mtodos que tambin pueden utilizarse para realizar los cambios de diseo comentados anteriormente. Se trata de: objeto.style.getAttribute('atributo') y de: objeto.style.setAttribute('atributo','valor') el primero de los mtodos nos devuelve una cadena conteniendo el valor actual de atributo mientras que el segundo nos permite efectuar modificar un atributo concreto .

<script type="text/javascript"> /* funcion para comprobar los valores actuales de una propiedad */ function comprueba_aspecto(elemento, propiedad){ if(elemento=='body'){ alert(window.document.body.style.getAttribute(propiedad)); }else{ alert(window.document.getElementById(elemento).style.getAttribute(propiedad); } } /* funcion para cambiar los valores actuales de una propiedad */ function cambia_aspecto(elemento, propiedad, valor){ if(elemento=='body'){ window.document.body.style.setAttribute(propiedad,valor); }else{ window.document.getElementById(elemento).style.setAttribute(propiedad,valor); } } </script>
Ver ejemplo Ver cdigo fuente

Algunas consideraciones respecto al ejemplo anterior


Al ejecutar el ejemplo anterior podrs observar un par de cosas interesantes que conviene tener muy en cuenta. Si pulsas el enlace Comprueba colores de fondo inmediatamente despus de cargar la pgina vers que no aparece nada en la ventana del alert. Aunque el fondo por defecto es blanco JavaScript no lo identificar si previamente no ha sido establecido un valor bien por medio de JavaScript o a travs de una definicin de estilo por medio de la sintaxis de CSS. Si observas el cdigo fuente del ejemplo vers que los valores que pasamos como atributos de ancho y alto tienen el formato200px (llevan la unidad inmediatamente despus del valor numrico de la medida) lo que significa que tales valores van a ser siempre una cadena alfanumrica y no un valor numrico. Si pulsas los enlaces Comprueba el ancho o Comprueba el alto observars que detrs del valor numrico aparecen indicadas las unidades (170px, 200px, etctera). Eso significa que, igual que comentamos en el prrafo anterior, el valor devuelto es una cadena que no es susceptible de ser tratada mediante funciones aritmticas. Si se pretende tratar aritmticamente el valor de una propiedad hemos de recurrir al mtodo parseInt('cadena') que extrae el valor numrico entero de la cadena de forma similar a lo que ocurra en PHP con (int)$variable tal como puedes recordar en este enlace. Por tanto el manejo aritmtico de una de estas propiedades requerira un proceso similar a este Extraer el valor numrico del valor de la propiedad por medio de variable=parseInt(propiedad) Operar aritmticamente ese valor (por ejemplo sumndole 10 unidades) variable=variable+10

Modificar el valor de la propiedad agregando al resultado anterior la cadena que especifica el el tipo de unidades. Tendra una sintaxis similar a esta:propiedad=variable+'px'

Moficaciones masivas de aspecto


En todos los ejemplos comentados hasta ahora hemos aludido a modificaciones del aspecto de un elemento especfico identificado por su window.document.ElementById('identificador'). No es la nica opcin. Pueden plantearse situaciones que requieran la modificacin en bloque un conjunto de elementos. Una primera posibilidad podra ser la necesidad de todos los elementos de un tipo determinado (por ejemplo todos los elementos etiquetados como <td>, <li> o <div>) contenidos en una pgina. Para este fin los objetos JavaScript disponen de un mtodo muy interesante. Se trata de getElementsByTagName(etiqueta) que nos devuelve un objeto que contiene todos los elementos cuya etiqueta coincide con el parmetro etiqueta. El nmero de esos elementos puede conocerse por medio de la propiedad length de tal forma que una expresin del tipo getElementsByTagName(etiqueta).length nos devolvera el nmero de elementos definidos por medio de etiqueta Para referirnos a un elemento concreto deberemos utilizar la sintaxis getElementsByTagName(etiqueta)[i] dnde el ndice i es el nmero de orden de cada etiqueta, contado a partir de cero y recorriendo secuencialmente los contenidos de la pgina. Cuando el nombre de la etiqueta se sustituye por un * el asterisco se interpreta como carcter comodn y en consecuencia se efectuar un recuento de todos los elementos o nodos de la pgina independientemente de cual sea su tag o etiqueta. Aqu tienes un ejemplo de una funcin JavaScript que realiza esos recuentos

<script type="text/javascript"> function recuenta(etiqueta){ /* en caso de que etiqueta sea nulo le asigna el valor del comodin * */ if ( etiqueta == null || etiqueta == ''){etiqueta = '*'}; /* el objeto elementos recoger todos elementos cuyo nombre coincide con la variable etiqueta*/ var elementos = document.getElementsByTagName(etiqueta); /* la variable cadena recoger un literal y el nmero de elementos especificado por la propiedad elementos.length Los carcteres '\n\r' son saltos de lnea */ var cadena="Tengo "+elementos.length+'\n\r'; /* por medio de un bucle vamos aadiendo a la variable cadena los nombres de cada uno de los elementos contenidos en el objeto elementos e identificados por el subndice que indica su orden de creacin */ for (i=0;i<elementos.length;i++){ /* la propiedad tagName contiene el nombre del elemento */ cadena+=elementos[i].tagName+'\n\r'; } /* visualizamos la cadena resultante de la consulta */ alert(cadena); } </script>
Si ejecutas este ejemplo y pulsas el enlace Recuenta todos los elementos podrs ver la enumeracin ordenada de los nombres de cada uno de los elementos que contiene la pgina de ejemplo. Presta atencin a las diferentes etiquetas que visualiza y observa que, por ejemplo, contempla TBODY pese a no haber sido especificado expresamente dentro de la etiquet TABLE.
Ver ejemplo Ver cdigo fuente

La funcin anterior tiene su utilidad reducida a la enumeracin de los diferentes elementos de una pgina pero puede ser el soporte de estas otras funciones que si permiten llevar a cabo las pretendidas modificaciones masivas de los elementos de una pgina.

<script type="text/javascript">

/* la funcion recibe tres valores. El nombre de la etiqueta que pretendemos modificar el atributo que queremos cambiar o agregar a esas etiquetas y el valor que se pretende asignar al atributo */ function modifica(etiqueta,atributo,valor){ /* el condicional sustituye los valores nulos o vacios por el comodn */ if ( etiqueta == null || etiqueta == ''){etiqueta = '*'}; /* por comodidad creamos el objeto elementos que incluir todos todos los objetos cuya etiqueta coincida con ese parmetro*/ var elementos = document.getElementsByTagName(etiqueta); /* por medio del bucle recorreremos secuencialmente cada uno de los elementos y mediante el mtodo setAttribute le aplicamos el nuevo valor al atributo indicado */ for (i=0;i<elementos.length;i++){ elementos[i].style.setAttribute(atributo,valor); } } /* esta otra funcion es la alternativa ya comentada de modificacin de una propiedad sin utilizar el mtodo setAttribute. Cualquiera de las dos funciones producir el mismo resultado */ function modifica1(etiqueta,atributo,valor){ if ( etiqueta == null || etiqueta == ''){etiqueta = '*'}; var elementos = document.getElementsByTagName(etiqueta); for (i=0;i<elementos.length;i++){ elementos[i].style[atributo]=valor; } } </script>
Ver ejemplo Ver cdigo fuente

La utilizacin de hojas de estilo en cascada (CSS) lleva implcita la definicin de diferentes clases de estilos que son aplicados a los diferentes elementos de las pginas incluyendo dentro de sus etiquetas el atributo class="nombre_de_la_clase". Si en el ejemplo anterior hacamos un modificacin masiva de todas las etiquetas de un determinado tipo es posible que en momentos determinados tratemos de restringir esa modificacin a las etiquetas de una clase determinada. Esta posibilidad es propiciada por la propiedad objeto.className que nos devolver el nombre de la clase (si ha sido establecida) correspondiente a un objeto (etiqueta html) determinado. En caso de no haberse establecido esa propiedad tendr valor null o cadena vaca. Contemplar esta nueva posibilidad implicar readecuar las funciones del ejemplo anterior a este nuevo escenario.

<script type="text/javascript"> /* agregamos el nuevo parmetro clase a la funcin anterior */ function modifica(etiqueta,clase,atributo,valor){ if ( etiqueta == null || etiqueta == ''){etiqueta = '*'}; var elementos = document.getElementsByTagName(etiqueta); for (i=0;i<elementos.length;i++){ /* establecemos la condicin de que para modificar el atributo coincida la clase con el valor recibido en ese parmetro o que la funcin haya sido invocada asignndole a clase un valor nulo o una cadena vacia en cuyo caso afectara a todos los elementos que no tuvieran una clase establecida*/ if(elementos[i].className==clase || clase==null || clase==''){ elementos[i].style[atributo]=valor; }

} } /* igual que en el ejemplo precedente esta funcin es una alternativa a la anterior */ function modifica1(etiqueta,clase,atributo,valor){ if ( etiqueta == null || etiqueta == ''){etiqueta = '*'}; var elementos = document.getElementsByTagName(etiqueta); for (i=0;i<elementos.length;i++){ if (elementos[i].className==clase || clase==null || clase==''){ elementos[i].style[atributo]=valor; } } } </script>
Ver ejemplo Ver cdigo fuente

Aun puede darse un poco ms de versatilidad a la opcin de llevar a cabo modificaciones masivas de estilos. En los ejemplos anteriores la bsqueda de etiquetas y/o clases la realizabamos en document, es decir, a lo largo de toda la pgina visualizada en la ventana actual. Es posible que en determinadas situaciones nos interese realizar la bsqueda y modificacin slo en una parte del documento. Esa posibilidad nos obligara a llevar a cabo una nueva ampliacin en la funciones modificadoras que hemos venido manejando en los ejemplos anteriores. Aqu tienes el cdigo fuente.

<script type="text/javascript"> /* la funcion recibe ahora un quinto parmetro que hemos llamado contenedor*/ function modifica(contenedor,etiqueta,clase,atributo,valor){ if ( etiqueta == null || etiqueta == ''){etiqueta = '*'}; /* si el contenedor es null o vacio entendemos que nos referimos a todo el documento */ if (contenedor==null || contenedor==''){ var elementos = document.getElementsByTagName(etiqueta); }else{ /*cuando el contenedor no es vacio entendemos que nos referimos al elemento de documento cuyo nombre identificador unico (id) es contenedor. La bsqueda de los elementos modificable la realizaremos dentro de esa parte del del documento (objeto cuya es etiqueta es etiqueta y contenidos dentro de un elemento cuyo id es el valor de la variable contenedor) */ var elementos=document.getElementById(contenedor).getElementsByTagName(etiqueta); } for (i=0;i<elementos.length;i++){ if(elementos[i].className==clase || clase==null || clase==''){ elementos[i].style[atributo]=valor; } } } /* las modificaciones son idnticas a las descritas para la funcin anterior que, como siempre, es una opcin alternativa a esta */ function modifica1(contenedor,etiqueta,clase,atributo,valor){ if ( etiqueta == null || etiqueta == ''){etiqueta = '*'}; if (contenedor==null || contenedor==''){ var elementos = document.getElementsByTagName(etiqueta); }else{ var elementos=document.getElementById(contenedor).getElementsByTagName(etiqueta); } for (i=0;i<elementos.length;i++){ if (elementos[i].className==clase || clase==null || clase==''){ elementos[i].style[atributo]=valor;

} } } </script>
Ver ejemplo Ver cdigo fuente

Eventos en JavaScript Cmo activar las modificaciones?


En la pgina anterior hemos visto como modificar los aspectos de los elementos de una pgina por medio de javascript. En todos los ejemplos all manejados la ejecucin de las funciones requera pulsar sobre un enlace clsico con su sintaxis habitual de: <a href="javascript:nombre_de_la_funcion()">texto del enlace </a> Esta no es la nica forma posible de hacerlo. En javascript existen una serie de eventos (acciones llevadas a cabo por el usuario) que pueden ser utilizados para disparar la ejecucin de una funcin. Veamos los nombres de algunos, sus significados y su forma de utilizacin sobre los textos de un enlace. Su sintaxis ms recomendada es: <a href="javascript:void(0)" manejador="nombre_de_la_funcion(parametros)">texto del enlace</a> cuyo ejemplo de utilizacin requiere una sintaxis como esta <a href="javascript:void(0)" onClick="alert('Has hecho clic')"></a> y cuyo funcionamiento puedes comprobarlo al hacer clic sobre el enlace. Existen otras opciones tales como <a href="#" manejador="nombre_de_la_funcion(parametros)">texto del enlace</a> y cuyo ejemplo de uso puedes ver en este cdigo y en este enlace <a href="#" onClick="alert('Has hecho clic')"></a> La diferencia entre ambas opciones es que en la primera se invoca la ejecucin de la funcin javascript void(0) (dara lo mismo si en vez de cero llevara cualquier otro valor numrico) que devuelve un valor nulo para href con lo cual no se recarga la pgina. Si escribiramos algo como: <a href="javascript:void()" onClick="alert('Has hecho clic')"></a> javascript nos dara un error de sintaxis (void requiere que incluyamos un valor dentro del parntesis) y si intentramos algo como <a href="" onClick="alert('Has hecho clic')"></a> podrs observar que si bien se produce el mensaje de alerta posteriormente intenta cargarse una pgina sin nombre y eso nos conducir a un error de pgina no encontrada o a la eventual pgina de error que por defecto hayamos podido establecer en .htaccess. El uso del formato <a href="#" onClick="alert('Has hecho clic')"></a> est bastante extendido aunque en puridad suele aconsejarse la opcin void(0). Cuando se usa esta alternativa lo que ocurre es que al pulsar se intentar recargar la pgina redirigindola a un ancla de la misma (anchor) sin nombre. Podremos observar que en la barra de direcciones aparece la direccin de la pgina seguida de #

Eventos del ratn sobre textos de hiperenlaces


Adems del ya comentado existen los siguientes manejadores para eventos del ratn: onDblClick El evento se dispara al hacer doble clic con el ratn sobre el texto del enlace Ejemplo: <a href="javascript:void(0)" onDblClick="alert('Has hecho doble clic')"></a> onMouseOver El evento se dispara al situar el puntero del ratn encima del texto del enlace Ejemplo: <a href="javascript:void(0)" onMouseOver="alert('Has puesto el ratn encima')"></a> onMouseOut El evento se dispara al quitar el puntero del ratn de encima del texto del enlace Ejemplo: <a href="javascript:void(0)" onMouseOut="alert('Has quitado el ratn de encima')"></a> onMouseDown El evento se dispara en el momento en que se pulsa cualquier botn del ratn encima del texto del enlace Ejemplo: <a href="javascript:void(0)" onMouseDown="alert('Me disparo cuando pulsas el ratn sobre el texto')"></a>

onMouseUp El evento se dispara en el momento en que se suelta cualquier botn del ratn encima del encima del texto del enlace Ejemplo: <a href="javascript:void(0)" onMouseUp="alert('Me disparo cuando sueltas botn el ratn sobre el texto')"></a>

Eventos del ratn sobre imgenes y botones


De igual forma que hemos hecho utilizando textos con reas sensibles a los eventos tambin podramos haber utilizado imgenes y/o elementos de formularios

Eventos del ratn y el teclado sobre campos de formulario tipo TEXT


Veamos que eventos se pueden manejar en los distintos elementos de un formulario. Empezaremos por los de tipo="text". Adems de manejar los eventos comentados anteriormente tal como puedes ver en estos ejemplos .
haz click aq haz doble click a pon el raton enc quita el raton pulsa aqui dentr suelta el raton

tanbin maneja los siguientes: onChange El evento se dispara al salir de campo de texto depus de haber modificado su contenido Ejemplo: onFocus El evento se dispara al tomar el foco que equivale a situar el cursor dentro del campo de texto bien mediante el ratn o desplazndose entre campos por medio de la tecla de tabulacin Ejemplo: onBlur El evento se dispara al perder el foco que equivale a sacar el cursor del campo de texto bien mediante el ratn o desplazndose entre campos por medio de la tecla de tabulacin Ejemplo: onSelect El evento se dispara al seleccionar texto dentro del campo Ejemplo: onKeyPress El evento se dispara al mantener pulsada una tecla cuando el cursor est dentro del campo Ejemplo: onKeyUp El evento se dispara al soltar una tecla pulsada cuando el cursor est dentro del campo Ejemplo:
pulsa y suelta mantn pulsada selecciona una parte escribe aqui

onKeyDown El evento se dispara al pulsar una tecla cuando el cursor est dentro del campo Ejemplo:
pulsa una tecla

onKeyPress (leyendo el valor de la tecla pulsada) El evento se dispara al mantener pulsada una tecla cuando el cursor est dentro del campo y el alert muestra el resultado de ejecutar una funcin javascript que captura el valor de la tecla pulsada. Esa funcion tiene la forma siguiente:

<script type="text/javascript"> function captura_teclado(e){ var numero_de_tecla_pulsada; var caracter_de_la_tecla_pulsada; if(window.event){ //cosas de IE var numero_de_tecla_pulsada = e.keyCode //recoge en IE el valor ASCII de la tecla } else if(e.which){ // Cosas Netscape/Firefox/Opera var numero_de_tecla_pulsada = e.which //recoge valor ASCII en otros navegadores } /* obtiene el caracter correspondiente al codigo ASCII recogido */ caracter_de_la_tecla_pulsada = String.fromCharCode(numero_de_tecla_pulsada); /* devuelve el valor del caracter correpondiente a la tecla pulsada */ return caracter_de_la_tecla_pulsada; } </script>
Ejemplo (teclea dentro del campo):

Eventos del ratn sobre input type="radio"


onChange El evento se dispara al producirse un cambio en el elemento. Se comprueba el cambio cuando el elemento pierde el foco. Ejemplo: onClick El evento se dispara al hacer clic sobre la opcin Ejemplo: onFocus El evento se dispara al tomar el foco. Ejemplo: onBlur El evento se dispara al perder el foco. Ejemplo: Si No Si No Si No Si No

Eventos del ratn sobre input type="checkbox"


onChange El evento se dispara al producirse un cambio en el elemento. Se comprueba el cambio cuando el elemento pierde el foco. Ejemplo: onClick Si No

El evento se dispara al hacer clic sobre la opcin Ejemplo: onFocus El evento se dispara al tomar el foco. Ejemplo: onBlur El evento se dispara al perder el foco. Ejemplo: Si No Si No Si No

Eventos del ratn sobre select


onChange El evento se dispara al producirse un cambio en el elemento. Se comprueba el cambio cuando el elemento pierde el foco. Ejemplo: onFocus El evento se dispara al tomar el foco. Ejemplo: onBlur El evento se dispara al perder el foco. Ejemplo:

Eventos del ratn y el teclado sobre campos de formulario tipo TEXTAREA


Maneja exactamente los mismos eventos que el input type=text tal como puedes ver en estos ejemplos .

tanbin maneja los siguientes: onChange El evento se dispara al salir de campo de texto depus de haber modificado su contenido

Ejemplo: onFocus El evento se dispara al tomar el foco que equivale a situar el cursor dentro del campo de texto bien mediante el ratn o desplazndose entre campos por medio de la tecla de tabulacin

Ejemplo: onBlur El evento se dispara al perder el foco que equivale a sacar el cursor del campo de texto bien mediante el ratn o desplazndose entre campos por medio de la tecla de tabulacin

Ejemplo: onSelect El evento se dispara al seleccionar texto dentro del campo

Ejemplo: onKeyPress El evento se dispara al mantener pulsada una tecla cuando el cursor est dentro del campo

Ejemplo: onKeyUp El evento se dispara al soltar una tecla pulsada cuando el cursor est dentro del campo

Ejemplo: onKeyDown El evento se dispara al pulsar una tecla cuando el cursor est dentro del campo

Ejemplo: onKeyPress (leyendo el valor de la tecla pulsada) El evento se dispara al mantener pulsada una tecla cuando el cursor est dentro del campo y el alert muestra el resultado de ejecutar una funcin javascript que captura el valor de la tecla pulsada. Esa funcion tiene la forma siguiente:

<script type="text/javascript"> function captura_teclado(e){ var numero_de_tecla_pulsada; var caracter_de_la_tecla_pulsada;

if(window.event){ //cosas de IE var numero_de_tecla_pulsada = e.keyCode //recoge en IE el valor ASCII de la tecla } else if(e.which){ // Cosas Netscape/Firefox/Opera var numero_de_tecla_pulsada = e.which //recoge valor ASCII en otros navegadores } /* obtiene el caracter correspondiente al codigo ASCII recogido */ caracter_de_la_tecla_pulsada = String.fromCharCode(numero_de_tecla_pulsada); /* devuelve el valor del caracter correpondiente a la tecla pulsada */ return caracter_de_la_tecla_pulsada; } </script>

Ejemplo (teclea dentro del campo):

El botn submit
No presenta mayores complicaciones. Es un input type button (tambin podra ser una imagen que lleva asociado el evento onClick que lleva implcita la funcin submit() (enviar) el formulario que se indica.
Haz clic Haz doble clic Quita el ratn Pulsa cualquier botn Suelta cualquier boton

Un ejemplo de uso de eventos


En este ejemplo ya contemplado en la pgina anterior hemos modificado nicamente la forma de modificar los diferentes valores de los elementos. Ahora usaremos algunos de los eventos aqu descritos y comprobaremos que se les puede asociar ms de una instruccin javascript (observa el cdigo fuente de los que requieren pulsar una tecla determinada) y, observa tambin, que un mismo elemento puede tener asociadas acciones distintas para dos eventos distintos. Tal es el caso de la opcin que reduce la imagen al colocar el ratn encima y recupera el tamao al quitarlo.
Ejecutar ejemplo Ver cdigo fuente

Cambios en los contenidos de una pgina Cambios de contenido de los elementos de una pgina
Los contenidos de los elementos de una pgina web (vistos como objetos JavaScript) son recogidos como valores en una de sus propiedades. El problema es que dependiendo del tipo objeto la propiedad ser distina y por tanto habr que tomar en consideracin este aspecto. A modo de ejemplo, para conocer el contenido de un elemento del tipo div tendramos que utilizar la propiedad innerHTML de modo que: document.getElementById('identificador_del_div').innerHTML contendra el valor de ese elemento. Igual que hacamos en con las propiedades de los objetos en PHP la lectura de ese valor podra hacerse por medio de: document.getElementById('identificador_del_div').innerHTML=nuevo_contenido
Ver ejemplo Ver cdigo fuente

Intentaremos incluir en las lneas siguientes una lista de los diferentes elementos de una pgina y de las propiedades que permiten modificar sus contenidos. Objetos con las etiquetas: <div>, <p>, <td>, <ul>, <li>, <tr>*, <table>* (Las sealadas con * parecen no funcionar en Internet
Explorer)

La lectura y/o modificacin de los contenidos de los objetos de estos tipos puede hacerse por medio de la propiedadinnerHTML. Si un objeto contiene otros objetos el valor de la propiedad innerHTML incluir a estos. Puedes verlo en este ejemplo.
Ver ejemplo Ver cdigo fuente

Para esas lecturas y/o modificaciones pueden utilizarse funciones similares a estas:

<script type="text/javascript"> function lee (identificador){ alert(document.getElementById(identificador).innerHTML); } function cambia (identificador,nuevo_valor){ document.getElementById(identificador).innerHTML=nuevo_valor; alert(document.getElementById(identificador).innerHTML); } </script>
Aqu puedes ver un ejemplo de utilizacin en los diferentes elementos.
Ver ejemplo Ver cdigo fuente

Objetos con las etiquetas: <img> o <iframe>(Las sealadas con * parecen no funcionar en Internet Explorer) La lectura y/o modificacin de los contenidos de los objetos de estos tipos puede hacerse por medio de la propiedad src. Puedes verlo en este ejemplo.
Ver ejemplo Ver cdigo fuente

Para esas lecturas y/o modificaciones pueden utilizarse funciones similares a las contempladas en el prrafo anterior. Una ligera modificacin en su estructura, introduciendo un nuevo parmetro (tipo) y un operador condicional podr permitirnos utilizar la misma funcin en ambas modalidades:

<script type="text/javascript"> function lee (identificador,tipo){ if(tipo=='imagen' || tipo=='iframe'){//condicion particular alert(document.getElementById(identificador).src); }else if(tipo=='' || tipo==null){// condicion general alert(document.getElementById(identificador).innerHTML); } } function cambia (identificador,nuevo_valor,tipo){ if(tipo=='imagen' || tipo=='iframe'){// condicion particular document.getElementById(identificador).src=nuevo_valor; alert(document.getElementById(identificador).src); }else if(tipo=='' || tipo==null){// condicion general document.getElementById(identificador).innerHTML=nuevo_valor; alert(document.getElementById(identificador).innerHTML); } } </script>
Aqu puedes ver un ejemplo de utilizacin de estas nuevas funciones con los diferentes elementos.
Ver ejemplo Ver cdigo fuente

Objetos con la etiqueta: <object> que permite incluir como tal: imgenes, vdeos, sonidos o, de forma similar a iframe, pginas web.

El uso de objetos parece que va ser la opcin de futuro. Sin embargo no es fcil superar los obstculos que actualmente se plantean cuando se trata de utilizar cdigo compatible entre los navegadores ms usados. Parafraseando a don Quijote diremos aquello de Con la iglesia hemos dado, Sancho aunque este caso no se trate de los muros de la parroquial de El Toboso sino con las diferentes maneras de interpretar los objetos por parte de los distintos navegadores. Intentaremos analizar cada uno de los tipos (tipos MIME) de contenidos de los objetos. Imgenes Este tipo de objetos se incluyen en los documentos mediante la sintaxis: <object data="ruta y nombre del fichero" class="(opcional)" style="(opcional)" id="(opcional)"></object> Como podrs observar el nico atributo de la etiqueta object que tiene condicin de imprescindible es data. Loa restantes class, style (hacen alusin a los estilos aplicables) e id son opcionales aunque para los fines aqu propuestos (modificacin de contenidos) el atributo id es imprescindible. El caso de las imgenes es el que ofrece mayor compatibilidad entre navegadores. Para leer datos de la imagen actual bastara con leer la propiedad data. Para modificarlos sera suficiente modificar el valor de esa propiedad tal como puedes ver en este ejemplo. Como podrs observar no hemos incluido el tipo MIME ya que, al parecer, los navegadores habituales (Firefox, Opera, Chrome, IE y Safari) son capaces de gestionar imgenes en los formatos ms frecuentes (jpg, png, gif) sin necesidad de especificar su tipo MIME concreto.

Ver ejemplo

Ver cdigo fuente

Vdeos La proliferacin de formatos de vdeo y las especificaciones poco estandarizadas de los navegadores hacen que la gestin de este tipo de archivo resulte un autntico rompecabezas. Ante esta situacin hemos optado por la calle del medio que no es otra cosa que tratar de insertar los vdeos en un formato nico (el de extensin .swf por ser uno de los ms populares) y sugerir la transformacin del formato cuando nuestros originales procedan de fuentes en otro formato. Existen aplicaciones gratuitas que permiten efectuar ese tipo de transformaciones sin dificultad alguna. Considerando ese formato la inclusin de un fichero de vdeo requerira el uso de una sintaxis como esta: <object data="nombre del video" type="application/x-shockwave-flash" width="ancho" height="alto" id="(opc)"> <param name="movie" value="nombre del video" /> <param name="quality" value="best" /> <param name="bgcolor" value="#cccccc" /> <param name="scale" value="noScale" /> <param name="play" value="false" /> <param name="loop" value="0" /> </object> Los valores marcados en rojo son obligatorios y los incluidos en cursiva opcionales. Podrs observar una informacin aparentemente redundante. El nombre del vdeo se incluye como valor de parmetro movie (por compatibilidad con Internet Explorer) y como data (por compatibilidad con los restantes navegadores habituales). Los parmetros play pueden establecer con un valor booleano (cuando se configura como true la reproduccin de vdeo comenzar inmediatamente despus de cargarse la pgina, si se hace false ser necesario que el usuario la active de forma manual). Cuando se trata de loop si se le asigna el valor false la reproduccin se detendr en el momento en que se haya llegado al final del mismo. Si se configura como true al llegar al final de vdeo empezar una nueva reproduccin del mismo. En cuanto al parmetro scale admite como valores: default (permite visualizar sin distorsin el vdeo completo ajustndolo a las dimensiones especificadas en el style del mismo. Las zonas no ocupadas por la imagen aparecern del color especificado en el parmetro bgcolor), noborder (ajusta el tamao del vdeo para que ocupe todo el rea especificada sin distorsionar la imagen. Para evitar la distorsin recortara la imagen si fuera preciso),exactfit (rellena todo el res especificada distorsionando la imagen si fuera necesario) o noscale (impide la ampliacin de la imagen para ajustarse al area especificada. ) El parmetro quality admite como valores: low (antepone la velocidad de reproduccin al aspecto y nunca suaviza las imgenes), autolow (prioriza la velocidad de reproduccin pero intenta mejorar el aspecto y suavizar las imgenes siempre que las caractersticas del hardware lo permitan), autohigh (establece igual prioridad inicial a velocidad y calidad. Si la visualizacin se ralentiza mejora la velocidad de reproduccin sacrificando el suavizado de la imagen), medium (es una calidad intermedia entre la baja -Low- y la alta -high-), high (prioriza el aspecto a la velocidad de reproduccin) o best (proporciona la mejor calidad de visualizacin sin tener en cuenta la velocidad de reproduccin). Las modificaciones, cuando se trata de compatibilizar navegadores, s que abren una ventana a la demencia. Cuando se trata de modificar los parmetros width heigth no surge ningn problema aparente. Basta con

utilizardocument.getElementById('identificador').setAttribute('width', nuevo valor). Si intentamos, mediante el mismo procedimiento modificar otros parmetros veremos que esa opcin solo funciona en Internet Explorer. Pero, sin duda, lo ms esperpntico es cambiar el vdeo que se visualiza. Ah si que hay una modalidad para cada una de las opciones. Cuando se trata de Internet Explorer se logra mediante:document.getElementById(identificador).movie=nuevo_valor y cuando una piensa que para otros navegadores la solucin podra ser del tipo document.getElementById(identificador).data=nuevo_valor la ilusin se desvanece cuando uno intenta probar esa opcin en Chrome. All no funciona. Una solucin (ms bien debera decir una chapuza) puede ser esta: Incluimos el objeto dentro de una div Cuando el navegador sea Internet Explores modificamos el parmetro movie del objeto flash Cuando el navegador no sea Internet Explorer reescribimos la totalidad del contenido del contenedor divmodificando en ese proceso el valor del parmetro data. Una de las mltiples formas (seguro que no la ms eficiente) podra ser la utilizacin de una funcin JavaScript similar a esta:

/* la funcion recibe cinco parmetros: contenedor: Recogera el nombre de la div creada para contener el objeto vdeo. identificador: es el identificador del objeto video tipo: es un parmetro para diferenciar distintos tipos de objetos atributo: recoge el nombre del atributo a modificar (data en este caso) nuevo_valor: ser el nombre, extensin y ruta del nuevo video */ function cambia_video (contenedor,identificador,tipo,atributo,nuevo_valor){ if(tipo=='flash'){ /* Comprobado que el tipo es flash, comprobamos la propiedad appName del objeto navigator si su valor es Microsoft Internet Explorer ser suficiente modificar el valor del parmetro movie. */ if(navigator.appName=="Microsoft Internet Explorer"){ document.getElementById(identificador).movie=nuevo_valor; }else{ /* Para navegadores diferentes a IE podemos unificar le proceso leyendo el contenido de la div contenedora del objeto y recogiendo su contenido en una variable que aqu llamamos anterior */ var anterior=document.getElementById(contenedor).innerHTML; /* Lo que debemos cambiar es el valor del atributo data (lo hemos recogido del parmetro atributo) asignndole por medio del signo = el nuevo valor que incluimos entre comillas. */ nuevo_valor=atributo+"=\""+nuevo_valor+"\""; /* Tenemos que sustitur el data anterior por el nuevo_valor. Creamos un nuevo objeto (new RegExp) expresin regular que estar formada por el atributo (data en nuestro caso) seguido de un signo igual. Detrs estar el el nombre actual (na serie de caracteres que identificaremos por medio de los metacaracteres (.*) y acabados en unas comillas. Invertimos la codicia (para delimitar en las primeras comillas que encuentre) por medio del metacaracter ? que sigue al * Como segundo parmetro incluimos el modificador "i" que hace la expresin insensible a maysculas/minsculas*/ valor_a_reemplazar=new RegExp(atributo+'=.*?"',"i"); /* aplicamos el mtodo replace a la cadena que contiene los datos actuales pasndole dos parmetros: valor a reemplazar y nuevo valor. El resultado ser la cadena ya actualizada */ var renovado=anterior.replace(valor_a_reemplazar,nuevo_valor); /* ya podemos modificar el elemento contenor insertndole sus nuevos valores */ document.getElementById(contenedor).innerHTML=renovado; }

} }
No podemos olvidarnos de que los vdeos incluidos por este procedimiento no disponen de elementos de control. Afortunadamente la gestin de esos controles es compatible con los diferentes navegadores por lo cual bastara con ejecutar alguno de estoy mtodos: objeto_flash.Play() (iniciara la reproduccin del vdeo),objeto_flash.Stop()(detendra la reproduccin) y objeto_flash.Rewind() (rebobinara el vdeo y lo devolvera a la posicin inicial) Considerando todas estas variables podramos llegar a algo como lo que puedes ver en este ejemplo.
Ver ejemplo Ver cdigo fuente

Pginas web La inclusin de pginas web en en objetos no presenta grandes complicaciones sintcticas. Sera suficiente una sintaxis similar a esta: <object type="text/html" data="direccion" width="250" height="250" id="identificador"> </object> Ahora el tipo MIME sera text/html (adecuado a su contenido) y el parmetro data nos permitira especificar la direccin URL. Parecera que la modificacin de los contenidos pasara por la modificacin del parmetro data. Y es cierto, solo que a medias. Hay navegadores que no responden a esa modificacin y la solucin (al menos una de las soluciones, seguramente ni la nica ni la mejor) es hacer algo similar a lo comentado para el caso del vdeo. Incluyendo el objeto dentro de una div contenedora y reescribiendo el contenido de esa div parece ser que se logra la ansiada compatibilidad entre navegadores. La funcin que permitiera el cambio de contenidos podra ser el resultado de una modificacin de la comentada anteriormente. Ahora puede aplicarse un procedimiento nico razn por la cual ya no es preciso diferenciar por nombre del navegador.

function cambia (contenedor,identificador,tipo,atributo,nuevo_valor){ if(tipo=='flash'){ if(navigator.appName=="Microsoft Internet Explorer"){ document.getElementById(identificador).movie=nuevo_valor }else{ var anterior=document.getElementById(contenedor).innerHTML; nuevo_valor=atributo+"=\""+nuevo_valor+"\""; valor_a_reemplazar=new RegExp(atributo+'=.*?"',"i"); var renovado=anterior.replace(valor_a_reemplazar,nuevo_valor); document.getElementById(contenedor).innerHTML=renovado; } } if(tipo=='web'){ var anterior=document.getElementById(contenedor).innerHTML; nuevo_valor=atributo+"=\""+nuevo_valor+"\""; valor_a_reemplazar=new RegExp(atributo+'=.*?"',"i"); var renovado=anterior.replace(valor_a_reemplazar,nuevo_valor); document.getElementById(contenedor).innerHTML=renovado; } }
Ver ejemplo Ver cdigo fuente

Ficheros de sonido mp3 La inclusin y reproduccin de ficheros de sonido en una web vuelve a abrir todo un mundo de opciones y tambin de incompatibilidades. Por una parte los formatos y por otra las extensiones (plug-in) multimedia del navegador que va a mostrar los paneles de control en la pgina web. La solucin chapuza (no es la ms elegante pero probablemente nos retrasar un poco la demencia) podra ser la unificacin. Podramos pensar en unificar el formato de los ficheros de sonido. Existen aplicaciones gratuitas tales como pazera o Audacity que permiten la edicin y el cambio de formato de audio. No hemos inclinado por unificar en formato mp3. El siguiente punto de unificacin habr de ser el plug-in reproductor. En este aspecto una opcin que nos parece razonable y prctica es la desarrollada en flash por alsacreations.fr bajo licencia Creative Commons y que, tal como puede verse en su pgina principal, ofrecen varias opciones de paneles de control para el reproductor mp3. La utilizacin de esta opcin requiere obtener el fichero dewplayer.zip y descomprimirlo en alguna parte del servidor. Ese archivo contiene una serie de ficheros con extensin .swf (son los distintos reproductores) e incluso unas instrucciones de uso.

La utilizacin de este tipo de objetos requiere una sintaxis como esta: <object type="application/x-shockwave-flash" data="(ver comentario)" width="ancho" height="alto" id="ident"> <param name="movie" value="(ver comentario)" /> </object> La compatibilidad famosa nos obliga a incluir, junto con el tipo MIME especfico de los ficheros flash, el parmetromovie con un value idntico al requerido por data. Adems de eso deberemos indicar el ancho y alto de visualizacin de plugin .swf (las dimensiones para las diferentes opciones puedes verlas en su pgina web). Los parmetros data y movie requieren particular atencin. Estn formados por: la ruta nombre y extension de fichero .swf que vayamos a utilizar como reproductor, seguida de ?mp3= y de la ruta, nombre y extensin de fichero mp3 que se pretende reproducir. Resultara una expresin del tipo: /reproductores/dewplayer.swf?mp3=/sonidos/mi_sonido.mp3 El cambio de fichero a reproducir requerira modificar el valor de movie en el caso de Internet Explorer o data en los restantes navegadores. Por lo que hemos podido comprobar, en este caso no es necesario recurrir a la inclusin del objeto en una div contenedora. Basta con asignar nuevo valor al parmetro data. Aqu tienes un ejemplo.
Ver ejemplo Ver cdigo fuente

Cambios en los valores de los elementos de los formularios


Los diferentes elementos de los formularios incluyen, adems de sus valores, algunas propiedades susceptibles de ser modificables por el usuario. Intentaremos ir viendo los diferentes elementos y sus propiedades modificables pero antes vamos a echar un vistazo a las diferentes formas de identificar los elementos de los formularios.

Como identificar un elemento de un formulario?


Los elementos de los formularios suelen tener como finalidad bsica la transferencia de informacin a un servidor. Para que esa informacin pueda ser recogida es imprescindible que cada uno de los elementos incluya el atributo name tal como hemos comentado en esta pgina. Por tanto ser requisito que los diferentes campos tengan, al menos, una estructura como esta: <input type="text" name="obligatorio" /> <input type="password" name="obligatorio" /> <textarea name="obligatorio" /></textarea> <select name="obligatorio" /><option>aaa</option>/><option>bbb</option></select> <input type="radio" name="obligatorio" /> <input type="checkbox" name="obligatorio" /> Adems de incluir el atributo name es imprescindible que los valores de los name sean distintos. De lo contrario al enviar los formularios tendramos el problema de que el valor de ltimo de los incluidos en el formulario sobrescribira a los previos. Puedes verlo en este ejemplo:
Ver ejemplo Ver cdigo fuente

La nica excepcin a esta obligatoriedad son los elementos de opcin (los input type="radio") que como puedes rescordar aqu utilizan ese name comn para formar agrupaciones. Adems del name podramos incluir en cada uno de los elementos un identificador nico utilizando el archimencionado atributoname. Aunque son perfectamente compatibles ambos atributos no resulta imprescindible,para nuestros propsitos, el uso de id. En cualquier caso, supongamos que disponemos de ambos atributos en una sintaxis tal como esta: <input type="text" name="obligatorio" id="identificador_unico" /> <input type="password" id="identificador_unico"name="obligatorio" /> <textarea id="identificador_unico"name="obligatorio" /></textarea> <select name="obligatorio" id="identificador_unico"/> <option id="identificador_unico">aaa</option>/>

<option id="identificador_unico">bbb</option> </select> <input type="radio" name="obligatorio" id="identificador_unico"/> <input type="checkbox" name="obligatorio" id="identificador_unico"/> Como vers hemos puesto indentificadore (nicos) en todo, incluso en lo sealado como option. Para aludir a los elementos podemoas hacerlo ahora mediante el ya comentado: document.getElementById('nombre del identificador') y podremos hacerlo por medio de una de estas otras dos opciones: document.getElementsByName('nombre').item(0) o document.getElementsByName('nombre')[0] El mtodo getElementById devuelve siempre un objeto nico. Por el contrario, el mtodo getElementsByName devuelvesiempre un array (incluso en los casos en lo que el array contenga un nico elemento). Por esa razn es necesario ser ms explcito e indicar a cual de los elementos del array nos referimos. Eso puede hacerse por medio del ndice del array especificado como [indice] o mediante .item(indice). En este segundo supuesto se utiliza siempre el punto seguido de la palabra item y, entre parntesis, el ndice del array. Como es lgico en los casos en los que el array contenga un solo elemento el ndice ser cero.

Cuidado! Ten cuidado con la sintaxis. En un caso se usa getElementById y en el otro getElementsByName. No siempre prestamos a la s toda la atencin que requiere.

Qu y cmo modificar?
Input type text, password y textarea Este tipo de elementos de los formularios permiten establecer y/o modificar los siguientes atributos: disabled Este atributo puede asignarse incluyendo el atributo disabled="disabled" en la etiqueta <text> o en cualquier otra que defina un elemento. Puede activarse o desactivarse por medio de JavaScript utilizando una de las sintaxis siguientes: document.getElementById('identificador').disabled=true; document.getElementById('identificador').disabled=false; document.getElementsByName('nombre')[0].disabled=true; document.getElementsByName('nombre')[0].disabled=false; document.getElementsByName('nombre').item(0).disabled=true; document.getElementsByName('nombre')item(0).disabled=false; Cuando est activado impide la modificacin de los contenidos de esos campos del formulario y, adems, sus valores no son enviados junto con el formulario. La variable identificada por el name de su formulario no ser recibida por el servidor. readOnly (cuidado con la sintaxis, JavaScript diferencia maysculas de minsculas) Este atributo puede asignarse incluyendo el atributo readonly="readonly" en la etiqueta <text> o en cualquier otra que defina un elemento. Puede activarse o desactivarse por medio de JavaScript utilizando una de las sintaxis siguientes: document.getElementById('identificador').readOnly=true; document.getElementById('identificador').readOnly=false; document.getElementsByName('nombre')[0].readOnly=true; document.getElementsByName('nombre')[0].readOnly=false; document.getElementsByName('nombre').item(0).readOnly=true; document.getElementsByName('nombre')item(0).readOnly=false; Cuando est activado tambin impide la modificacin de los contenidos de esos campos del formulario pero, a diferencia de disabled permite el envo de los valores que contenga incluso cuando ese valor sea una cadena vaca.

value Este atributo puede asignarse incluyendo el atributo value="valor preasignado" en la etiqueta <text> o en cualquier otra que defina un elemento. Puede modificarsr por medio de JavaScript utilizando una de las sintaxis siguientes: document.getElementById('identificador').value='nuevo valor'; document.getElementsByName('nombre')[0].value='nuevo valor'; document.getElementsByName('nombre').item(0).value='nuevo valor';
Ver ejemplo Ver cdigo fuente

Input type select Tambin admite, y con las mismas consecuencias, la utilizacin de disabled. Adems tiene una peculiaridad importante. Las diferentes posibilidades de eleccin se incluyen en el formulario dentro de etiquetas <option></option> Para referirnos desde JavaScript a una opcin concreta tenemos varias posibilidades: document.getElementById('identificador_del_select').options[indice] La etiqueta select debe llevar un id. Las options constituyen un array escalar cuyos ndices (empiezan en cero) y que mantiene el mismo orden en que se van insertando las option. La prima tendr ndice cero, la segunda uno, etctera. document.getElementsByName('name_del_selector')[0].options[indice] En este supuesto identificamos el select por su name. Tal como hemos comentado anteriormente el resultado se representa mediante un array del que extraemos el primer elemento [0] (suponemos un solo select con ese nombre, de ah el cero). Con este paso tenemos completada la primera parte de la eleccin. Hay que aadirle a cual de las opciones hacemos referencia y para ello usamos options[indice] igual que en el caso anterior. document.getElementById('identificador_especifico_de_la opcion') Este ltimo supuesto requiere que dentro de la etiqueta <option> se haya incluido un id para asignarle un identificador nico En el elemento elegido es factible seleccionar uno de estos atributos: value Por medio de esta propiedad y con una de estas sintaxis document.getElementById('identificador').options[indice].value='nuevo valor'; document.getElementsByName('nombre_del_select')[0].options[indice].value='nuevo valor'; document.getElementsByName('identificador_de_la_opcion').value='nuevo valor'; se permite modificar el valor de una opcin. El cambio no afecta a la leyenda visualizada en pantalla pero s modifica el contenido transferido al servidor. Recuerda que la leyenda es considerada nicamente valor por defecto cuando no se asigna ningn value dentro de la etiqueta option text Por medio de esta propiedad y con una de estas sintaxis document.getElementById('identificador').options[indice].text='nuevo texto'; document.getElementsByName('nombre_del_select')[0].options[indice].text='nuevo texto'; document.getElementsByName('identificador_de_la_opcion').text='nuevo texto'; se permite modificar el texto de la leyenda de una opcin. El cambio no afecta al valor enviado al servidor salvo que no haya sido especificado el atributo value. Recuerda que el texto solo es tomado como value en el caso de que este no estuviera definido en la etiqueta option selected La seleccin de una de las opciones puede hacerse bien de la forma tradicional (eligiendo con el ratn en el selector) o bien por medio de una sentencia javaScript independiente del selector. Mediante una de estas sintaxis: document.getElementById('identificador').options[indice].selected=true; document.getElementsByName('nombre_del_select')[0].options[indice].selected=true; document.getElementsByName('identificador_de_la_opcion').selected=true; podremos seleccionar la opcin correspondiente. Al seleccionar una de las opciones se deseleccionaran las dems. remove Por medio de este mtodo puede eliminarse items de una lista de opciones. La sintaxis sera document.getElementById('identificador').remove(indice); document.getElementsByName('nombre_del_select')[0].remove(indice);

dnde ndice es el nmero de orden (contado a partir de cero) de la posicin que ocupa dentro del select la opcin que pretendemos eliminar. add La seleccin de una de las opciones puede hacerse bien de la forma tradicional (eligiendo con el ratn en el selector) o bien por medio de una sentencia javaScript independiente del selector. Mediante una de estas sintaxis: document.getElementById('identificador').options[indice].selected=true; document.getElementsByName('nombre_del_select')[0]options[indice].selected=true; document.getElementsByName('identificador_de_la_opcion').selected=true; podremos seleccionar la opcin correspondiente. Al seleccionar una de las opciones se deseleccionaran las dems.
Ver ejemplo Ver cdigo fuente

Input type select multiple Mantiene los mismos mtodos y propiedades ya comentado para el select simple. Solamente hay que tener en cuenta que se diferencia de aquel en que dentro de la etiqueta &select> incluye ahora los atributos:multiple="multiple" (para establecer la condicin de multiple) size="numero" (para establecer el nmero de items que se visualizarn de forma simultnea). Adems, hay que tomar en consideracin algo de suma importancia. El atributo name ha de estar asociado con un array para permitir la transferencia de los mltiples valores eventualmente elegidos. La forma adecuada de hacerlo sera similar a: value="nombre_de_variable[ ]" Respecto a lo comentado para el input simple la nica diferencia sera evitar el uso de la sintaxis que utilice el nombre_de_variable asignado en value. Es decir, no usar document.getElementsByName('nombre_del_select')comentada para el select simple.
Ver ejemplo Ver cdigo fuente

Input type radio Los botones de opcin tiene la peculiaridad de agruparse automticamente sin ms que asignarles el mismo valor al atributo name. De esa forma, cuando se selecciona una de las opciones se deseleccionan de forma automtica todas las dems siempre que compartan su mismo name. Este tipo de elementos de los formularios permiten establecer y/o modificar los siguientes atributos: disabled Este atributo puede incluirse en la etiqueta <input type="radio"> escribiendo disabled="disabled". Puede activarse o desactivarse por medio de JavaScript utilizando una de las sintaxis siguientes: document.getElementById('identificador').disabled=true; document.getElementById('identificador').disabled=false; document.getElementsByName('nombre')[indice].disabled=true; document.getElementsByName('nombre')[indice].disabled=false; Se usaran las dos primeras opciones cuando se haya establecido un id="identificador" como atributo de la etiqueta <input type="radio">. En caso de que no exista ese id podemos hacer uso de las dos ltimas opciones. En ellas nombre se refiere al valor comn asignado a name siendo el valor de indice en[indice] el nmero de orden (empezando por cero) dentro del grupo de la opcin. Como siempre ese nmero de orden atiende a aquel en el que han sido creados los diferentes elementos del grupo. value Este atributo suele incluirse en la etiqueta <input type="radio"> escribiendo value="valor". Puede crearse o modificarse por medio de JavaScript utilizando una de las sintaxis siguientes: document.getElementById('identificador').value="valor_asignado"; document.getElementsByName('nombre')[indice].value="valor_asignado"; checked Este atributo (indica que la opcin est seleccionada por defecto) suele incluirse en la etiqueta <input type="radio"> escribiendo checked="checked". Puede crearse o modificarse por medio de JavaScript utilizando una de las sintaxis siguientes: document.getElementById('identificador').checked=true; document.getElementById('identificador').checked=false; document.getElementsByName('nombre')[indice].checked=true; document.getElementsByName('nombre')[indice].checked=false;

Cuando se selecciona una de las opciones (por medio del ratn o a travs de una sentencia JavaScript) se deselecciona de forma automtica cualquier otra que estuviera previamente seleccionada. name Este atributo ya reseado anteriormente puede crearse modificarse por medio de JavaScript utilizando una de las sintaxis siguientes: document.getElementById('identificador').name='nuevo_nombre'; document.getElementsByName('nombre')[indice].name='nuevo_nombre';

Cuidado! Cuando se cambia el nombre el elemento deja de pertenecer al grupo. Por esa razn sera perfectamente factible seleccionarlo sin que se deseleccionen susantiguos compaeros de grupo.
agregar una nueva opcin Agregar una nueva opcin a un grupo requiere incluirla en el lugar adecuado (al lado de las opciones que comparten grupo) y asignarle un texto identificativo. Una de las opciones para poder llevar a cabo esa inclusin sera tomar la cautela de crear un contenedor (un elemento tipo div con un id a que llamaremos aqu contenedor aunque pueda tener cualquier nombre). El proceso de agregar una nueva opcin consistira en: Leer el contenido de la div que incluye las opciones. Puede hacerse por medio de innerHTML Agregar a la cadena innerHTML la informacin correspondiente al nuevo elemento Actualizar el contenido de la div contenedora. Esas modificaciones podran hacerse por medio de una funcin similara a esta:

function agrega_radio(contenedor,nombre,texto,valor,identificador) { /* leemos el contenido actual del contenedor y lo guardamos en la variable contenido */ var contenido=document.getElementById(contenedor).innerHTML; if (identificador==null || identificador==''){ /*agregamos los datos del nuevo input sin incluir id especifico */ contenido += "<input type='radio' name='"+nombre+"' "; contenido += "value='"+valor+"' />"+texto; }else{ /*agregamos los datos del nuevo input incluyendo un id */ contenido += "<input type='radio' name='"+nombre+"' "; contenido += "id='"+identificador+"' value='"+valor+"' />"+texto; } /* reemplazamos los valores incluidos en el contenedor */ document.getElementById(contenedor).innerHTML=contenido; }
Ver ejemplo Ver cdigo fuente

Input type checkbox Es conveniente tener bien presente que si dos elementos de distinto o igual tipo (con excepcin de radio) tienen asignado un mismo name el valor transferido por medio del formulario ser el ltimo de los incluidos con ese nombre comn. Puedes comprobarlo en este ejemplo.
Ver ejemplo Ver cdigo fuente

Es conveniente tener bien presente que los distintos elementos de este tipo han de tener (por la razn comentada en el prrafo anterior) nombres distintos. Dicho esto los mtodos y propiedades comentados para el caso del radio son aplicables en su mayora en este tipo de elementos. La identificacin de los elementos se hara ahora por medio de document.getElementById('identificador'); document.getElementsByName('nombre')[0] El valor cero asignado en la segunda de las opciones se justifica por el hecho de que para cada nombre slo existir un elemento de este tipo.
Ver ejemplo Ver cdigo fuente

Esta miscelnea de posibilidades tiene una limitacin importante. A la hora de efectuar modificaciones en los valores de los diferentes elementos ya que no dispone de medios para obtener esos nuevos valores desde el servidor. En la pgina siguiente intentaremos ver la utilidad y forma de utilizacin de AJAX para estos menesteres.

Empezando con Ajax AJAX (Asynchronous JavaScript and XML)


Modificaciones parciales en una web
Sin meternos en grandes profundidades del JavaScript ni del llamado DOM (Document Object Model) lo conocido como AJAX(Asynchronous JavaScript and XML) no es un lenguaje de programacin ni tan siquiera una herramienta. Es simplemente la combinacin de otras tecnologas ya existentes entre las que cabe destacar: HTML y CSS, DOM y JavaScript, el objeto XMLHttpRequest y, tambin, XML. El uso conjunto de estas tecnologa nos va a permitir intercambiar datos con el servidor y actualizar partes de una pgina web sin necesidad de recargar totalmente la pgina. Un elemento imprescindible para estos propsitos es la interface conocida como XMLHttpRequest que, aunque desarrollada inicialmente por Microsoft, en la actualidad est integrada prcticamente todo los navegadores como un clase Javascript cuyos objetos se encargan, desde el propio navegador y a travs de sus propios mtodos, de realizar la comunicacin bidireccional con el servidor.

Crear objetos JavaScript


Dado que XMLHttpRequest es un objeto JavaScript empezaremos por comentar la sintaxis de creacin de objetos en este lenguaje que no difiere prcticamente en nada de la ya comentada cuando los crebamos en PHP. Igual que ocurra all, mediante la sintaxis objeto = new XMLHttpRequest() incluida entre dos etiquetas <script type="text/javascript"></script> estaramos creando un objeto de la clase XMLHttpRequest. Este ser el elemento bsico para el uso de AJAX y funcionar con las versiones ms actuales de los navegadores habituales. Por no romper con las tradiciones, es posible que puedas encontrarte con algunos navegadores antiguos que no incluyen esta interface y que, en el caso de Internet Explorer, van a requerir el uso de una sintaxis alternativa tal como puedes ver en este ejemplo de cdigo fuente.

<html> <head> <meta http-equiv="content-type" content="text/html; charset=iso-8859-1"> <title>Objeto Ajax</title> <script type="text/javascript"> if(window.XMLHttpRequest) { objetoAjax = new XMLHttpRequest(); } else if(window.ActiveXObject) { objetoAjax = new ActiveXObject("Microsoft.XMLHTTP"); } alert(objetoAjax); </script> </head> <body> </body> </html>
Ver ejemplo

Propiedades del los objetos XMLHttpRequest


Es importante tener bien que la secuencia de utilizacin prctica de los objetos XMLHttpRequest que es la siguiente: Se crea un objeto XMLHttpRequest El objeto XMLHttpRequest realiza un peticin al servidor El servidor atiende la peticin y devuelve su respuesta El resultado obtenido por XMLHttpRequest es utilizado para visualizar los resultados de la peticin Igual que ocurra en PHP y tal como comentamos en la pgina anterior los objetos JavaScript tiene propiedades a las que se alude mediante la sintaxis nombre_del_objeto.nombre_de_la_propiedad. En el caso de los objetos de la clase XMLHttpRequest las propiedades ms importantes son las relativas a los pasos enemurados anteriormente y que en resumen son las siguientes: Informacin sobre el estado del objeto objeto.readyState Informa sobre el estado actual del objeto que se resume en uno de estos cuatro valores: 0 En reposo. Sin comenzar una comunicacin con el servidor 1 Transaccin iniciada. Abierta la comunicacin 2 Transaccin en ejecucin. Cabeceras recibidas 3 Transaccin ejecutndose. Cargando datos 4 Transaccin con el servidor completada Informacin sobre el estado de la peticin objeto.status Devuelve el cdigo de estado de la peticin HTTP al servidor. Algunos de sus valores son los siguientes: 200 Peticin correcta 400 Peticin incorrecta 403 Acceso prohibido 404 Pgina no encontrado 500 Error interno del servidor objeto.statusText Devuelve una cadena informativa sobre el estado de la peticin HTTP al servidor OK Peticin correcta Bad Request Peticin incorrecta Forbidden Acceso prohibido Not Found Pgina no encontrado Internal Server Error Error interno del servidor Informacin recibida desde el servidor objeto.responseText Se utiliza para tratar los datos recibidos desde el servidor que no tienen formato XML objeto.responseXML Se utiliza para tratar los datos suministrados en formato XML por el servidor. Para poder acceder a esa informacin la respuesta del servidor ha de tener el encabezado text/xml, application/xml. En caso contrario su valor sera null.

Mtodos del los objetos XMLHttpRequest

Igual que ocurra en PHP y tal como comentamos en la pgina anterior los objetos JavaScript disponen de mtodos a los que se alude con la sintaxis nombre_del_objeto.nombre_del_metodo(parametros). En el caso de los objetos de la clase XMLHttpRequest las mtodos ms usuales son los siguientes: objeto.getAllResponseHeaders() Devuelve todas las de cabeceras HTTP de la peticin como una cadena 0 En reposo. Sin comenzar una comunicacin con el servidor 1 Transaccin iniciada. Abierta la comunicacin 2 Transaccin en ejecucin. Cabeceras recibidas 3 Transaccin ejecutndose. Cargando datos 4 Transaccin con el servidor completada objeto.getResponseHeader('nombre_de_la_cabecera') Devuelve la cabecera HTTP cuyo nombre se incluye como parmetro. Algunos de esos nombres son: Server En reposo. Sin comenzar una comunicacin con el servidor Date Transaccin iniciada. Abierta la comunicacin Content-length Transaccin en ejecucin. Cabeceras recibidas Content-type Transaccin ejecutndose. Cargando datos Conection Transaccin en ejecucin. Cabeceras recibidas Keep-alive timeout:Es el tiempo en segundos que Apache esperar peticiones subsiguientes antes de cerrar una conexin persistente. Max: es el nmero de peticiones permitidas por conexin. objeto.open(metodo, URL, tipo, usuario, contrasea') Prepara una peticin de informacin al servidor, pero no la enva. Requiere los siguientes parmetros metodo Puede tomar los valores: GET, POST o PUT (este ltimo de uso mucho ms infrecuente) URL Es la direccin absoluta o relativa de la pgina solicitada al servidor. Como norma general, cuando se utiliza el mtodo GET se incluyen junto con URL las variables que deseen incluirse en la peticin. Es decir la ya conocida sintaxis: nombre_de_la_pagina.extension?variable1=valor1&variable2=valor2. Cuando se usa el mtodo POST no se agregan valores de las variables aqu. En ese caso se incluirn (en forma de cadenas del tipo "variable1=valor1&variable2=valor2") como parmetros datos en la llamada al mtodo sendque comentamos ms abajo tipo Admite como valores true o false. Un valor true indica que el proceso del script contina despus del mtodo send(), sin esperar a la respuesta, y false indica que el script se detiene hasta que se complete la operacin, tras lo cual se reanuda la ejecucin. usuario y contrasea Son parmetros opcionales para aquellos casos en que esos valores sean requeridos por el servidor. objeto.setRequestHeader(etiqueta, valor ) Permite establecer cabeceras personalizadas en la peticin HTTP. Cuando se utiliza el mtodo POST debe incluirse una llamada a este mtodo antes de invocar el mtodo send() incluyendo como parmetros etiqueta-valor los siguientes:"Content-Type", "application/x-www-form-urlencoded". Como podrs comprobar guarda una gran similitud con lo indicado para ENCTYPE cuando hablbamos del envo de formularios. objeto.send(datos) Enva la peticin al servidor. El parmetro datos debe incluirse obligatoriamente. Si no hay datos que deban enviarse se escribir null. Se entienden como datos de este parmetro cadenas del tipo: "usuario=pepe&password=pepa" similares a las ya mencionadas cuando hacamos alusin al mtodo GET cuanto tratbamos los formularios

El gran hermano de XMLHttpRequest


Adems de los mtodos y propiedades antes aludidos un elemento imprescindible para su correcta utilizacin. Se trata del evento: objeto.onreadystatechange = gran_hermano()

Reacciona a cada cambio de estado modificacin de una propiedad, ejecucin de un mtodo, etctera del objeto ejecutando la funcin gran_hermano(). Dicho de otra forma, reacciona automticamente cada vez que algo cambia pudiendo hacerlo de forma distinta en cada situacin de acuerdo con lo especificado en la propia funcin gran_hermano() . En este ejemplo puedes ver (los resultados varan dependiendo del navegador que ests usando) la lista de propiedades de un objetoXMLHttpRequest. La visualizacin utiliza un bucle Javascript con la siguiente sintaxis: for (var=variable in nombre_del_objero){ //recorre el objeto pasando por cada una de sus propiedades document.write(variable+"<br>"); //escribimos el nombre de la propiedad concatenado con un salto de linea }
Ver ejemplo Ver cdigo fuente

Lectura de datos de un fichero de texto


Empezaremos con un ejemplo muy sencillo. Se trata de utilizar el objeto XMLHttpRequest para acceder al servidor, leer el contenido de un fichero de texto e incluir su contenido en una div de la pgina actual. El proceso es el siguiente: Creamos un objeto XMLHttpRequest Preparamos una peticin al servidor Activamos el detector de eventos para que escriba el resultado de la peticin una vez se confirme que la peticin al servidor ha resultado correcta y que la transaccin se ha completado. Enviamos la peticin al servidor y esperamos el final de la transaccin La forma de creacin del objeto XMLHttpRequest ha sido descrita ms arriba. El resto del proceso podra incluirse en una funcin como esta:

/* la funcin recibe dos parmetros, la URL de la pgina que va a solicitarse al servidor (origen) y la div en la que van a escribirse los resultados */ function obtenerDatos(origen, dest){ /* comprueba que existe el objeto XMLHttpRequest */ if(objetoAjax) { /*recogemos el valor dest en la variable GLOBAL destino su condicin de global se debe a que no lleva delante la palabra reservada var. De esta forma (GLOBAL) destino estar disponible para cualquier funcion o parte del script */ destino=dest; /*preparamos la peticin mediante el open. Incluimos el parmetro GET y el la direccin de la URL que solicitaremos al servidor. No incluimos el parmetro tipo con lo cual tomar su valor por defecto que es true. */ objetoAjax.open("GET", origen); /* asignamos al evento cambio de estado la ejecucion de la funcion gran_hermano. Observa que no ponemos parntesis en la llamada. Elo se debe a que lo que pretendemos es asignar al evento la ejecucion de la funcin. Si incluyramos los parntesis tipicos gran_hermano() lo que estaramos tratando de asignar al evento no sera la ejecucin de la funcin sino el resultado de esta. */ objetoAjax.onreadystatechange = gran_hermano; /* preparada la peticion y activada la captura de eventos ya solo nos queda enviar la peticion al servidor */ objetoAjax.send(null); } //cerramos el if } //finalizamos la funcion /* esta funcion no recibe ningun parmetro pero tiene disponible el valor de

la variable destino creada (creada como GLOBAL) por la funcin anterior */ function gran_hermano(){ /* comprueba si la propiedad readyState vale 4 (Transaccion completada) y que la peticin haya sido considerada correcta por el servidor (status=200)*/ if (objetoAjax.readyState==4 && objetoAjax.status==200) { /* si se completo correctamente la transaccin escribe en la div de destino el texto recibido del servidor (responseText) */ document.getElementById(destino).innerHTML = objetoAjax.responseText; }else{ /* si no se complet la peticion le indicamos que escriba "procesando " */ document.getElementById(destino).innerHTML ="procesando.."; } }
Aqu tienes dos casos de utilizacin de esa funcin. Observa las diferencias de respuesta.
Ver ejemplo Ver cdigo fuente Ver ejemplo Ver cdigo fuente

Habrs podido observar que el segundo ejemplo presenta incorrectamente algunos carcteres. La explicacin es simple. En el primer caso al crear el fichero de texto lo hemos guardado con codificacin UTF8 que es la que lee correctamente. El segundo fichero, idntico al anterior, ha sido guardado con codificacin ANSI y ese el origen de los problemas de visualizacin de los carcteres con tilde, las ees, etctera. Existen otras soluciones alternativas a descrita anteriormente. En vez de la funcin gran_hermano incluimos una funcin annima tal como puedes ver en este cdigo fuente.

/* la funcin recibe dos parmetros, la URL de la pgina que va a solicitarse al servidor (origen) y la div en la que van a escribirse los resultados */ function obtenerDatos(origen, dest){ /* comprueba que existe el objeto XMLHttpRequest */ if(objetoAjax) { /*recogemos el valor dest en la variable GLOBAL destino su condicin de global se debe a que no lleva delante la palabra reservada var. De esta forma (GLOBAL) destino estar disponible para cualquier funcion o parte del script */ destino=dest; /*preparamos la peticin mediante el open. Incluimos el parmetro GET y el la direccin de la URL que solicitaremos al servidor. No incluimos el parmetro tipo con lo cual tomar su valor por defecto que es true. */ objetoAjax.open("GET", origen); /* asignamos al evento cambio de estado la ejecucion de la funcion anmina que definimos con la palabra function() ahora con parntesis ya que esa es exigencia para su definicin*/ objetoAjax.onreadystatechange = function(){ /* comprueba si la propiedad readyState vale 4 (Transaccion completada) y que la peticin haya sido considerada correcta por el servidor (status=200)*/ if (objetoAjax.readyState==4 && objetoAjax.status==200) { /* si se completo correctamente la transaccin escribe en la div de destino el texto recibido del servidor (responseText) */ document.getElementById(dest).innerHTML = objetoAjax.responseText; }else{ /* si no se complet la peticion le indicamos que escriba "procesando " */ document.getElementById(dest).innerHTML ="procesando.."; } } /* preparada la peticion y activada la captura de eventos ya solo nos queda enviar la peticion al servidor */

objetoAjax.send(null); } //cerramos el if } //finalizamos la funcion

Estos son los resultados utilizando esta nueva sintaxis


Ver ejemplo Ver cdigo fuente Ver ejemplo Ver cdigo fuente

Una peticin que enva datos y recoge resultados


Mediante GET En este primer ejemplo utilizaremos GET. En tal situacin incluiremos las variables y sus valores junto con la URL utilizando la sintaxis clsica: multiplica.php?a=13&b=47.. No es necesario incluir objetoAjax.setRequestHeader() Se utiliza objetoAjax.send(null) ya que los datos fueron incluidos junto con la URL
Ver ejemplo Ver cdigo fuente Ver cdigo fuente del script

Mediante POST En este otro ejemplo utilizaremos POST. En esta ocasin pondremos como valor del parmetro URL del mtodo opennicamente multiplica.php Incluimos objetoAjax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded") antes de invocar el mtodosend Ahora deberemos incluir los datos. objetoAjax.send("a=13&b=48$c=Hola").
Ver ejemplo Ver cdigo fuente Ver cdigo fuente del script

Cuidado! Observa las diferencias entre los resultados de ambos ejemplos. Cuando se usa GET la correcta visualizacin de los resultados en el script php (en este caso multiplica.php) requerira tratar la cadena de texto por medio de la funcin PHP utf8_decode. No olvides que esta funcin, junto con utf8_encode pueden resultar muy tiles en muchas ocasiones.

Aplicacin de AJAX al autocompletado de formularios


Cada da es ms frecuente encontrarnos con pginas en las que los datos a incluir dentro de un campo de un formulario se nos van autosugiriendo a medida que vamos escribiendo caracteres en ese campo. A lo largo de los prrafos siguientes intentaremos ir creando, paso a paso, uno de esos formularios. 1. Incluir en el <head> del documento el cdigo JavaScript que cree un objeto XMLHttpRequest De esta forma el objeto XMLHttpRequest se crear al cargarse la pgina y lo tendremos disponible para cuando sea necesario. La sintaxis es idntica a la vista en ejemplos anteriores. 2. Incluir un <input type="text"> con un identificador y configurarlo para que capture el evento soltar una tecla. El objeto podra tener un comportamiento como este: donde a medida que vamos pulsando teclas dentro del campo nos aparecen alertas donde se visualiza el contenido actual del campo. La sintaxis del input anterior es: <input type="text" id="entrada" name="miprueba" value="" onKeyUp="alert(this.value)"; />. Identificaremos el elemento como entrada, le asignamos como name miprueba e incluiremos el evento onKeyUP (soltaruna tecla lo cual implica necesariamente haberla tenido que pulsar antes y en consecuencia haber aadido o eliminado un carcter en el campo

de texto). Este evento activa un funcin (en este caso alert, ms adelante hemos de cambiarla y sustituirla por el nombre de una funcin) y adems, por medio del parmetro this.value estamos recogiendo el valor actual de ese campo. 3. Necesitamos disponer y visualizar todos los valores posibles que contengan los carcteres tecleados. Para visualizarlos necesitaremos agregar un elemento a la pgina, por ejemplo una <div id="pruebas"> que ser la encargada de visualizar los resultados. Supongamos que disponemos de los datos en una tabla MySQL llamada paises, que contiene un campo llamado pais en el que se incluyen los nombres de los paises del mundo . Necesitamos un script PHP que consulte esa tabla cada vez que modificamos el input (tecleando o borrando) y que esa consulta considere coincidencias todos los registros que contengan la cadena escrita en el input. . Entre las muchas opciones posibles cabra efectuar esa consulta utilizando una clasula WHERE Nombres LIKE '%$busca%' (bucara el contenido de la variable $busca en cualquier posicin del nombre del pas) o por medio de WHERE Nombres LIKE '$busca%' buscara unicamente la coincidencia al comienzo del nombre. Este podra ser el script de una consulta de este tipo:
Ver ejemplo Ver cdigo fuente

4. Una vez disponemos del script que realiza la consulta MySQL ya solo necesitamos hacer algunas modificaciones en la pgina que el objeto XMLHttpRequest Modificar la funcin invocada por el evento onKeyUp en el campo input escribiendo algo como: <input type="text" id="entrada" name="miprueba" value="" onKeyUp="obtenerDatos('ejemplo779.php?busca='+this.value,,'pruebas');" /> De esta forma cada vez que se pulsara una tecla se ejecutaria la funcin obtenerDatos pasando dos parmetros: la cadena formada por ejemplo779.php?busca= (nombre del script que ejecuta la bsqueda seguido del nombre de la variable utilizada para aquella bsqueda y del signo igual) concatenada con el valor actual del campo de texto this.value El segundo paramtro es identificador del div al que hemos llamado pruebas y que ser el lugar dnde aparecern los resultados. Tenemos que definir la funcin JavaScript obtenerDatos() que puede tener una sintaxis como esta:

function obtenerDatos(origen, destino){ if(objetoAjax) { /* la variable origen incluye en este caso la cadena de busqueda*/ objetoAjax.open("GET",origen); objetoAjax.onreadystatechange = function(){ if (objetoAjax.readyState==4 && objetoAjax.status==200){ /* el estilo de la div destino tiene asignado display=none, eso significa que ahora que va a tener datos hay que cambiar es estilo a block para que pueda visualizarse */ window.document.getElementById(destino).style.display='block'; /* se visualiza la lista utilizando el estilo que asignado a ese elemento en el script de bsqueda. Los resultados resultantes de la consulta aluden a una funcion llamada selecciona que aun no ha sido definida */ window.document.getElementById(destino).innerHTML=objetoAjax.responseText; } } objetoAjax.send(null); } }
An tendramos pendiente definir la funcin selecciona() que hemos asociado al evento onClick para cada uno de los elementos de la lista resultante de la bsqueda. El objetivo de esa funcin sera que al hacer clic se rellenara el campo de texto del formulario con el valor incluido en ella como parmetro y que dejara de visualizarse la capa que contiene la lista de elementos. Para lograr esos fines bastara con que fuera similar a esta:

function selecciona(valor){ document.getElementById('entrada').value=valor; document.getElementById('pruebas').style.display='none'; }


El resultado de lo comentado hasta ahora sera algo como lo que puedes ver en este ejemplo en el que hemos optado con utilizar la opcin GET al usar el mtodo open.

Ver ejemplo

Ver cdigo fuente

El uso de la opcin POST requerira una pequea modificacin de la funcion javascript obtenerDatos() que podra quedar ahora de la forma siguiente:

function obtenerDatos(valor, origen, destino){ if(objetoAjax) { /* formamos una cadena de consulta con la palabra busca, nombre de la variable y el valor capturado de input text. Esa cadena ser incluida como parmetro al invocar el metodo send */ cadena_de_busqueda="busca="+valor; /* la variable origen incluye en este caso unicamente el nombre del script*/ objetoAjax.open("POST",origen); objetoAjax.onreadystatechange = function(){ if (objetoAjax.readyState==4 && objetoAjax.status==200){ /* el estilo de la div destino tiene asignado display=none, eso significa que ahora que va a tener datos hay que cambiar es estilo a block para que pueda visualizarse */ window.document.getElementById(destino).style.display='block'; /* se visualiza la lista utilizando el estilo que asignado a ese elemento en el script de bsqueda. Los resultados resultantes de la consulta aluden a una funcion llamada selecciona que aun no ha sido definida */ window.document.getElementById(destino).innerHTML=objetoAjax.responseText; } } /* el uso de POST nos obliga a llamar a este mtodo incluyendo sus encabezado */ objetoAjax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded") /* la cadena_de_busqueda se incluye ahora como parmetro del mtodo POST */ objetoAjax.send(cadena_de_busqueda); } }
Ver ejemplo Ver cdigo fuente

Los objetos en JavaScript (JSON) Los objetos JavaScript


Clases y prototipos
En la pgina anterior nos referamos a la creacin de objetos XMLHttpRequest por medio de objeto =new XMLHttpRequest() que nos recordaba, al menos desde el punto de vista operativo, la forma de hacerlo en PHP. Sin embargo existen diferencias sustanciales entre los objetos PHP y los objetos JavaScript. Los objetos PHP como en la mayora de los lenguajes de programacin estn basadas en la utilizacin de clases. Por el contrario los objetos JavaScript no utilizan ninguna un concepto formal de clase sino que se crean mediante un proceso de copia o clonacin, a partir de otros objetos ya existentes llamadosprototipos. Por esa razn cuando crebamos el objeto =new XMLHttpRequest() no utilizbamos clase sino que partamos de otro objeto, el objeto XMLHttpRequest. Este hecho diferencial nos va a permitir disponer de varias posibilidades (tambin algunas restricciones)a la hora de manejar objetos en JavaScript.

Creacin de objetos vacos en JavaScript


Una de las formas de creacin de un objeto JavaScript es utilizar la notacin JSON (JavaScript Object Notation) que mediante: nombre_del_objeto = {}

dnde nombre_del_objeto, ser el nombre del nuevo objeto y {} la sintaxis obligatoria para la creacin de un nuevo objeto por el momento vaco usando la notacin JSON. Otra de las opciones ms simples es la utilizacin de la sintaxis: nombre_del_objeto =new Object() dnde nombre_del_objeto ser, igual que en el caso anterior, el nombre del nuevo objeto y new Object() la sintaxis obligatoria (recuerda que JavaScript diferencia entre letras maysculas y minsculas) para la creacin de nuevo objeto. Como podrs observar, el nuevo objeto carece de propiedades y/o mtodos. Por el momento es una especie de objeto vaco. Tambin es posible la creacin de objetos por medio de una funcin constructora que, de forma similar a las clases de PHP, nos permite, al ser invocada, la creacin y la asignacin de propiedades y sus valores a un nuevo objeto. En ese caso son necesarios dos elementos: la funcin constructora y la llamada a esa funcin. El primero de los elementos tendra una estructura de este tipo: function funcion_constructora(parametro1, parametro2,...) { this.propiedad1 = parametro1 this.propiedad1 = parametro1 .... } La palabra reservada this tiene una significacin idntica a la comentada para $this en PHP. De forma muy similar a lo que ocurra en aquel caso. De igual modo this.propiedad se comportara en JavaScript de forma similar a $this->propiedad en PHP. En ambos casos aludira a la propiedad en el objeto actual. La creacin de objetos utilizando una funcin constructora requerira algo como esto: nombre_del_objeto = new funcion_constructora (parametro1, parametro2,... ) ahora la palabra reservada new va seguida del nombre de la funcin constructora y de los parntesis que pueden incluir los eventuales parmetros requeridos por la funcin. Esta forma de creacin de objetos permite una variante. Es la siguiente: variable = function funcion_constructora(parametro1, parametro2,...) { this.propiedad1 = parametro1 this.propiedad1 = parametro1 .... } que slo difiere de la anterior en el hecho de que hemos incluido la funcin constructora como valor de una variable. Ahora para la creacin del nuevo objeto debemos invocar el nombre de la variable con una sintaxis similar a esta: nombre_del_objeto = new variable (parametro1, parametro2,... ) No acaban aqu las posibilidades de creacin de objetos JavaScript. Los objetos con notacin JSON pueden ser creados a partir de una cadena de texto. Esa posibilidad tiene particular inters ya que nos va a permitir crear objetos JavaScript a partir de cadenas recibidas por medio de una peticin a un servidor. Es decir, se abre la posibilidad de intercomunicar objetos JavaScript con PHP y tambin objetos PHP con JavaScript. Por el momento conformmosnos con conocer el procedimiento de creacin de esos objetos JavaScript. Por medio de la funcin eval podemos convertir una cadena de carcteres en un objeto JavaScript. Esta transformacin requiere dos cosas importantes: Qu la cadena empiece y acabe por parntesis Qu la cadena utilice la santaxis correcta de la notacin JSON. Si se cumplen las premisas anteriores la creacin de un objeto (en notacin JSON) se hara de la siguiente forma: cadena= "{ ... contenido... }" nombre_del_objeto =eval('('+cadena+')')

dnde la cadena ha de empezar por { y acabar con }, su contenido ha de respetar estrictamente la sintaxis JSON (ms adelante nos referiremos a ella) aunque por el momento no incluyamos nada y por tanto la utilizaremos para crear un objeto vaco. Para la transformacin de la cadena en objeto JavaScript utilizaremos la funcin eval() en la que incluiremos como parmetros el valor de la cadena resultante de agregar a la anterior un parntesis de apertura y otro de cierre. Cualquiera de las formas descritas permite crear objetos JavaScript tal como puedes ver en el ejemplo que encontrars un poco ms abajo.

<script type="text/javascript"> /* creamos un objeto con notacin JSON de nombre objeto1 */ var objeto1 = {}; /* creamos un objeto vaco llamado objeto 2 */ var objeto2 = new Object(); /* creamos un funcion costructora vaca*/ function constructora(){ } /* creamos un objeto por medio de la funcion anterior */ var objeto3= new constructora(); /* creamos una variable cuyo contenido es una funcion por el momento esa funcin no tendr contenidos */ var creadora= function otra_constructora(){ } /* creamos un nuevo objeto utilizando la variable creadora */ var objeto4= new creadora(); /* crearemos ahora un objeto JSON a la cadena unicamente incluye las var cadena="{}"; /* por medio de la funcion eval, previamente entre parntisis. objeto, esta vez con notacin objeto5=eval('('+cadena+')'); partir de una cadena llaves */ evaluamos la cadena anterior, incluyendola La funcin eval va a devolvernos un nuevo JSON */

/* vamos a comprobar la existencia de esos objetos (vacios) por medio de alert */ alert('El alert('El alert('El alert('El alert('El </script>
Ver ejemplo Ver cdigo fuente

alert alert alert alert alert

dice dice dice dice dice

que que que que que

el el el el el

objeto1='+objeto1); objeto2='+objeto2); objeto3='+objeto3); objeto4='+objeto4); objeto5='+objeto5);

Creacin de objetos JavaScript incluyendo propiedades y valores


Los objetos creados en el ejemplo anterior no tienen ninguna utilidad prctica ya que carecen de propiedades (valores) y mtodos (procedimientos o funciones) que son la esencia y razn de ser de los objetos. En los prrafos siguientes intentaremos las diferentes formas de aadir propiedades (junto con sus valores) a los diferentes objetos JavaScript clasificndolas en dos modalidades:

Agregar propiedades en el momento de crear los objetos


Cuando se trata de crear objetos utilizando la notacin JSON pueden incluirse propiedades junto con sus valores utlizando la sintaxis: nombre_del_objeto ={ "propiedad1" : "valor1" ,"propiedad2"" : "valor2", ... }

dnde las llaves ({ }), tal como comentamos anteriormente, son obligatorias como comienzo y final del objeto y dnde las parejas"propiedad" : "valor" representan el nombre que pretendemos asignar a cada propiedad y su valor. Son obligatorios los dos puntos : que separan ambos parmetros. Cuando vayamos a incluir ms de una propiedad iremos separando mediante comas (,) las diferentes parejas propiedad valor. Cuando se trabaja en entornos de PHP cosa que ocurre cuando un objeto JSON va a ser transferido a un servidor e interpretado desde PHP) hay que tener particular cuidado con los siguientes aspectos sintcticos:

Los datos que deban ser tratados por PHP han de tener codificacn UTF-8 Utilizar siempre comillas dobles (" ") para rodear tanto nombres como valores alfanumricos Los valores numricos, booleanos y el valor null no requieren comillas En los casos en los que la creacin del objeto se realiza invocando su funcin constructura, los nombres de las propiedades y sus valores se establecen dentro de la propia funcin constructora por medio de la sintaxis: this.nombre_de_la_propiedad=valor_asignado Cuando la creacin del nuevo objeto Javascript se realiza por medio de eval() se utilizara una notacin similar a la descrita para JSON con la difrencia de que ahora, por tratarse de una cadena ha de incluirse todo entre comillas cadena= '{ "propiedad1" : "valor1", "propiedad2" : "valor2"}' nombre_del_objeto =eval('('+cadena+')') tratando siempre de usar comillas simples para las ms externas y reservando las dobles para propiedades o valores, o, si se utilizan comillas dobles para las ms externas utilizar \" en nombres y valores. En cualquiera de las opciones estaramos logrando el objetivo propuesto que no es otro que evitar las comillas simples como delimitadores de nombres de propiedades o de sus valores. Cuando los objetos JavaScript son creados por medio de una funcin constructora la asignacin de propiedades y valores puede hacerse incluyndolos en la propia funcin constructora por medio la sintaxis this.propiedad = valor

Agregar o modificar propiedades a objetos preexistentes


Para el caso de que necesitemos agregar una nueva propiedad a un objeto ya existente o modificar el valor de la misma disponemos de la opcin: objeto.propiedad= valor dnde propiedad es el nombre de la nueva propiedad (o de la ya existente cuyo valor queremos modificar) y valor es el nuevo valor de dicha propiedad.

Qu puede incluirse como valor de una propiedad?


A las propiedades de los objetos puede asignrseles como valor: Un valor nmerico. Como es habitual no requiere que se incluya entre comillas. Los valores as asignados sern identificados por la funcin tipeof (objeto.propiedad) o tipeof(variable) como number. Una cadena alfanumrica. Como es habitual requiere que se incluya entre comillas. Los valores as asignados sern identificados por la funcin tipeof (objeto.propiedad) o tipeof(variable) como string. Una valor booleano. Requerira asignar como valor true o false y no requiere que se incluya entre comillas esas palabra reservadas. Los valores as asignados sern identificados por la funcin tipeof (objeto.propiedad) o tipeof(variable) como boolean. Una valor nulo. Requerira asignar como valor null sin requerir que se incluya entre comillas esa palabra reservadas. Los valores as asignados sern identificados por la funcin tipeof (objeto.propiedad) o tipeof(variable) como null. Un array escalar. Requerira asignar como valor una expresin del tipo: [1,2,"a",3,"z"] en la que como puedes observar los valores encerrados en corchetes separados por comas siendo necesario encerrar entre comillas los valores alfanumricos. Tambin permitira, tal como puedes ver en el ejemplo crear previamente el array (por medio de new Array) y despus incluirlo asignado como valor el nombre del mismo. Los valores as asignados sern identificados por la funcin tipeof (objeto.propiedad) o tipeof(variable)como object.

Un objeto. Requerira asignar como valor el nombre de objeto a incluir. Los valores as asignados sern identificados por la funcin tipeof (objeto.propiedad) o tipeof(variable) como object.

<html> <head> <title>Objetos JavaScript</title> <script type="text/javascript"> /* creamos un objeto con notacin JSON de nombre objeto1 incluyendo algunas propiedades*/ var objeto1 = {"var nombre":"pepe1", "pass":"pepa", "edad":26, "usuario":true, "soporte":false, "antecedentes":null, "miarray":["a",2,"b",4] }; /* creamos un objeto vaco llamado objeto 2 */ var objeto2 = new Object(); /* aqui las propiedades las agregamos invocando el objeto recien creado por medio de esta sintaxis */ objeto2.nombre="pepe2"; objeto2.pass="pepa2"; objeto2.edad=16; objeto2.usuario=false; objeto2.soporte=true; objeto2.antecedentes=25; objeto2.miarray=["a",2,"b",4]; /* creamos un funcion costructora incluyendo las propiedades y sus valores correspondientes*/ function constructora(){ this.nombre="pepe3"; this.pass="pepa3"; this.edad=36; this.usuario=false; this.soporte=true; this.antecedentes=null; this.miarray=["a",2,"b",4]; } /* creamos un objeto por medio de la funcion anterior. Se le asignarn, de forma autmatica, las propiedades incluidas en la funcion constructora */ var objeto3= new constructora(); /* creamos una variable cuyo contenido es una funcion asignndole sus propiedades despus de leer los parmetros recibidos al ser invocada la funcin. El operador ternario asinga valores por defecto a las propiedades en el caso que no sean asignados en la llamada a la funcin constructora */ var creadora= function otra_constructora(a,b,c,d,e,f,g){ (a == 'undefined' || a == null || a == '') ? this.nombre="pepe3" : this.nombre=a; (b == 'undefined' || b == null || b == '') ? this.pass="pepa3" : this.pass=b; (c == 'undefined' || c == null || c == '') ? this.edad=35 : this.edad=c; (d == 'undefined' || d == null || d == '') ? this.usuario=false : this.usuario=d; (e == 'undefined' || e == null || e == '') ? this.soporte=true : this.soporte=e; (f == 'undefined' || f == null || f == '') ? this.antecedentes=null : this.antecedentes=f; (g == 'undefined' || g == null || g == '') ? this.miarray=["a",2,"b",4] : this.antecedentes=f; }

/* creamos un nuevo objeto utilizando la variable creadora */ var objeto4= new creadora('luis','',58); /* crearemos ahora un objeto a partir de una cadena escrita con notacin JSON Evitaremos incluir saltos de lnea en la cadena. Cuando por la razn que sea necesitamos "partirla en trozos" utilizamos el operador de concatenacin (+) */ var cadena='{"nombre":"pepe5","pass":"pepa5","edad":26,'; cadena +='"usuario":true,"soporte":false,"antecedentes":null,"miarray":["a",2,"b",4]}'; /* por medio de la funcion eval, evaluamos la cadena anterior, incluyendola previamente entre parntisis. La funcin eval va a devolvernos un nuevo objeto, esta vez con notacin JSON */ objeto5=eval('('+cadena+')'); </script> </head> <body> <h3>Listado de propiedades del objeto1</h3> <!-- el bucle variable in objeto nos permitir ir recorriendo el objeto como un array. Los sucesivos valores de variable sern los nombres de las propiedades y los de objeto[variable] los valores actuales de la propiedad contenida en variable -> <script type="text/javascript"> for (i in objeto1){ document.write(i+"="+objeto1[i]+"<br />"); } </script> <h3>Listado de propiedades del objeto2</h3> <script type="text/javascript"> for (i in objeto2){ document.write(i+"="+objeto2[i]+"<br />"); } </script> <h3>Listado de propiedades del objeto3</h3> <script type="text/javascript"> for (i in objeto3){ document.write(i+"="+objeto3[i]+"<br />"); } </script> <h3>Listado de propiedades del objeto4</h3> <script type="text/javascript"> for (i in objeto4){ document.write(i+"="+objeto4[i]+"<br />"); } </script> <h3>Listado de propiedades del objeto5</h3> <script type="text/javascript"> for (i in objeto5){ document.write(i+"="+objeto5[i]+"<br />"); } </script> <h3>Agregamos una nueva propiedad y listamos el objeto1</h3> <script type="text/javascript"> objeto1.nuevapropiedad="soy la nueva"; for (i in objeto1){ document.write(i+"="+objeto1[i]+"<br />"); } </script> <h3>Modificamos una propiedad y listamos el objeto5</h3> <script type="text/javascript"> objeto5.nombre="Me han cambiado de nombre"; for (i in objeto5){ document.write(i+"="+objeto5[i]+"<br />");

} </script> </body> </html>


Ver ejemplo

Opciones alternativas a la funcin eval()


La funcin eval() tiene la gran ventaja de su rapidez pero tiene tambin el incoveniente de que puede intepretar y ejecutar cualquier programa JavaSCript lo cual eleva los riesgos de su utilizacin cuando el origen de los datos evaluados (la cadena de texto incluida como parmetro en la llamada a la funcin eval()) no es de absoluta confianza. Para reducir esos riesgos resulta muy til utilizar como alternativa un analizador JSON. Este analizador (parser) viene incluido como elemento nativo en los navegadores ms habituales a partir de las versiones:Internet Explorer 8, Firefox 3.1, Safari 4, Chrome 3, y Opera 10.5. Cuando los navegadores diponen de JSON nativo estn disponibles dos mtodos muy interesantes: objeto =JSON.parse(cadena, funcion_opcional(){...}) que crea un objeto JSON a partir de las parejas propiedad : valor contenidas en la cadena. Opcionalmente, cuando se incluye como segundo parmetro la funcin_opcional los valores contenidos en la cadena son transformados por medio esta funcin antes de ser asignados como valores del objeto JSON. cadena =JSON.stringify(objeto) realiza en proceso inverso a la anterior. En este caso, al apliclar ste mtodo a un objeto JavaScript tendremos como resultado una cadena en notacin JSON. Ambos mtodos resultan de particular inters cuandos e trata de intercambiar informacin entre servidor-cliente y viceversa. En el caso en que los navegadores no disponga de estos mtodos en forma nativa es pueden incluirse en la pgina web documentos externos de JavaScript que los contengan. Desde la pgina oficial de JSON podremos acceder a un enlace que nos llevara a este otro desde dnde podremos obtener un fichero con extensin zip que contiene varios ficheros .js. Entre ellos hay uno llamado json2.js que incluye los dos mtodos comentados anteriormente. Bastara con descomprimirlo, colocarlos en algn lugar del servidro y agregarlo como un fichero externo por medio de <script src="ruta_hasta_el_fichero/json2.js" type"text/Javascript"></script> incluido entre las etiquetas <head></head> de la pgina.

Cuidado! Es importante descargar el fichero comprimido al que se accede desde este enlace. Cuando hemos descargado directamente el fichero json2.js desde este otro enlace hemos tenido problemas porque al parecer este ltimo fichero tiene errores. En cualquier caso, para facilitarte la labor, en este enlace tienes un fichero llamado json2.zip con la versin correcta de json2.js.

En el ejemplo que tienes a continuacin puedes ver la forma de utilizar estos recursos. Presta atencin a los comentarios porque es muy importante tener en cuenta las peculiaridades de la sintaxis para lograr un aceptable grado de compatibilidad entre navegadores.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>JSON</title> <script type="text/javascript"> /* Comprobamos la existencia del objeto JSON. Si existe es que la versin del navegador lo incluye. Si no existe el objeto JSON incluimos el fichero externo json2.js La particular manera de partir las palabra script tiene como finalidad evitar errores del navegador al interpertar ya que se presenta una confusin

al desconocer si debe tratarlo como una cadena o como un script que deba ejecutarse. La cabecera <!DOCTYPE HTML PUBLIC ... es imprescindible en este caso ya que el navegador IE dar un error JSON no est definido en el caso de no incluirla*/ if (typeof(JSON)==="undefined"){ alert('<sc'+'ript type="text/javascript" src="json2.js">'+'</sc'+'ript>'); document.write('<sc'+'ript type="text/javascript" src="json2.js">'+'</sc'+'ript>'); }else{ document.write("No es necesario el json2.js externo. El navegador incluye JSON<br>"); } /* Cuidado! la etiqueta script debe cerrarse aqu, despus de la comprobacin y abrirse nuevamente para continuar con el resto de las instrucciones. De esta forma el fichero JSON ya estar disponible cuando se acceda desde el bloque que insertamos a continuacin */ </script> <script type="text/javascript"> /* creamos la cadena con las propiedades y valores del objeto */ var cadena='{"nombre":"pepe5","pass":"pepa5","edad":26,"usuario":true,"soporte":false,'; cadena+='"antecedentes":null,"miarray":["a",2,"b",4]}'; /* utilizamos el mtodo parse para crear el objeto */ objeto=JSON.parse(cadena); /* visualizamos las propiedades del objeto */ document.write("<br>Estas son las propiedade del objeto JSON<br>"); for (i in objeto){ document.write(i+"="+objeto[i]+"<br />"); } /* ahora creamos una cadena JSON a partir del contenido del objeto */ document.write("<br>El objeto JSON convertido en cadena por JSON.stringify<br>"); document.write(JSON.stringify(objeto)); /* utilizaremos el segundo parmetro de la funcion para que invoque una funcion llamada funcion_opcional Esta vez no lleva los () porque lo que pretendemos de esa funcion no es que nos devuelva un valor sino que se ejecute*/ var objeto1 = JSON.parse(cadena, funcion_opcional); /* la llamada a la funcin opcional se har reiterativamente mientras va recorriendo todos los pares propiedad:valor que son recibidos en la llamada a la funcin */ function funcion_opcional(propiedad, valor) { /* si el valor es tipo cadena le aadimos un texto delante */ if (typeof valor === 'string') { return "A&ntilde;adido + "+ valor; } /* si el valor es tipo boleano lo ponemos como false */ if (typeof valor === 'boolean') { return false; } /* si es tipo numero le multiplicamos por 7 */ if (typeof valor === 'number') { return valor*7; } /* si el valor es null lo cambiamos por 45 */ if (valor==null){ return 45; } /* si el valor no es de los tipos anteriores lo devuelve sin modificar */

return valor; } /* listamos las propiedades del objeto resultante */ document.write("<br>Listado de propiedades del objeto JSON modificado<br>"); for (i in objeto1){ document.write(i+"="+objeto1[i]+"<br />"); } /* ahora creamos una cadena JSON a partir del contenido del objeto */ document.write("<br>El objeto modificado convertido en cadena por JSON.stringify<br>"); document.write(JSON.stringify(objeto1)+"<br><br>"); /* el metodo JSON.strinfgify es aplicable a cualquier objero JavaScript Crearemos un objeto incluyendo propiedades de todo tipo */ var una_matriz=new Array('Aviles','Oviedo','Gijn'); var otro_objeto= function crea_objeto(){ this.propiedad1="valor1"; this.propiedad2=45; this.propiedad3=true; this.propiedad4=null this.objeto_incluido=objeto; this.otro_objeto=objeto1; this.matriz=[1,2,"a","b"]; this.matriz2=una_matriz; } objeto_complejo=new otro_objeto(); /* listamos los tipos y valores de las propiedades del objeto resultatne*/ for (i in objeto_complejo){ document.write(typeof(objeto_complejo[i])+"-->"); document.write(i+"="+objeto_complejo[i]+" "); } document.write('<br><br>Listamos las propiedades, tipos y valores del objeto'); document.write(' incluido como propiedad en el objeto principal<br>'); for (i in objeto_complejo.objeto_incluido){ document.write(typeof(objeto_complejo.objeto_incluido[i])+"-->"); document.write(i+"="+objeto_complejo.objeto_incluido[i]+"<br>"); } /* ahora creamos una cadena JSON a partir del contenido del objeto */ document.write("<br><br>Cadena JSON del objeto resultante<br><br>"); document.write(JSON.stringify(objeto_complejo)); </script> </head> <body> </body> </html>
Ver ejemplo

Incluyendo mtodos en objetos JavaScript


Igual que ocurre en PHP los mtodos son funciones incluidas dentro del objeto. Hay varios formas para crear un mtodo nuevo: incluyendo una funcin annima o vinculando una funcion externa en la la funcin constructora, extendiendo el prototipo, o agregando una funcin (annima o externa) a una propiedad de un objeto. Veamos las diferentes posibilidades:

Incluir una funcin annima

Entendemos como funcin annima aquella que es definida sin incluir ningn nombre de la funcin. Tendra por tanto una estructura del tipo: function () { ... instrucciones } Este tipo de funciones pueden incluidas como mtodos de un objeto JavaScript de una de las formas siguientes: Incluyndolas en un funcin constructora invocable directamente para crear un objeto. function constructora(){ ... instrucciones en la funcin constructora this.mi_metodo = function(){ ... instrucciones de la funcin annima } ... instrucciones en la funcin constructora } El metodo se invoca utilizando la sintaxis: objeto= new constructora(); objeto.mi_metodo(); Antes de invocar el mtodo debe haber sido creado un objeto y el mtodo se invoca (y esto es muy importante) agregando parntesis () despus del nombre del mtodo. En este caso el resultado de la ejecucin del mtodo sera el resultado de la ejecucin de la funcin annima. Si se invocara el mtodo sin agregar los parntesis () finales lo que se obtendra sera un copia de la funcin annima pero no el resultado de su ejecucin. Incluyndolas en la funcin constructora incluida como contenido de una variable. variable =function constructora(){ ... instrucciones en la funcin constructora this.mi_metodo = function(){ ... instrucciones de la funcin annima } ... instrucciones en la funcin constructora } El metodo se invoca utilizando la sintaxis: objeto= new variable(); objeto.mi_metodo(); Este caso es una leve variante del anterior. La nica diferencia es que ahora la funcin constructora est asignada a una variable. Por tanto, para crear un objeto se invoca tal variable en vez de invocar a la funcin como ocurra en el caso anterior. El resto de los comentarios del caso anterior, incluidos los relativos a los parntesis () siguen siendo vlidos en este supuesto. Agregndolas a un objeto JavaScript ya creado. objeto =new Object(); objeto.mi_metodo = function(){ ... instrucciones de la funcin annima } El metodo se invoca utilizando la sintaxis: objeto.mi_metodo(); Este supuesto nos permite visualizar la importancia de los mencionados parntesis. Cuando lo escribimos sin parntesis le estamos asignando (o leyendo) la funcion annima. Sin embargo, cuando le agregamos los parntesis le estamos solicitando que nos devuelva el resultado de la ejecucin de la funcin En este ejemplo puedes ver las distintas opciones de definir mtodos utilizando funciones annimas.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>)Objetos JavaScript</title>

<script type="text/javascript"> /* comprobamos en un script independiente si JSON es soportado nativamente y en caso contrario carga el fichero correspondiente */ if (typeof(JSON)== "undefined"){ alert('<sc'+'ript type="text/javascript" src="json2.js">'+'</sc'+'ript>'); document.write('<sc'+'ript type="text/javascript" src="json2.js">'+'</sc'+'ript>'); } /* continuamos escribiendo el cdigo JavaScript pero incluyndolo dentro de una nuevas etiquetas */ </script> <script type="text/javascript"> function crea_objeto1(){ this.nombre="soy el objeto 1"; /* defino un mtodo por medio de una funcin annima (observa que entre function y () no lleva ningn nombre de ah lo de annima incluida dentro de la propia funcion constructora */ this.metodo1=function(){ return (5*3); } /* escribirlo as es pura redundancia ya que la propiedad1 y el mtodo1 son la misma cosa */ this.propiedad1=this.metodo1; /* esto ya es diferente. La propiedad2 tomar el valor resultante de la ejecucin del mtodo, es decir 15*/ this.propiedad2=this.metodo1(); } /* creamos un objeto utilizando la funcion constructora crea_objeto1 */ objeto1=new crea_objeto1(); document.write("<h3>Utilizando una funcin constructora</h3>"); document.write("<br><br>Probando la funcin annima<br><br>"); document.write("Soy el resultado de this.metodo1 leido desde la propiedad1 = "); document.write(objeto1.propiedad1+"<br>"); document.write("Soy el resultado de objeto1.metodo1 = "); document.write(objeto1.metodo1+"<br>"); document.write("Soy el resultado de this.metodo1() leido desde la propiedad2 = "); document.write(objeto1.propiedad2+"<br>"); document.write("Soy el resultado de objeto1.metodo1() = "+objeto1.metodo1()+"<br><br>"); document.write("Soy el resultado de objeto1.metodo1() = "); document.write(objeto1.metodo1()+"<br>"); /* ahora creamos una cadena JSON a partir del contenido del objeto */ document.write("<br><br>Cadena JSON del objeto resultante"); document.write(" (slo transforma propiedades)<br><br>"); document.write(JSON.stringify(objeto1)+"<br>"); /* ahora la funcion constructora ser una funcin annima asignada a la variable que hemos llamado trabajadora */ var trabajadora=function (){ this.nombre="Yo soy el objeto creado por la trabajadora"; /* defino un mtodo por medio de una funcin annima (observa que entre function y () no lleva ningn nombre de ah lo de annima incluida dentro de la propia funcion constructora */ this.metodo1=function(){ return (25-3); } this.propiedad1=this.metodo1; this.propiedad2=this.metodo1();

} /*creamos el nuevo objeto utilizando la variable trabajadora */ objeto2=new trabajadora(); document.write("<h3>Utilizando una variable que contiene la funcin constructora</h3>"); document.write("<br><br>Probando la funcin annima<br><br>"); document.write("Soy el resultado de this.metodo1 leido desde la propiedad1 = "); document.write(objeto2.propiedad1+"<br>"); document.write("Soy el resultado de objeto2.metodo1 = "); document.write(objeto2.metodo1+"<br>"); document.write("Soy el resultado de this.metodo1() leido desde la propiedad2 = "); document.write(objeto2.propiedad2+"<br>"); document.write("Soy el resultado de objeto2.metodo1() = "); document.write(objeto2.metodo1()+"<br>"); /* ahora creamos una cadena JSON a partir del contenido del objeto */ document.write("<br><br>Cadena JSON del objeto resultante"); document.write(" (slo transforma propiedades)<br><br>"); document.write(JSON.stringify(objeto2)+"<br>"); document.write("<h3>Utilizando new Object()</h3>"); objeto3=new Object(); /* asignamos un mtodo al objeto recin creado */ objeto3.metodo1=function(){ return "Soy le resultado del metodo1 (anonimo) en el objeto3"; } /* visualizamos los elementos del nuevo objeto. */ document.write("Soy el resultado de objeto3.metodo1 = "); document.write(objeto3.metodo1+"<br>"); document.write("Soy el resultado de objeto3.metodo1() = "); document.write(objeto3.metodo1()+"<br>"); /* ahora creamos una cadena JSON a partir del contenido del objeto */ document.write("<br><br>Cadena JSON del objeto resultante<br>"); document.write("Como slo transforma propiedades no tiene contenidos<br><br>"); document.write(JSON.stringify(objeto3)+"<br>"); </script> </head> <body> </body> </html>
Ver ejemplo

Incluir una funcin externa


Esta opcin requiere tener definido el mtodo en un funcin externa (totalmente ajena a los objetos JavaScript) tal como esta:

function externa () { ... instrucciones } Tambin puede se utilizada en los tres supuestos planteados para las funciones annimas. Incluyndolas en un funcin constructora invocable directamente para crear un objeto. function constructora(){ ... instrucciones en la funcin constructora this.mi_metodo = externa ... instrucciones en la funcin constructora } El metodo se invoca utilizando la sintaxis: objeto= new constructora(); objeto.mi_metodo(); Cuando desde this.mi_metodo se invoca la funcin constructora no se ponen parntesis dado que en este caso no pretendemos que se ejecute la funcin sino que se agregue su contenido al mtodo que estamos creando. Una vez creado el mtodo se invoca exactamente igual que hacamos cuando se trataba de funciones annimas Incluyndola en la funcin constructora incluida como contenido de una variable. variable =function constructora(){ ... instrucciones en la funcin constructora this.mi_metodo = externa ... instrucciones en la funcin constructora } El metodo se invoca utilizando la sintaxis: objeto= new variable(); objeto.mi_metodo(); Son vlidos los mismos comentarios realizados en el supuesto anterior. Agregndolas a un objeto JavaScript ya creado. objeto =new Object(); objeto.mi_metodo = constructora El metodo se invoca utilizando la sintaxis: objeto.mi_metodo(); Tambin aqu tienen plena validez los comentarios relativos a la no inclusin de parntesis detrs del nombre de la funcin externa cuando se trata de crear un nuevo mtodo En este ejemplo puedes ver las distintas opciones de definir mtodos utilizando una funcin externa.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>)Objetos JavaScript</title> <script type="text/javascript"> /* comprobamos en un script independiente si JSON es soportado nativamente y en caso contrario carga el fichero correspondiente */ if (typeof(JSON)== "undefined"){ alert('<sc'+'ript type="text/javascript" src="json2.js">'+'</sc'+'ript>'); document.write('<sc'+'ript type="text/javascript" src="json2.js">'+'</sc'+'ript>'); } /* continuamos escribiendo el cdigo JavaScript pero incluyndolo dentro de una nuevas etiquetas */ </script> <script type="text/javascript"> /* esta sera la funcin externa */ function externa(){

return "Solo el resultado de la funcion externa"; } /* funcion constructora */ function crea_objeto1(){ this.nombre="soy el objeto 1"; /* defino un mtodo por medio de la funcin externa a la que llamamos sin agregar los parntesis finales*/ this.metodo1=externa; /* escribirlo as es pura redundancia ya que la propiedad1 y el mtodo1 son la misma cosa */ this.propiedad1=this.metodo1; /* esto ya es diferente. La propiedad2 tomar el valor resultante de la ejecucin del mtodo */ this.propiedad2=this.metodo1(); } /* creamos un objeto utilizando la funcion constructora crea_objeto1 */ objeto1=new crea_objeto1(); document.write("<h3>Utilizando una funcin constructora</h3>"); document.write("<br><br>Probando la funcin externa<br><br>"); document.write("Soy el resultado de this.metodo1 leido desde la propiedad1 = "); document.write(objeto1.propiedad1+"<br>"); document.write("Soy el resultado de objeto1.metodo1 = "); document.write(objeto1.metodo1+"<br>"); document.write("Soy el resultado de this.metodo1() leido desde la propiedad2 = "); document.write(objeto1.propiedad2+"<br>"); document.write("Soy el resultado de objeto1.metodo1() = "+objeto1.metodo1()+"<br><br>"); document.write("Soy el resultado de objeto1.metodo1() = "); document.write(objeto1.metodo1()+"<br>"); /* ahora creamos una cadena JSON a partir del contenido del objeto */ document.write("<br><br>Cadena JSON del objeto resultante"); document.write(" (slo transforma propiedades)<br><br>"); document.write(JSON.stringify(objeto1)+"<br>"); /* ahora la funcion constructora ser una funcin annima asignada a la variable que hemos llamado trabajadora */ var trabajadora=function (){ this.nombre="Yo soy el objeto creado por la trabajadora"; /* defino un mtodo por medio de la funcion externa */ this.metodo1=externa this.propiedad1=this.metodo1; this.propiedad2=this.metodo1(); } /*creamos el nuevo objeto utilizando la variable trabajadora */ objeto2=new trabajadora(); document.write("<h3>Utilizando una variable que contiene la funcin constructora</h3>"); document.write("<br><br>Probando la funcin externa<br><br>"); document.write("Soy el resultado de this.metodo1 leido desde la propiedad1 = "); document.write(objeto2.propiedad1+"<br>"); document.write("Soy el resultado de objeto2.metodo1 = "); document.write(objeto2.metodo1+"<br>"); document.write("Soy el resultado de this.metodo1() leido desde la propiedad2 = "); document.write(objeto2.propiedad2+"<br>");

document.write("Soy el resultado de objeto2.metodo1() = "); document.write(objeto2.metodo1()+"<br>"); /* ahora creamos una cadena JSON a partir del contenido del objeto */ document.write("<br><br>Cadena JSON del objeto resultante"); document.write(" (slo transforma propiedades)<br><br>"); document.write(JSON.stringify(objeto2)+"<br>"); document.write("<h3>Utilizando new Object()</h3>"); objeto3=new Object(); /* asignamos un mtodo al objeto recin creado */ objeto3.metodo1=externa /* visualizamos los elementos del nuevo objeto. */ document.write("Soy el resultado de objeto3.metodo1 = "); document.write(objeto3.metodo1+"<br>"); document.write("Soy el resultado de objeto3.metodo1() = "); document.write(objeto3.metodo1()+"<br>"); /* ahora creamos una cadena JSON a partir del contenido del objeto */ document.write("<br><br>Cadena JSON del objeto resultante<br>"); document.write("Como slo transforma propiedades no tiene contenidos<br><br>"); document.write(JSON.stringify(objeto3)+"<br>"); </script> </head> <body> </body> </html>
Ver ejemplo

Agregar mtodos extendiendo el prototipo


En aquellos casos en los que se utiliza una funcin constructora (bien de manera directa o asignndola a una variable) cada vez que es invocada esta se crear un nuevo objeto conteniendo los mtodos y/o propiedades definidos en aquella. Si pretendiramos agregar un nuevo mtodo podramos editar la funcin constructora e incluirlo en ella pero tambin sera posible hacerlo extendiendo el prototipo. Este proceso se realiza de la forma siguiente: constructora.prototype.nuevo_metodo = function() { ... instrucciones de la funcion annima del nuevo mtodo } o constructora.prototype.nuevo_metodo = nombre_de_la_funcion_externa en el primer caso se tratara de una funcin annima y en el segundo en el caso de una funcin externa. Este procedimiento es vlido tanto para el caso de que constructora sea el nombre de una funcin como para el supuesto que sea el nombre de una variable que contenta una funcin de este tipo. Este procedimiento no es aplicable en los casos de objetos creados por medio de new Object(). Este es un ejemplo de aplicacin de este procedimiento.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head>

<title>)Objetos JavaScript</title> <script type="text/javascript"> /* comprobamos en un script independiente si JSON es soportado nativamente y en caso contrario carga el fichero correspondiente */ if (typeof(JSON)== "undefined"){ alert('<sc'+'ript type="text/javascript" src="json2.js">'+'</sc'+'ript>'); document.write('<sc'+'ript type="text/javascript" src="json2.js">'+'</sc'+'ript>'); } /* continuamos escribiendo el cdigo JavaScript pero incluyndolo dentro de una nuevas etiquetas */ </script> <script type="text/javascript"> /* esta sera la funcin externa */ function externa(){ return "Solo el resultado de la funcion externa"; } /* funcion constructora la defino vaca*/ function crea_objeto1(){ } /* agregamos un nuevo mtodo -en este caso una funcion annimaa la funcin constructora anterior */ crea_objeto1.prototype.metodo1 = function() { return ("Esta es la funcion anonima incluida como metodo 1"); } /* agregamos un segundo mtodo -en este caso una funcion externaa la funcin constructora anterior */ crea_objeto1.prototype.metodo2 = externa; /* creamos un objeto utilizando la funcion constructora crea_objeto1 */ objeto1=new crea_objeto1(); /* ejecutamos ambos mtodos con y sin parntesis */ document.write("Soy el resultado de objeto1.metodo1 = "); document.write(objeto1.metodo1+"<br>"); document.write("Soy el resultado de objeto1.metodo1() = "); document.write(objeto1.metodo1()+"<br>"); document.write("Soy el resultado de objeto1.metodo2 = "); document.write(objeto1.metodo2+"<br>"); document.write("Soy el resultado de objeto1.metodo2() = "); document.write(objeto1.metodo2()+"<br>"); /* ahora la funcion constructora ser una funcin annima asignada a la variable que hemos llamado trabajadora. Tambien la crearemos vaca*/ var trabajadora=function (){ } /* agregamos un nuevo mtodo -en este caso una funcion annimaa la variable anterior */ trabajadora.prototype.metodo1 = function() { return ("Esta es otra funcion anonima incluida como metodo 1 en trabajadora"); }

/* agregamos un segundo mtodo -en este caso una funcion externaa la variable trabajadora */ trabajadora.prototype.metodo2 = externa; /* creamos un objeto utilizando la variable trabajadora */ objeto2=new trabajadora(); /* ejecutamos ambos mtodos con y sin parntesis */ document.write("Soy el resultado de objeto2.metodo1 = "); document.write(objeto2.metodo1+"<br>"); document.write("Soy el resultado de objeto2.metodo1() = "); document.write(objeto2.metodo1()+"<br>"); document.write("Soy el resultado de objeto2.metodo2 = "); document.write(objeto2.metodo2+"<br>"); document.write("Soy el resultado de objeto2.metodo2() = "); document.write(objeto2.metodo2()+"<br>"); </script> </head> <body> </body> </html>
Ver ejemplo

Una vez conocemos los rudimentos de los objetos en JavaScript y dado que tambin hemos manejado los objetos PHP ya estaremos en condiciones de afrontar la labor de intercambiar objetos entre ambos lenguajes y, por lo tanto, intercambiar objetos entre cliente y servidor y tambin entre servidor y cliente. Ser lo que afrontaremos en la pgina siguiente.

También podría gustarte