MySQL y PHP
MySQL y PHP
AJAX y PHP
U.N.E.D.
Indice general
Módulo 3
Volumen 4
16 Consultas 16.1
16.1 Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .16.1
16.2 Selección de datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .16.1
16.3 Expresiones regulares . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .16.8
16.4 Operadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .16.10
16.5 Funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .16.17
18 Instalación 18.1
18.1 Instalación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .18.1
18.2 Instalación en Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .18.2
18.3 Instalación de MySQL en Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .18.7
18.4 Instalación en Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .18.7
21 Cadenas 21.1
21.1 Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .21.1
21.2 Delimitación de cadenas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .21.1
21.3 Visualización de cadenas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .21.2
21.4 Acceso al contenido . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .21.4
21.5 Búsqueda en cadenas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .21.5
21.6 Comparación de cadenas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .21.7
21.7 Operar con subcadenas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .21.7
21.8 Modificación del contenido . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .21.10
21.9 Relación con html . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .21.15
21.10 Otras funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .21.15
22 Arrays 22.1
22.1 Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .22.1
22.2 Arrays escalares . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .22.1
22.3 Arrays asociativos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .22.5
22.4 Arrays multidimensionales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .22.6
22.5 Recorrer un array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .22.9
22.6 Ordenar un array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .22.14
22.7 Otras operaciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .22.18
23 Funciones 23.1
23.1 Funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .23.1
23.2 Funciones con número indeterminado de parámetros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .23.7
23.3 Funciones variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .23.9
23.4 Funciones recursivas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .23.9
Tecnologías Web
10.1 INTRODUCCIÓN
Una aplicación Web es un conjunto de páginas Web estáticas y dinámicas. Una página Web está-
tica es aquella que no cambia cuando un usuario la solicita: el servidor Web envía la página al
navegador Web solicitante sin modificarla. Por el contrario, el servidor modifica las páginas Web
dinámicas antes de enviarlas al navegador solicitante. La naturaleza cambiante de este tipo de
página es la que le da el nombre de dinámica. Aquellas tecnologías en las que es el servidor el
que procesa toda la información ya sea de formateo, gestión de contenido, consultas a bases de
datos, etc. , se denominan Tecnologías del lado del servidor.
Como ejemplos de este tipo de tecnologías se pueden nombrar principalmente tres; PHP, ASP y
JSP. A lo largo de los siguientes capítulos se desarrollarán las dos primeras y se explicarán sus
conceptos básicos; lenguaje, acceso a bases de datos, procesamiento de la información, etc.
Un sitio Web estático suele constar de un conjunto de páginas HTML (XHTML y CSS) relacio-
nadas y de archivos alojados en un equipo que ejecuta un servidor Web.
Un servidor Web es un software que suministra páginas Web en respuesta a las peticiones de los
navegadores Web. Una petición de una página se genera cuando un usuario hace clic en un vín-
culo en una página Web, elige un marcador en un navegador o introduce un URL en el cuadro
Dirección del navegador y luego hace clic.
El contenido final de una página Web estática lo determina el diseñador y no cambia cuando se
solicita la página. Un ejemplo:
<html>
10.2 TECNOLOGÍAS WEB
<head>
<title>Prueba</title>
</head>
<body>
<h3>Esto es una prueba<h3>
</body>
</html>
El diseñador escribe todas y cada una de las líneas de código HTML de la página antes de colo-
car la página en el servidor. Dado que el código HTML no cambia una vez colocado en el serv
dor, este tipo de páginas se denomina página estática.
En sentido estricto, una página estática puede no ser estática en absoluto. Por ejemplo, una ima-
gen de sustitución o una película de Macromedia Flash pueden hacer que una página estática
cobre vida. No obstante, en este curso se habla de página estática cuando esta se envía al navega-
dor sin modificaciones.
Cuando el servidor Web recibe una petición de una página estática, el servidor lee la solicitud,
localiza la página y la envía al navegador solicitante, como se muestra en la siguiente figura (Fig.
10.1):
En el caso de las aplicaciones Web, que contienen tanto contenido dinámico como páginas Web
estáticas, algunas líneas de código no están determinadas cuando el usuario solicita la página.
Estas líneas deben determinarse mediante algún mecanismo antes de enviar la página al navega-
dor. En la siguiente sección se describe dicho mecanismo.
Cuando un servidor Web recibe una petición de una página Web estática, el servidor envía la
página al navegador solicitante sin retraso. El servidor Web reacciona de manera diferente
cuando recibe una petición de una página dinámica: pasa la página a una ampliación de software
especial que se encarga de finalizar la página. Este software especial se denomina servidor de
aplicaciones.
Un ejemplo de servidor de aplicaciones es PHP, el cual se puede instalar desde el DVD del curso
para ejecutarlo con un servidor Web como Apache.
El servidor de aplicaciones lee el código de la página, finaliza la página en función de las instruc-
ciones del código y después elimina el código de la página. El resultado es una página estática
que el servidor de aplicaciones devuelve al servidor Web, que a su vez la envía al navegador soli-
citante. Lo único que el navegador recibe cuando llega la página es código HTML puro. A conti-
nuación se incluye una vista de este proceso (Fig. 10.2):
Un servidor de aplicaciones le permite trabajar con recursos del lado del servidor, como una base
de datos. Por ejemplo, una página dinámica puede indicar al servidor de aplicaciones que
extraiga datos de una base de datos y los inserte en el código HTML de la página.
La instrucción para extraer datos de una base de datos recibe el nombre de consulta de base de
datos. Una consulta consta de criterios de búsqueda expresados en un lenguaje de base de datos
denominado SQL (Structured Query Language: Lenguaje de consulta estructurado). La consulta
SQL se escribe en los scripts o etiquetas del lado del servidor de la página.
Un servidor de aplicaciones no puede comunicar directamente con una base de datos porque el
formato propio de la base de datos hace que los datos sean ilegibles, de la misma forma que un
documento de Word resulta ilegible al abrirlo en el Bloc de notas. El servidor de aplicaciones
sólo puede comunicarse mediante un software de controlador de base de datos intermediario que
actúa como un intérprete entre el servidor de aplicaciones y la base de datos.
La ilustración siguiente (Fig. 10.3) muestra el proceso de consulta de base de datos y de devolu-
ción de los datos al navegador.
Siempre que disponga del controlador de base de datos adecuado, podrá utilizar prácticamente
cualquier base de datos con su aplicación Web. Si tiene intención de desarrollar pequeñas aplica-
ciones de bajo coste, puede utilizar una base de datos basada en archivos, como las que permite
crear Microsoft Access. En cambio, si desea desarrollar aplicaciones empresariales críticas,
puede utilizar una base de datos basada en servidor, como las que permite crear Microsoft SQL
Server, Oracle 9i o MySQL.
Si la base de datos está situada en un sistema distinto del servidor Web, asegúrese de disponer de
una conexión rápida entre ambos sistemas para que la aplicación Web pueda funcionar de forma
rápida y eficiente.
La creación de una página dinámica implica, en primer lugar, escribir el código HTML, luego
añadir los scripts o etiquetas del lado del servidor al código HTML para crear la página dinámica.
Figura 10.3 Consulta a una base de datos y devolución de los mismos al navegador.
Por esta razón, estos lenguajes se conocen como lenguajes de programación incrustados en
HTML. El siguiente ejemplo utiliza PHP:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://
www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Documento sin título</title>
</head>
<body>
<?php
$prueba="Hola";
echo $prueba;
?>
</body>
</html>
Las instrucciones incrustadas anteriormente (entre las etiquetas <?php y ?>) realizan las siguien-
tes acciones:
1 Crean una variable denominada $prueba y le asigna la cadena “Hola”.
2 Muestra el contenido de la variable.
Es posibler utilizar Dreamweaver para crear aplicaciones Web mediante cinco tecnologías de ser-
vidor: ColdFusion, ASP.NET, ASP, JSP o PHP. Cada una de estas tecnologías corresponde a un
tipo de documento en Dreamweaver. La elección de una de ellas para una aplicación Web
depende de diversos factores, entre los que se encuentran el nivel de conocimiento de los diver-
sos lenguajes de scripts y el servidor de aplicaciones que vaya a utilizar.
11.1 INTRODUCCIÓN
La WEB sigue siendo un fenómeno muy reciente. Tim Berners-Lee inventó la Web a finales de
los 90 cuando trabajaba en el CERN, el Laboratorio Europeo de Física de Partículas. Lo desarro-
lló para que los físicos de varias universidades de todo el mundo tuvieran acceso instantaneo a la
información.
Tim definió los URL, HTTP y HTML y, con Robert Cailliau, escribió su primer servidor Web y
el primer software para clientes Web que posteriomente se bautizó con el nombre de navegador.
Hace solo apenas unos años, tendríamos que haher explicado el significado de estos conceptos a
casi todo el mundo. Ahora, casi no hay gente (por to menos en las naciones desarrolladas) que no
sepa lo que es la W W W.
Poco después del trabajo inicial de Tim, un grupo de Centro Nacional de Actividades de Super-
computación, National Center for Supercomputing Activities (NCSA) de la Universidad de Illi-
nois, en Urbana-Champaign (UIUC) desarrolló el servidor web HTTPd NCSA y el navegador
web gráfico NCSA Mosaic. Mosaic no fue el primer navegador web gráfico aunque la gente lo
crea. Ese honor le corresponde a Viola, escrito por Pei Wei y disponible con anterioridad a
Mosaic, pero Mosaic se apropió rapidamente de esta mención, y se convirtió en el navegador
web mas usado en 1992.
HTTPd NCSA fue el servidor mas utilizado en la Web durante los primeros mños de su existen-
cia. Sin embargo, en 1994, Rob McCool, que es el creador de HTTPd NCSA, dejó el NCSA, y el
proyecto se terminó. Ya no había organización central que desarrollara nuevas caractcristicas y
que distribuyera un producto funcional.
11.2 SERVIDORES WEB. APACHE
Antes de que el código fuente del servidor se pusiera a disposición de todo el mundo, muchos de
sus usuarios habituales habian ya dasarrollado sus propias soluciones a los errores y a sus propias
características. Estas soluciones se comipartian fortuitamente a traves de Usenet, pero no había
un mecanismo central que recuperara y distribuyera dichas soluciones.
Por consiguiente, Apache (al igual que la World Wide Web) fue ensamblado por voluntarios.
Aunque la terminación del proyecto HTTPd NCSA dejara a los desarrolladores con un producto
que no funcionaba bien en la época y con nadie al que reclamar, al final se consiguió un producto
muy superior.
Los ocho socios fundadores del Grupo Apache eran Behlendorf, Skolnick, Roy T. Fielding, Rob
Hamill, David Robinson, Randy Terbush, Robert S. Thau y Andrew Wilson.
Poco después del primer lanzamiento, Thau disenó una arquitectura completamente nueva.
Comenzando con la versibn 0.8.8 en agosto de 1995, Apache se incorporó a esta nueva base de
código.
Esto les podrá parecer extraño a los que han conocido el concepto durante décadas y que estan
acosmmbrados a que se ignore, a incluso sea repudiado, por personas de la industria del software
comercial.
En mayo de 1997, Eric Raymond dió una charla, "La catedral y el bazar", en el Congreso de
Linux Kongress en Wurzhurg, Alemania (véase http://www.linux-kongress.de/1997/). Con esto
empezó una cadena de acontecimientos, entre ellos, la decisión de Netscape de liberar el código
fuente de su navegador web. El mundo del software ya no podia ignorar el movimiento "software
gratuito", que rebautizó a Open Source para desbancar a algunas de las asociaciones negativas
que giraban en tomo al movimiento. Eric ya era muy conocido en el movimiento de software y
había creado un número importance de productos de software, como GNU Emacs, Nei-Jack, nur-
ses y fetchmail. Escribió fetchmail, al menos en parte, para desentrañar el misterio de por que
funcionaba el modelo de desarrollo de software Open Source, mientras que el sentido común
capitalists traditional decía que no debía funcionar. Puede encontrar el texto completo de la
ponencia del Congreso de Linux, así como otras ponencias adicionales, en su sitio web en http://
www.tuxedo.org/-esr/writings/cathedral-bazaar/.
En junio de 1998, el Grupo Apache anunció que estaba en negociaciones con IBM para seguir
desarrollando el servidor Apache, de forma que IBM pudiera incluir ese código en su producto
WebSphere. Este fue uno de los primeros ejemplos de empresa líder de software que apoyaba un
proyecto Open Source, y constituyó uno de los ejes para hacer que el movimiento Open Source
pareciera viable ante los ojos del resto del mundo del software. El apoyo y sopone financiero de
la empresa de software más grande del mundo hizo ver a otras empresas que el movimiento Open
Source no era un grupo de rebeldes melenudos que trataban de dinamitar la industria del software
comercial, sino que era un metodo probado de crear productos de calidad.
Con anterioridad al acuerdo con IBM, hubo una serie de intentos de hacer que Apache funcionara
en Windows, pero había muchas dificultades técnicas y muy pocos programadores Windows
interesados en el proyecto. Con la financiacion y los recursos provenientes del acuerdo con IBM,
pudieron hacer que Apache se ejecutara en Windows.
Apache en Windows es una gran altemativa a IIS (Internet Information Server), particularmente
para aquellos que ya conozcan Unix/Linux pero que tengan que utilizar Windows. La solución
modular adoptada por Apache supone un alivio si la comparamos con IIS, que instala una aplica-
cion monolítica enorme que hace de todo, hasta cosas que no sirven para nada.
Apache es ligero, y cualquier opción puede ser agregada cargando otro módulo. Apache es facil
de configurar y de administrar, y le permite configurar parámetros que en IIS ni siquiera puede
imaginar. Y si quiere tener una utilidad de configuraci6n gráfica, Comanche la ofrece sin restar
potencia como administrador de servidor.
Al cliente se le denomina normalmente navegador o explorador. Los más conocidos son Firefox,
Mozilla e Internet Explorer.
Entre tanto, también existen muchos servidores, aunque dos son los que acaparan la mayor cuota
de mercado; el servidor Apche, software libre que se distribuye bajo licencia GPL, y el servidor
IIS de Microsoft.
El número de la versión de Apache va parejo al número de versión del protocolo HTTP. Este pro-
tocolo es cada vez más complejo; de la versión 1.0 se pasó a la versión 1.1 y de ahí directamente
a la versión 2.0. La velocidad y la seguridad también se ha potenciado y el número de métodos
aceptados ha ido en aumento. Valga como muestra el hecho de que la especificación del proto-
colo en su versión 1.0 tuviera 60 páginas, frente a las 161 de la versión 1.1. La necesidad de
conexiones seguras a llevado a añadir cifrado y generar el protocolo HTTPS basado en SSL.
Por otra parte, el lenguaje de documentos web ha sido durante años HTML y, aunque sigue
siendo el lenguaje principal, se tiende a sustituirlo y a adaptarlo al metalenguaje XML. Entre
tanto, han surgido propuestas exitosas como CSS y DHTML.
HTML está orientado a establecer el aspecto de los documentos, mientras que XML está orien-
tado a representar la estructura de la información, pudiendo mostrar la misma de formas muy
diferentes. El lenguaje XSLT facilita el mapeo de las estructuras con su representación, y las ver-
siones más recientes de los navegadores están adaptadas para interpretar este lenguaje.
En resumen, la estructura de los sitios web ha cambiado mucho. En los inicios de la web, las
hojas estáticas eran lo más común, pero ahora la mayoría de los sitios se basan en sistemas de
bases de datos, ya que permiten una gestión de los datos mucho más flexible. Para ello ha hecho
falta un trabajo considerable de programación, desde los primeros programas CGI hasta los sofis-
ticados programas actuales.
Aunque el lenguaje Java parece predominar en este aspecto, otros lenguajes tienen cierta presen-
cia, entre ellos PHP, Perl, Python y ASP y las plataformas web PHP-Nuke, PostNuke, Zope, etc.
Salvo la plataforma ASP de Microsoft, el resto se basan en software libre.
El desarrollo web ha influenciado incluso los paradigmas de programación, y hoy en día se están
popularizando las plataformas de servidores de aplicaciones como Websphere de IBM, Oracle 9i,
o incluso Microsoft.NET.
Además de todo esto, las aplicaciones web tienden a ser cada vez más adaptables a los usuarios
finales, y ofrecen servicios personalizados y cada vez más seguros, aunque todavía hay reticen-
cias y desconfianza hacia las compras y transacciones en Internet.
Con todo, la programación y la seguridad son los protagonistas en los servicios de hoy en día,
tanto en el entorno de redes de área amplia como en los servicios internos de las redes locales, en
las que la web se ha convertido en el componente fundamental del concepto de Intranet.
Apache posee varias características que lo han convertido en exitoso: es rápido, potente, eficaz y
flexible. Más del 60% de los servidores web son servidores Apache, duplicando la cifra de los
servidores Microsoft IIS.
Apache suele venir incorporado en todas las distribuciones de Linux. De todas maneras, el pro-
ceso en si no se llama Apache sino httpd y se inicia mediante el script /etc/init.d/httpd.
En este caso, será necesario más espacio en el disco duro y en la RAM para poder satisfacer todas
las necesidades.
No obstante hoy en día cualquier computador de última generación está preparado de sobra para
ejecutar este servicio y muchos más.
El CD que acompaña a este módulo, contiene una versión para la plataforma W32.
Apache funciona como un servicio por lo que habrá que ponerlo en marcha. La manera de
hacerlo varía en función del sistema operativo sobre el que se está corriendo.
1 En el caso de Linux (concretamente la distrubución Mandrake) existen dos formas:
- Ejecutando desde una consola el script /etc/init.d/httpd start. Para ello es necesario
entrar primero en modo de superusuario mediante el comando su.
- Usando la herramienta gráfica de activación de servicios a la cual se accede como
Menu->sistema->Configuración->Configurar su computadora->Sistema-
>Habilitar o deshabilitar los servicios del sistema. (Fig. 11.2)
- Mediante la herramienta webmin.
2 En el caso de Windows, una vez instalado el software, se dispone de una herramienta grá-
fica que se encuentra en la Barra de iconos de tareas (Fig. 11.1)
Una vez que está activo el servidor, es posible comprobar su correcto funcionamiento mediante
un navegador conectándonos a la siguiente url http://localhost.
Si Apache está instalado, el mencionado script httpd estara creado en el directorio init.d. Los
ficheros de configuracion suelen crearse en el directorio /etc/httpd/conf, pero la ubicación de los
datos suele variar entre /var/www, /var/httpd o /home/httpd, según la distribución de la que se dis-
ponga. En la version de Mandrake, el directorio utilizado es /var/www, y será el directorio que
usaremos en los ejemplos.
Para estudiar el estado del servidor Apache será necesario explorar estos directorios. Para una
primera aproximación se puede utilizar por ejemplo este comando:
ls -l /var/www
Configurar Apache es una tarea ardua, pero controlar los principales parametros no es tan dificil.
Existen ademas varios programas gráficos de configuracion que ayudan en esta labor, como por
ejemplo la herramienta llamada comanche o webmin.
Cada vez que el servidor Apache se inicia, lee este fichero de modo que cualquier cambio que
realicemos en el mismo, solo se notará si reiniciamos el servidor apache. Esto se puede hacer eje-
cutando el script /etc/init.d/httpd restart (en Linux) o mediante la herramienta gráfica mostrada
citada en el apartado 11.4 (Iniciar Apache) de la página 6 en el caso de tratarse de un sistema
Windows.
En cada linea especifica el valor de un parametro, ofreciendo información completa de los posi-
bles valores que puede tomar. Muchas veces estas directivas se encuentran desactivadas, con el
caracter # por delante a modo de comentario. Es decir, cualquier linea que comience con el carac-
ter # se considera un comentario y por tanto no se ejecutará.
Es interesante que mientras estudia los posibles valores de los siguientes parámetros, abra el
fichero /etc/httpd/conf/httpd2.conf o en otras distribuciones /etc/httpd/conf/httpd.conf para ir
comprobando el código.
Comentarle antes que dentro de este fichero puede incluirse una sentencia denominada include
nombre-fichero que permite insertar en ese punto el contenido del fichero nombre-fichero. Por
ello, algunos de los parámetros que aquí describiremos no aparecen en el fichero principal
(podrían tambien estar) sino en algunos de los ficheros asociados. Esto se hace así para poder
tener ficheros con distintas configuraciones y con solamente cambiar una linea include hacer que
el servidor trabaje de una forma totalmente distinta.
Los parámetros mas importantes, aquellos que suelen ser modificados en ocasiones, son los
siguientes:
• Modo de inicio. ServerType. Tiene dos opciones: la primera para que el servidor se inicie
directamente (standalone), y la segunda mediante inetd (inetd). Normalmente se utiliza la
opción standalone. El formato es el siguiente:
ServerType standalone
• Máximo número de conexiones: MaxClients. Con este número se puede limitar el maximo
de clientes, para evitar problemas por sobrecargas o ataques de denegación de servicio. Por
ejemplo:
MaxClients 150
• Margen del número de servidores: MinSpareServers, MaxSpareServers, StartServers. Con
estos parametros se puede definir el número de servidores en marcha simultaneamente: el
minimo, el maximo y el valor de inicio. El valor de inicio suele ser cinco en casi todas las
distribuciones. Por ejemplo:
StartServers 5
MinSpareServers 5
MaxSpareServers 15
Por lo tanto, se puede servir entre cinco y quince peticiones simultáneas y en el caso de
que lleguen más, se pondrán en la lista de espera. Por eso es habitual que haya varios pro-
cesos httpd en marcha a la vez.
• Puerto: Port. Determina en que puerto debe escuchar el servidor. El valor por defecto es
80, pero para hacer pruebas se utiliza en ocasiones el puerto 8080.
Port 80
• Puerto o IP adicional: Listen. Es complementario del anterior, ya que permite escuchar en
más de un puerto a la vez.
Listen 8080
• Directorio del servicio: ServerRoot. Establece el directorio en el que se van a almecenar
los archivos del servidor.
ServerRoot /etc/httpd
• Directorio raIz de las paginas web: DocumentRoot. En este directorio se situarán las pági-
nas web, por lo que habra que tener especial cuidado con los permisos de los documentos.
En este directorio se pueden utilizar enlaces simbólicos.
DocumentRoot /var/www/html
• Módulos plug-in: LoadModule y AddModule. Como Apache se trata de un programa
modular, es flexible en ese aspecto. De esta manera podemos añadir a Apache habilidades
extra. Suele haber varias líneas de este tipo, una por cada módulo del directorio modules.
He aqui algunos ejemplos:
LoadModule mime_module modules/mod_mime.so
AddLanguage en .en
AddLanguage eu .eu
AddLanguage ca .ca
AddLanguage fr .fr
LanguagePriority es en eu ca fr
• Activación de la función de cache: CacheRoot, CacheSize, CacheMaxExpire, etc. Con
estos parámetros se puede activar (on) o desactivar (off) la función de caché para permitir
que se acumulen las últimas consultas realizadas sobre las paginas dinámicas del sitio, de
forma que se puedan servir con mayor rapidez. En el siguiente comando se especifica el
directorio que se va a utilizar para almacenar archivos con caché.
CacheRoot "/var/cache/httpd"
Estas son unas lineas con los principales parámetros de configuración de Apache. No obstante la
referencia completa y probablemente la mejor guía (en castellano) se encuentra en http://
httpd.apache.org/docs/2.0/.
El término host virtuales hace referencia a ejecutar mas de un sitio web en el mismo servidor. Se
podría tratar de múltiples nombres que tuvieran el mismo dominio como http://tallerdigi-
tal.uned.es y http://tallerdgital.uned.es o de nombres con dominios distintos, como http://
www.miweb.com y http://www.tuweb.com.
Apache fue el primer servidor web que acuñó esta característica que ha mantenido desde su ver-
sión 1.1 (la versión actual es la 2.0).
servidor por cada IP) ya que todas las solicitudes las maneja un solo proceso. Esto se hace con los
hosts virtuales basados en IP.
Los hosts virtuales basados en IP requieren una dirección IP separada en cada host virtual. Para
añadir direcciones IP adicionales a la máquina, es necesario configurar el sistema operativo. Se
puede añadir una tarjeta de red para cada IP o, en la mayoría de sistemas operativos, asignar múl-
tiples direcciones al mismo dispositivo.
La sección <VirtualHost>
Dentro del fichero de configuración de Apache httpd.conf existen los denominados contenedores
los cuales son trozos de código que se ejecutan entre dos marcas, en este caso entre <Virtual-
Host> y </VirtualHost>.
Por ello, entre estas dos etiquetas, incluiremos los parámetros propios de cada uno de los hosts
virtuales que deseemos definir. Se pueden definir tantos bloques <VirtualHost> como se desee.
La sección <VirtualHost> del archivo de configuración del servidor incluye aquellas directivas
que se aplican a un determinado host virtual. Entre ellas se encuentran como mínimo Documen-
tRoot y también puede haber otras como ServerAdmin, ErrorLog, etc.
ServerAdmin webmaster@yo.com
DocumentRoot /home/yo/html
ServerName servi1.yo.com
</VirtualHost>
<VirtualHost 192.168.1.151>
ServerAdmin webmaster@tu.com
DocumentRoot /home/tu/html
ServerName servi2.tu.com
</VirtualHost>
La directiva NameVirtualHost
Los hosts virtuales se configuran de manera muy similar a los hosts virtuales basados en direc-
ciones IP, con una diferencia principal: la directiva NameVirtualHost le indica al servidor sobre
qué dirección IP se van a recibir las solicitudes de hosts virtuales basados en nombres. Las sec-
ciones <VirtualHost> tienen el mismo aspecto que cuando se usan hosts virtuales basados en
direcciones IP, con la excepción de que todas ellas señalan a la misma dirección IP.
El proyecto consiste en hacer que Apache distinga las solicitudes que llegan de cada dominio y
las redirija a las páginas web propias de cada uno.
NameVirtualHost 192.168.0.1
<VirtualHost 192.168.0.1>
ServerName www.yo.com
DocumentRoot /var/www/yo
</VirtualHost>
<VirtualHost 192.168.0.1>
ServerName www.tu.com
DocumentRoot /var/www/tu
</VirtualHost>
Aquí podremos configurar completamente nuestro servidor, es decir, en vez de editar a mano el
fichero httpd.conf el sistema lo hace por nosotros añadiendo, modificando o suprimiendo líneas
del mismo en función de las opciones elegidas
Para la gestión del servidor por defecto y de los dominios virtuales se utilizan las opciones que
aparecen tras hacer un clic en uno de los servidores virtuales.
12.1 INTRODUCCIÓN
Antes de entrar en contacto con MySQL se presentarán algunos aspectos fundamentales sobre
bases de datos, que serán de importancia para la compresión de las posibilidades que este Sis-
tema de Gestión de Bases de Datos (SGBD) ofrece. En primer lugar, se dan una serie de defini-
ciones sobre conceptos básicos. A continuación se indican los objetivos que se persiguen con los
SGBD y se tratan los problemas relativos a la abstracción de la información. Por último, antes de
presentar la estructura general de un SGBD, se tratan los modelos de datos que serán de impor-
tancia durante el diseño de bases de datos.
trayectorias de acceso a la base de datos de tal forma que se pueda acceder rápidamente a
los datos. 3) Manejar los datos de acuerdo a las peticiones de los usuarios. 4) Registrar el
uso de las bases de datos. 5) Interaccionar con el manejador de archivos a través de senten-
cias en LMD (Lenguaje de Manipulación de Datos). 6) Disponer de mecanismos que per-
miten la recuperación de los datos en caso de fallo en el sistema de base de datos. 7)
Controlar la interacción entre los usuarios concurrentes para no producir inconsistencia de
datos. 8) Disponer de mecanismos que permitan el control de la consistencia de los datos
evitando que estos se vean perjudicados por cambios no autorizados o no previstos. En la
figura se muestra el SGBD como interfaz entre la base de datos física y las peticiones de
usuario.
Petición de usuario
Base de datos física
Indagaciones
Sistema
SGBD Base de
operativo
datos
Sistema de
manejo de
archivos
Figura 12.1 SGBD como interfaz entre la base de datos física y las peticiones de usuario
datos: 1) Procedimentales, requieren que el usuario especifique que datos necesita y cómo
obtenerlos. 2) No procedimentales, requieren que el usuario especifique que datos necesita
sin especificar cómo obtenerlos
• SQL Structured Query Language. Lenguaje orientado al sector de las bases de datos. Los
comandos de SQL se pueden dividir en tres tipos: 1) Los que hacen referencia a la defini-
ción de datos (LDD). 2) Los que hacen referencia a la manipulación de datos (LMD). 3)
Los que hacen referencia al control y seguridad de los datos.
• Consulta. Petición al SGBD para que procese un determinado comando. Incluye peticio-
nes de datos, creación de bases de datos, modificaciones e inserciones, entre otros.
• Usuarios de las bases de datos. Toda persona que tenga contacto con el sistema de base de
datos desde que éste se diseña, elabora, termina y se usa. Pueden ser: 1) Programadores de
aplicaciones, profesionales en computación que interactúan con el sistema por medio de
llamadas en LMD. 2) Usuarios sofisticados, interactúan con el sistema escribiendo sus
preguntas en un lenguaje de consultas de base de datos. 3) Usuarios especializados, usua-
rios sofisticados que escriben aplicaciones de base de datos especializadas que no encajan
en el marco tradicional de procesamiento de datos. 4) Usuarios ingenuos, usuario final que
utiliza el sistema de base de datos sin saber nada del diseño interno del mismo, interactúa
con el sistema invocando alguno de los programas de aplicación del sistema de base de
datos.
• Administrador de base de datos. Persona o conjunto de personas responsables del control
y manejo del sistema de base de datos. Sus funciones principales son: 1) Definición de
esquema, el esquema original de la base de datos se crea escribiendo un conjunto de defi-
niciones que son traducidas por el compilador de LDD a un conjunto de tablas que son
almacenadas permanentemente en el diccionario de datos. 2) Definición de la estructura
de almacenamiento del método de acceso, se crean escribiendo un conjunto de definicio-
nes que son traducidas por el compilador del lenguaje de almacenamiento y definición de
datos. 3) Concesión de autorización para el acceso a los datos, regular las partes de las
bases de datos que van a ser accedidas por varios usuarios. 4) Especificación de límites de
integridad, serie de restricciones que se encuentran almacenados en una estructura espe-
cial del sistema que es consultada por el gestor de base de datos cada vez que se realice
una actualización al sistema.
Los sistemas de base de datos están diseñados para manejar gran cantidad de información. La
manipulación de los datos involucra tanto la definición de estructuras para el almacenamiento de
la información como la provisión de mecanismos para la manipulación de la información, ade-
más un sistema de base de datos debe de tener implementados mecanismos de seguridad que
garanticen la integridad de la información, a pesar de caídas del sistema o intentos de accesos no
autorizados. En este sentido, el objetivo principal de un sistema de base de datos es proporcionar
a los usuarios una visión abstracta de los datos, escondiendo ciertos detalles sobre cómo se alma-
cenan y mantienen los datos.
• Seguridad. Algunos datos pueden ser más importantes que otros, por lo que se debe consi-
derar el control de acceso a los mismos, no todos los usuarios pueden visualizar toda la
información, por este motivo para que un sistema de base de datos sea fiable debe mante-
ner un grado de seguridad que garantice la autentificación y protección de los datos.
Una base de datos puede verse como una colección de archivos relacionados entre sí, de los cua-
les el usuario puede extraer información sin tener que conocer la estructura de archivos. En este
sentido, un objetivo importante de un sistema de base de datos es proporcionar a los usuarios una
visión abstracta de los datos, es decir, el sistema esconde ciertos detalles de cómo se almacenan
y mantienen los datos. Sin embargo, para que el sistema sea manejable, los datos se deben extraer
eficientemente.
Nivel de visión
Nivel
conceptual
Nivel físico
Existen diferentes niveles de abstracción para simplificar la interacción de los usuarios con el sis-
tema (ver figura):
• Nivel físico. Nivel más bajo de abstracción. Se describe de forma detallada como se alma-
cenan los datos en los dispositivos de almacenamiento.
• Nivel conceptual. Siguiente nivel de abstracción. Describe la base de datos completa en
términos de su estructura de diseño (datos almacenados y relaciones entre ellos). El nivel
conceptual lo usan los administradores de bases de datos, responsables de decidir la infor-
mación se va a guardar en la base de datos. En éste nivel se consideran las siguientes defi-
niciones: 1) Definición de los datos, se describen el tipo de datos y la longitud de campo
(atributos y registros conceptuales). 2) Relaciones entre datos, se definen las relaciones
entre datos para enlazar tipos de registros relacionados para el procesamiento de archivos
múltiples. En el nivel conceptual la base de datos aparece como una colección de registros
lógicos, sin descriptores de almacenamiento. En realidad los archivos conceptuales no
existen físicamente. La transformación de registros conceptuales a registros físicos para el
almacenamiento se lleva a cabo por el sistema y es transparente al usuario.
• Nivel de visión. Nivel más alto de abstracción, es lo que el usuario final puede visualizar
del sistema terminado, describe sólo una parte de la base de datos al usuario acreditado
para verla. El sistema puede proporcionar muchas visiones para la misma base de datos.
Se puede definir un modelo como una representación de la realidad que contiene las característi-
cas generales de algo que se va a realizar. En base de datos, esta representación se realiza de
forma gráfica.
Un modelo de datos, es una colección de herramientas conceptuales para describir los datos, las
relaciones que existen entre ellos, semántica asociada a los datos y restricciones de consistencia.
Los modelos de datos se dividen en tres grupos: 1) Modelos lógicos basados en objetos. 2)
Modelos lógicos basados en registros. 3) Modelos físicos de datos.
• Modelos lógicos basados en objetos. Se utilizan para describir datos en los niveles concep-
tual y de visión. Los datos se representan como son captados en el mundo real. Estos
modelos tienen una capacidad de estructuración bastante flexible y permiten especificar
restricciones de datos explícitamente. Existen diferentes modelos de este tipo, pero el más
utilizado por su sencillez y eficiencia es el modelo Entidad-Relación (E-R).
• Modelos lógicos basados en registros. Se utilizan para describir datos en los niveles con-
ceptual y físico. Estos modelos utilizan registros e instancias para representar la realidad,
así como las relaciones que existen entre estos registros. A diferencia de los modelos de
datos basados en objetos, se usan para especificar la estructura lógica global de la base de
datos y para proporcionar una descripción a nivel más alto de la implementación. Los tres
modelos de datos más ampliamente aceptados son: modelo relacional, modelo de red y
modelo jerárquico.
• Modelos físicos de datos. Se utilizan para describir a los datos en el nivel más bajo, aunque
existen muy pocos modelos de este tipo, básicamente capturan aspectos de la implementa-
ción de los sistemas de base de datos. Existen dos clasificaciones de este tipo que son:
modelo unificador y memoria de elementos.
Un sistema de base de datos se encuentra dividido en módulos cada uno de los cuales controla
una parte de las tareas del sistema. En la mayoría de los casos, el sistema operativo proporciona
únicamente los servicios más básicos y el sistema de base de datos debe partir de esa base y con-
trolar además el manejo correcto de los datos. Así, el diseño de un sistema de base de datos debe
incluir la interfaz entre el sistema de base de datos y el sistema operativo.
Usuarios
Código objeto de
Gestor de Sistema de Gestión
programas de
archivos de Bases de Datos
aplicación
Gestor de
archivos
Almacenamiento en disco
13.1 INTRODUCCIÓN
En este tema se tratan los cuatro primeros pasos, dejando el quinto para el resto de los temas
dedicados al lenguaje SQL en el sistema de gestión de bases de datos MySQL.
Como se ha indicado, el proceso de diseño de una base de datos consiste en pasar de un problema
real, planteado por un cliente, a su implementación en el ordenador. Para ello se deben realizar
los siguientes pasos:
• Definición del problema. Para poder definir el problema lo primero que hay que hacer es
hablar con el cliente para saber qué quiere y qué necesita. Esta tarea no es simple, ya que,
por lo general, el cliente tampoco sabe lo qué puede pedir (de hecho, es habitual que ni
siquiera sepa qué es lo que necesita). Los modelos conceptuales ayudan en esta fase del
diseño, pues facilitan una forma clara de ver el proceso en su totalidad mediante una repre-
sentación gráfica. Por otra parte, los modelos conceptuales no están orientados a ningún
sistema físico concreto, ni tienen una orientación informática clara, lo que facilita su com-
prensión por personas sin conocimientos de programación. También es importante obser-
var el funcionamiento del proceso que se quiere informatizar, ya que, generalmente, lo que
13.2 DISEÑO DE BASES DE DATOS RELACIONALES
se quiere hacer ya se realiza de forma manual o con un pequeño apoyo ofimático. El obje-
tivo de esta observación es conocer qué tipo de información se necesita y qué parte de ella
se utiliza con mayor frecuencia.
• Modelo conceptual. Una vez definido el problema, el siguiente paso es crear un modelo
conceptual. El modelo más usado en bases de datos es el modelo Entidad-Relación (E-R).
Durante esta fase, se tendrán que tomar decisiones que en cierto modo limitarán el modelo.
• Modelo lógico. La siguiente fase es convertir el modelo conceptual en un modelo lógico.
Existen varios modelos lógicos, pero el más usado y el que mejor se adapta a MySQL es el
modelo relacional. La conversión entre el modelo conceptual y el lógico es bastante mecá-
nica, aunque no por ello será siempre sencilla.
• Verificación. En el caso del modelo lógico relacional, existe un proceso que sirve para
verificar que se ha realizado bien el modelo, y en caso contrario, corregirlo. Este proceso
se llama normalización.
• Modelo físico. El último paso consiste en codificar el modelo lógico en un modelo físico.
Este proceso está ligado con el SGBD elegido, lo que requiere conocimientos del lenguaje
a utilizar. En el caso de MySQL, se requiere el conocimiento del lenguaje SQL.
El modelo Entidad-Relación (E-R), representa la realidad a través de entidades, que son objetos
que existen y que se distinguen de otros por sus características. Las entidades pueden ser de dos
tipos: 1) Tangibles, objetos físicos que se pueden ver, tocar o sentir. 2) Intangibles, eventos u
objetos conceptuales que no se pueden ver, aun sabiendo que existen. Las características de las
entidades en base de datos se llaman atributos. A su vez una entidad se puede asociar o relacio-
nar con más entidades a través de relaciones.
En esencia, el modelo E-R, consiste en buscar las entidades que describan los objetos que inter-
vienen en el problema y las relaciones entre esas entidades. Todo esto se representa en un
esquema gráfico que tiene por objeto, ayudar al programador durante la codificación y al usuario
a comprender el problema y el funcionamiento del programa.
• Relación. Asociación o conexión entre entidades. Ejemplo, la que existe entre un alumno
concreto y una asignatura concreta.
• Conjunto de relaciones. Asociación o conexión entre conjuntos de entidades. Ejemplo, la
que existe entre el conjunto de entidades alumnos y el conjunto de entidades asignaturas.
• Grado. Número de conjuntos de entidades que intervienen en una relación: Ejemplo, la
relación anterior es de grado 2 o binaria.
• Clave. Conjunto de atributos que identifican de forma unívoca una entidad. Cada entidad
se puede distinguir de otra por sus atributos (el conjunto completo de todos los atributos no
se puede repetir nunca). A menudo sólo cierto subconjunto de atributos diferencian una
entidad. En algunas casos se crea un atributo artificial para usarlo sólo como clave (clave
artificial). Ejemplo, en las entidades alumno, el nombre por si mismo, no es una clave, ya
que hay muchas personas con el mismo nombre (lo mismo ocurre con nombre y apelli-
dos). Si se considera el número de DNI, pueden surgir problemas con alumnos de distintas
nacionalidades o con menores de edad, que normalmente no disponen de DNI. En este
caso, se puede crear un atributo artificial número de expediente, para usarlo sólo como
clave.
• Claves candidatas. Una característica que se debe buscar siempre en las claves es que con-
tengan el número mínimo de atributos. Una clave es mínima cuando si se elimina cual-
quiera de los atributos que la componen, deja de ser clave. Si en una entidad existe más de
una de estas claves mínimas, cada una de ellas es una clave candidata. Clave candidata, es
cada una de las claves mínimas existente en un conjunto de entidades.
• Clave primaria o principal. Clave candidata elegida de forma arbitraria, que se utilizará
siempre para identificar una entidad.
• Claves de relaciones. Para definir una relación se utilizarán las claves primarias de las
entidades relacionadas. De este modo, el identificador de una relación es el conjunto de las
claves primarias de cada una de las entidades relacionadas.
• Entidades fuertes y débiles. A menudo la clave de una entidad está ligada a la clave princi-
pal de otra. La diferencia es que las entidades débiles no necesitan una clave primaria, sus
claves siempre están formadas como la combinación de una clave primaria de una entidad
fuerte y otros atributos. Además, la existencia de las entidades débiles está ligada o subor-
dinada a la de la fuerte. Es decir, existe una dependencia de existencia (si se elimina una
entidad fuerte, se deberá eliminar también todos las entidades débiles que dependan de
ella). Ejemplo, una entidad expediente, que usa la clave de un alumno y añade otros atribu-
tos como calificaciones, es una entidad débil, en contraposición a la entidad alumno, que
es una entidad fuerte. Si se elimina a un alumno, se debe eliminar también su expediente.
• Dependencia de existencia. Se produce una dependencia de existencia entre una entidad,
subordinada, y otra, dominante, cuando la eliminación de la entidad dominante, conlleva
también la eliminación de la entidad o entidades subordinadas. Desde cierto punto de
vista, se puede considerar que las entidades dominantes y sus entidades subordinadas for-
man parte de una misma entidad.
Entidad Entidad
Relación
• Cardinalidad de asignación. Es una restricción que expresa el número de entidades con las
que puede asociarse otra entidad, mediante un conjunto de relaciones. En los extremos de
las líneas que parten del rombo del conjunto de relaciones, se pueden añadir unos números
que indican la cantidad de entidades que intervienen. Esto también se suele hacer modifi-
cando el extremo de las líneas o utilizando flechas. Si terminan con un extremo involucran
a una entidad, si terminan en varios extremos o flechas involucrarán a varias entidades.
Sobre las líneas a veces se añade el rol que representa cada entidad. La cardinalidad de
asignación es más útil para describir conjuntos binarios de relaciones, aunque ocasional-
mente contribuyen a la descripción de conjuntos de relaciones que implican más de dos
conjuntos de entidades. Para un conjunto binario de relaciones R entre los conjuntos de
entidades A y B, la cardinalidad de asignación puede ser una de las siguientes: 1) Una a
una (1:1), una entidad A está asociada a lo sumo con una entidad B y viceversa. 2) Una a
muchas (1:N), una entidad A está asociada con un número cualquiera de entidades B, sin
embargo una entidad B puede estar asociada a lo sumo con una entidad A. 3) Muchas a
una (N:1), una entidad A está asociada a lo sumo con una entidad B, aunque una entidad B
puede estar asociada a un número cualquiera de entidades A. 4) Muchas a muchas (N:N),
una entidad A está asociada con un número cualquiera de entidades B, y viceversa.
1 n
Entidad1 Relación Entidad2
Descripción
Dominio
ISA
Para construir un modelo E-R, se puede dividir el proceso en varias tareas más simples. El pro-
ceso completo es iterativo y una vez terminado se debe volver al comienzo, repasar el modelo
obtenido y, probablemente, modificarlo. Una vez conformes con el modelo obtenido se pasará a
la siguiente fase de diseño (modelo lógico).
Uno de los primeros problemas que se presentan en la construcción del modelo E-R, es decidir
qué son entidades y qué atributos. La regla principal es que una entidad sólo debe contener infor-
mación sobre un único objeto real. Pero en ciertos casos esto puede obligar a crear entidades con
un único atributo. Una regla que puede ayudar en esta decisión es que si una entidad sólo tiene un
atributo, que sirve para identificarlo, entonces esa entidad puede ser considerara como un atri-
buto.
Otro problema frecuente se presenta con los atributos multivaluados. Pero, aunque como su pro-
pio nombre indica no dejan de ser atributos, es mejor considerar a los atributos multivaluados
como entidades débiles subordinadas. Esto evitará muchos problemas con el modelo lógico rela-
cional.
Para crear un diagrama conceptual no existe un procedimiento universal, pero se pueden dar
algunas directrices generales:
• Hablar con el cliente e intentar dejar claros los parámetros y objetivos del problema a
modelar.
• Estudiar el planteamiento del problema para identificar los conjuntos de entidades útiles
para modelar el problema e identificar los conjuntos de relaciones y determinar su grado y
tipo.
• Trazar un primer diagrama E-R.
• Identificar atributos y dominios para los conjuntos de entidades y relaciones.
• Seleccionar las claves primarias para los conjuntos de entidades.
• Verificar que el modelo resultante cumple el planteamiento del problema.
Ejemplo. Crear un diagrama conceptual de una base de datos para un centro de enseñanza que
contenga información sobre los alumnos, las asignaturas y las calificaciones que los alumnos
obtienen en cada una de las asignaturas. Para cada alumno habrá que almacenar su nombre, ape-
llido, DNI y domicilio, y para cada asignatura su nombre y curso al que pertenece.
• Indentificar los atributos. Como se indica en el enunciado los atributos para cada conjunto
de entidades serán: ALUMNOS (nombre_alum, apellido, dni, domicilio), ASIGNATU-
RAS (nombre_asig, curso), ALUM-ASIG (nota).
• Seleccionar las claves primarias. Para no complicar el diagrama final, se considerarán
como claves primarias dni para ALUMNOS y nombre_asig para asignaturas. Con ello se
está asumiendo que todo alumno posee DNI y que los nombres de las asignaturas que se
imparten en el centro son distintos. En un planteamiento más realista, y ante la posibiliad
de alumnos sin DNI o asignaturas de distitos cursos con igual nombre, se podría haber
obtado por utizar dos claves artificiales número de expediente y código de asignatura. La
clave de la relación ALUM-ASIG, estará formada por las claves de los dos conjuntos de
entidades.
• Verificar el modelo. En la figura se muestra el modelo E-R resultante, que cumple las espe-
cificaciones del enunciado. En este caso se ha optado por no utilizar flechas para indicar
que la relación es de muchos a muchos, ni subrallar las claves.
dni domicilio
Entre los modelos lógicos, el modelo relacional está considerado como el más simple y es el más
extendido (MySQL está orientado principalmente a bases de datos relacionales). El modelo rela-
cional se compone de tres partes: 1) Estructura de datos, básicamente formada por relaciones. 2)
Manipulación de datos, conjunto de operadores para recuperar, derivar o modificar los datos
almacenados. 3) Integridad de datos, colección de reglas que definen la consistencia de la base
de datos.
Como se ha apuntado, uno de los aspectos relativos a los datos de los que se ocupa el modelo
relacional es el de su representación o estructura. Una base de datos relacional se representa
mediante un conjunto de tablas, a cada una de las cuales se le asigna un nombre exclusivo. Cada
tabla, está formada por filas y columnas y en ella se encuentran los datos. Además, a cada
columna se le asigna un nombre exclusivo. Por otra parte, todos los datos que aparecen en una
misma columna deben pertenecer a un mismo dominio, entendiéndose por dominio, el conjunto
de valores permitidos para los datos que aparecen en cada una de las columnas.
Si D1, D2, ..., Dn denotan los dominios correspondientes a cada una de las n columnas de la
tabla, respectivamente, sus filas serán tuplas <d1,d2,...,dn>, donde los valores di pertenecen a los
dominios Di. En tal caso, el producto cartesiano de los distintos dominios D1 x D2 x ... x Dn, es
un conjunto cuyos elemento son todas las posibles tuplas <d1,d2,...,dn>. Por lo tanto, el conte-
nido de una tabla será un subconjunto del producto cartesiano que se conoce con el nombre de
relación.
Como las tablas son esencialmente relaciones, en el modelo relacional se utilizan los términos
relación, atributo y tupla en lugar de los términos tabla, columna y fila, respectivamente.
En términos formales, una relación se compone de dos partes cabecera o conjunto de atributos y
cuerpo o conjunto de tuplas. El grado n (número de atributos) de una relación permanece fijo en
el tiempo mientras que su cardinalidad m (número de tuplas) varía con éste.
Cada una de las relaciones que forma parte de un sistema relacional puede ser de alguno de los
siguientes tipos:
• Relación base. Relación que forma parte de la base de datos.
• Vista. Relación virtual definida en función de otras relaciones (no posee datos propios
almacenados).
• Instantánea. Relación definida en función de otras relaciones (posee datos propios almace-
nados).
• Resultado de consulta. Relación resultante de alguna consulta especificada.
• Resultado intermedio. Relación resultante de alguna expresión relacional anidada dentro
de otra expresión.
• Relación temporal. Relación que se destruye en algún momento sin que el usuario realice
ninguna acción para ello.
Una base de datos relacional se puede definir como una base de datos percibida por el usuario
como una colección de relaciones normalizadas de diversos grados que varía con el tiempo.
• Clave alternativa. Cada una de las claves candidatas que no son clave primaria, si es que
existen.
• Clave foránea (o externa). Es el atributo (o conjunto de atributos) dentro de una relación
que contienen claves primarias de otra relación. No hay nada que impida que ambas rela-
ciones sean la misma.
• Interrelación. Dos relaciones están interrelacionadas cuando una posee una clave foránea
de la otra. Cada una de las claves foráneas de una relación establece una interrelación con
la relación donde esa clave es la principal. Según esto, existen dos tipos de interrelación:
1) La interrelación entre entidades fuertes y débiles. 2) La interreación pura, entre entida-
des fuertes. Extrictamente hablando, sólo la segunda es una interrelación, pero en el
modelo relacional ambas tienen la forma de relaciones, al igual que las entidades com-
puestas, que son interrelaciones con atributos añadidos. Como en el modelo E-R, existen
varios tipos de interrelación: 1) Uno a uno, a cada tupla de una relación le corresponde una
y sólo una tupla de otra. 2) Uno a varios, a cada tupla una relación le corresponden varias
en otra. 3) Varios a varios, cuando varias tuplas de una relación se pueden corresponder
con varias tuplas en otra.
Ejemplo. A partir del modelo obtenido en la sección anterior para un centro de enseñanza, obte-
ner su correspondiente modelo relacional.
Para realizar las consultas de la base de datos, el álgebra relacional dispone de un conjunto de
operaciones básicas y de la operación de asignación. Esta última asigna el valor de alguna
expresión del álgebra a una relación nombrada. Por otra parte, cada operación toma una o dos
relaciones como entrada y produce una nueva relación como salida.
Además de estas ocho operaciones básicas se define la operación renombrar, que permite cam-
biar de nombre los atributos, y otras operaciones adicionales (ampliación, resumen y división
generalizada). Las ocho operaciones básicas no constituyen un conjunto mínimo. Así, las opera-
ciones reunión, intersección y división se pueden definir a partir de las otras cinco.
Para poder definir estas operaciones es necesario saber lo que se entiende por compatibilidad res-
pecto a la unión y compatibilidad respecto al producto:
• Dos relaciones son compatibles respecto a la unión si, y sólo si, sus cabeceras son idénti-
cas, lo que significa que: 1) Las dos tienen el mismo conjunto de nombres de atributos. 2)
Los atributos correspondientes se definen sobre el mismo dominio.
• Dos relaciones son compatibles respecto al producto si, y sólo si, sus cabeceras son disjun-
tas (no contienen nombres de atributos iguales).
Operación renombrar
En una relación, los nombres de los atributos que forman su cabecera deben ser distintos. Esto no
impide que, en una base de datos relacional, pueda existir más de una relación con un mismo
nombre para alguno de sus atributos. En tal caso, si mediante una operación se llega a otra rela-
ción que los contenga, se estaría incumpliendo la exigencia indicada. Así, si R1 y R2 son dos
relaciones en las que un atributo de R1 y otro atributo de R2 tienen el mismo nombre, y se
obtiene una nueva relación con los atributos de R1 y los atributos de R2, en ésta aparecerán dos
atributos con nombres iguales. Para evitar esta duplicidad se introduce la operación renombrar,
cuya misión es cambiar de nombre los atributos que sean necesarios antes de realizar una opera-
ción que pueda llevar a una relación con una cabecera en la que aparezcan dos atributos con el
mismo nombre.
• Operación renombrar . A partir de una relación R, crea una nueva copia de ésta en la que
sólo se han modificado los nombres de aquellos atributos (atributos_originales) que se
quieren renombrar (atributos_nuevos). La sintaxis del operador es:
R atributos_nuevos (atributos_originales)
Ejemplo 1. Sea la relación, ALUMNOS (dni, nombre_alum, apellido, domicilio), para cambiar
de nombre los atributos apellido y domicilio, por apellido_alum y domicilio_alum, respectiva-
mente, se utilizará:
Operaciones de conjuntos
• Unión ». La unión de dos relaciones R1 y R2, compatibles respecto a la unión, es otra rela-
ción cuya cabecera es idéntica a la de R1 (o a la de R2), y cuyo cuerpo está formado por
todas las tuplas pertenecientes a R1, a R2 o a las dos. La unión construye una relación for-
mada por todas las tuplas que aparecen en cualquiera de las dos relaciones especificadas.
La sintaxis de la operación es: R1 » R2
• Intersección «. La intersección de dos relaciones R1 y R2, compatibles respecto a la unión,
es una relación cuya cabecera es idéntica a la de R1 (o a la de R2) y cuyo cuerpo está for-
mado por todas las tuplas pertenecientes tanto a R1 como a R2. La intersección construye
una relación formada por todas las tuplas que aparecen en las dos relaciones especificadas.
La sintaxis de la operación es: R1 « R2
• Diferencia -. La diferencia de dos relaciones R1 y R2, compatibles respecto a la unión, es
una relación cuya cabecera es idéntica a la de R1 (o a la de R2) y cuyo cuerpo está formado
por todas las tuplas pertenecientes a R1 pero no a R2. La diferencia construye una relación
formada por todas las tuplas de la primera relación que no aparecen en la segunda de las
dos relaciones especificadas. La sintaxis de la operación es: R1 - R2
• Producto cartesiano x. El producto cartesiano de dos relaciones R1 y R2, compatibles res-
pecto al producto, es una relación cuya cabecera es la combinación de las cabeceras de R1
y R2 y cuyo cuerpo está formado por el conjunto de todas las tuplas t tales que t es la com-
Ejemplo 2. Sean ALUMNOS_1 y ALUMNOS_2 dos relaciones en las que aparecen las tuplas de
los alumnos con domicilio en madrid y los alumnos de nombre juan, respectivamente.
ALUMNOS_1
ALUMNOS_2
Estas relaciones son compatibles respecto a la unión por tener el mismo conjunto de nombres de
atributos y estar los atributos del mismo nombre definidos en el mismo dominio. Por lo tanto,
con ellas se podrán realizar las operaciones: unión, intersección y diferencia.
La unión de las dos relaciones indicadas es otra con la misma cabecera que éstas y en cuyo
cuerpo están todas las tuplas de las dos relaciones. Obsérvese como no aparecen las tuplas repeti-
das.
ALUMNOS_1 » ALUMNOS_2
La intersección de éstas relaciones es otra con la misma cabecera y en cuyo cuerpo aparecen las
tuplas que están simultáneamente en ellas.
ALUMNOS_1 « ALUMNOS_2
La diferencia ALUMNOS_2 - ALUMNOS_1 es una relación con la misma cabecera que las rela-
ciones que aparecen en la expresión y en cuyo cuerpo están las tuplas que pertenecen a
ALUMNOS_1 pero no a ALUMNOS_2. Observesé que este resultado es distinto a
ALUMNOS_2 - ALUMNOS_1.
ALUMNOS_1 - ALUMNOS_2
Estas relaciones son compatibles respecto al producto ya que, sus cabeceras no tienen nombres
de atributos iguales. Si en lugar de nombre_alum y nombre_asig, se hubiera utilizado el atributo
nombre en las dos relaciones, para que éstas fueran compatbles respecto al producto, habría que
renombrar el atributo nombre en alguna de las dos relaciones.
El producto cartesiano de estas dos relaciones es otra relación, en cuya cabecera aparecen los
atributos de las dos relaciones:
y su cuerpo está formado por todas las combinaciones de tuplas de las dos relaciones.
Operaciones relacionales
• Selección . La selección de tuplas de una relación R, es otra relación con la misma cabe-
cera que la de R y cuyo cuerpo esta formado por las tuplas de R que verifican una condi-
ción impuesta a los atributos. En la condición pueden aparecer operadores de comparación
(=, <>, >, >=) y booleanos (AND, OR, NOT). La selección extrae las tuplas especificadas
de una relación dada, es decir, restringe la relación sólo a las tuplas que satisfacen la condi-
ción. Los atributos que aparecen en la condición deben estar definidos sobre el mismo
dominio. La sintaxis de la operación es: condición (R)
• Proyección . La proyección de la relación R según los atributos A1, A2, …, An, es otra
relación que tiene como cabecera la formada por los atributos indicados y en cuyo cuerpo
aparecen todas las tuplas de R restringidas a dichos atributos, eliminando las tuplas repeti-
das. La sintaxis de la operación es: A1, A2, ..., An (R)
• Reunión. La reunión de dos relaciones específicas, es otra relación que contiene todas las
posibles combinaciones de tuplas, una de cada una de las dos relaciones, tales que las dos
tuplas participantes en la combinación satisfacen una condición especificada. Se conside-
ran dos tipos de reunión, la reunión natural y la reunión theta.
• Reunión natural *. Sea (A1, A2, ..., Am, B1, B2, ..., Bn) la cabecera de una relación R1 y
(B1, B2, ..., Bn, C1, C2, ..., Cp) la cabecera de otra relación R2, estando los atributos del
mismo nombre definidos en el mismo dominio. Si se consideran los tres atributos com-
puestos A (A1, A2, ..., Am), B (B1, B2, ..., Bn) y C (C1, C2, ..., Cp), la reunión natural de
R1 y R2 es una relación con la cabecera (A, B, C) y un cuerpo formado por el conjunto de
todas las tuplas (A:a, B:b, C:c) tales que una tupla t1 aparece en R1 con el valor a en A y el
valor b en B, y una tupla t2 aparece en R2 con el valor b en B y el valor c en C. La reunión
natural de dos relaciones específicas, es otra relación que contiene todas las posibles com-
binaciones de tuplas, una de cada una de las dos relaciones, tales que las dos tuplas partici-
pantes en la combinación tengan los mismos valores en los atributos comunes. La sintaxis
de la operación es: R1 * R2
• Reunión theta |x|. Sean las relaciones R1 y R2 compatibles respecto al producto y sea theta
un operador. La reunión theta de la relación R1 según el atributo A con la relación R2
según el atributo B, es una relación con la misma cabecera que el producto cartesiano de
R1 y R2, y un cuerpo formado por el conjunto de todas las tuplas t, tales que t pertenece a
la relación resultante si la evaluación de la condición A theta B resulta verdadera. Los atri-
butos A y B deberán estar definidos en el mismo dominio y la operación theta debe ser
aplicable a dicho dominio. La reunión theta de dos relaciones específicas, es otra relación
con las mismas tuplas que el producto cartesiano eliminando aquellas que no verifican la
condición. La sintaxis de la operación es: R1 |x| A theta B R2
• División ³. Sea (A1, A2, ..., Am, B1, B2, ..., Bn) la cabecera de una relación R1 y (B1, B2,
..., Bn) la cabecera de otra relación R2, estando los atributos del mismo nombre definidos
en el mismo dominio. Si se consideran los dos atributos compuestos A y B, la división de
R1 (dividendo) entre R2 (divisor), es otra relación con la cabecera (A) y un cuerpo for-
mado por el conjunto de todos los valores de R1 en el atributo A, cuyos valores correspon-
dientes en el atributo B incluyen a todos los valores del atributo B en la relación R2. La
división toma dos relaciones, una binaria y otra unaria, y construye una relación formada
por todos los valores de un atributo de la relación binaria que concuerdan, en el otro atri-
buto, con todos los valores en la relación unaria. La sintaxis de la operación es: R1 ³ R2
ALUMNOS
Para obtener las tuplas de los alumnos con apellido=perez y domicilio=barcelona, se utiliza:
RESULTADO_1
Si a partir de la relación anterior, se quieren obtener sólo los valores de sus atributos dni y
nombre_alum, se utilizará la siguiente expresión:
RESULTADO_2
dni nombre_alum
0007 raquel
0001 juan
ALUM_ASIG
0005 idioma_2 4
0016 lengua_3 8
0002 fisica_1 5
RESULTADO_3
Para obtener una relación con las cabeceras de RESULTADO_2 y ALUM_ASIG, en la que apa-
rezcan las combinaciones de tuplas de estas dos relaciones, tales que, en una misma tupla, el
valor del atributo dni de RESULTADO_2 sea menor que el valor del atributo dni de la relación
ALUM_ASIG, habrá que evaluar las siguientes expresiones.
En primer lugar, como estas dos relaciones no son compatibles respecto al producto, ya que tie-
nen un atributo con el mismo nombre (dni), habrá que obtener primero una relación, que se deno-
tará por RESULTADO_4, a partir de cualesquiera de las relaciones anteriores, con este atributos
renombrados:
RESULTADO_4
dni_R2 nombre_alum
0007 raquel
0001 juan
RESULTADO_5
DIVIDENDO
atributo_1 atributo_2
dato_1 dato_5
dato_2 dato_5
dato_3 dato_6
dato_1 dato_6
dato_4 dato_7
DIVISOR
atributo_2
dato_5
dato_6
RESULTADO_6
atributo_1
dato_1
Las modificaciones de claves primarias deben estar muy bien controladas. Dado que una clave
primaria identifica de forma unívoca a una tupla en una relación, parece poco lógico que exista
necesidad de modificarla, ya que eso implicaría que no se está definiendo la misma entidad. Ade-
más, hay que tener en cuenta que las claves primarias se usan frecuentemente para establecer
interrelaciones, lo cual implica que sus valores se usan en otras relaciones. Si se modifica un
valor de una clave primaria hay que ser muy cuidadoso con el efecto que esto puede tener en
todas las relaciones en las que se guarden esos valores.
Existen varias maneras de limitar la modificación de claves primarias. Tres de ellas son:
• Que sólo un número limitado de usuarios puedan modificar los valores de claves prima-
rias. Estos usuarios deben ser conscientes de las repercusiones de tales cambios, y deben
actuar de modo que se mantenga la integridad.
• La prohibición absoluta de modificar los valores de claves primarias. Modificarlas sigue
siendo posible, pero mediante un mecanismo indirecto. Primero hay que eliminar las
tuplas cuyas claves se quieren modificar y a continuación darlas de alta con el nuevo valor
de clave primaria.
• La creación de un comando distinto, del que se usa para modificar el resto de los atributos,
para modificar atributos que son claves primarias o partes de ellas.
Integridad referencial
La integridad referencial se refiere a las claves foráneas. Una clave foránea es un atributo de una
relación, cuyos valores se corresponden con los de una clave primaria en otra o en la misma rela-
ción. Este mecanismo se usa para establecer interrelaciones.
mina la tupla con el valor de clave primaria clave1, en todas las tuplas donde aparezca ese
valor como clave foránea se sustituirá por NULL.
13.5 NORMALIZACIÓN
Considerese el caso de una base de datos para un centro de enseñanza que contenga información
sobre los alumnos, las asignaturas y las calificaciones que los alumnos obtienen en cada una de
las asignaturas. Donde para cada alumno hay que almacenar su nombre, apellido, DNI y domici-
lio, y para cada asignatura su nombre y curso al que pertenece.
Una posibilidad sería crear una tabla, denominada CENTRO, con todos los datos:
Es fácil darse cuenta que esta base de datos no se encuentra demasiado bien diseñada, debido al
alto grado de redundancia que existe. Observese que para cada nueva asignatura, es necesario
introducir de nuevo todos los datos del alumno. Esta redundancia a su vez puede provocar graves
problemas. Si un alumno cambia de domicilio, sería necesario actualizar al nuevo valor todas las
tuplas en las que aparece. Otro problema que se plantea es que, en el momento en no existan
alumnos matriculados en una asignatura, no existirían datos sobre ella.
La normalización es una herramienta que permite verificar el diseño de una base de datos. Si se
han diseñado bien los modelos conceptual y lógico de la base de datos, la normalización general-
mente no requerirá cambios en dicho diseño. Antes de poder aplicar el proceso de normalización,
se debe garantizar que la base de datos cumple con la definición de base de datos relacional.
La teoría puede ayudar a resolver este problema, clasificando las dependencias en distintos tipos
e indicando sus características:
• Dependencia funcional. Sean X e Y subconjuntos de atributos de una relación R. Se dice
que Y tiene una dependencia funcional de X, o que X determina a Y, si cada valor de X
tiene asociado siempre un único valor de Y.
• Dependencia funcional completa. En una dependencia funcional, cuando X es un conjunto
de atributos, decimos que la dependencia funcional es completa , si sólo depende de X, y
no de ningún subconjunto de X.
• Dependencia funcional elemental. Un dependencia completa es una dependencia funcio-
nal elemental si Y es un atributo, y no un conjunto de ellos.
• Dependencia funcional trivial. Una dependencia funcional es trivial cuando Y es parte de
X. Esto sucede cuando X es un conjunto de atributos, e Y es a su vez un subconjunto de X.
• Dependencia funcional transitiva. Si se tiene una relación R con tres conjuntos de atribu-
tos: X, Y y Z, y X determina Y e Y determina Z, pero Y no determina X. En ese caso, Z
tiene dependencia transitiva con respecto a X, a través de Y.
• Dependencias multivaluadas. Se presentan cuando existen atributos multibaluados. Un
atributo es multivaluado cuando para una misma entidad puede tomar varios valores dife-
rentes, con independencia de los valores que puedan tomar el resto de los atributos. Siem-
pre se puede evitar el problema de los atributos multivaluados separándolos en relaciones
distintas. En una relación R con los atributos X, Y y Z existe una dependencia multivalu-
dada de Y con respecto a X si los posibles valores de Y para un par de valores de X y Z
dependen únicamente del valor de X.
• Dependencias de reunión. Es una restricción sobre una relación en cuestión. Se dice que la
relación R satisface la dependencia de reunión (X,Y,...,Z) si y sólo si R es igual a la
reunión de sus proyecciones según X,Y,...,Z donde X,Y,...,Z son subconjuntos del conjunto
de atributos de R. Las dependencias de reunión vienen dadas por restricciones que el dise-
ñador impone sobre la tabla.
• Tercera forma normal (3FN). Una relación R se encuentra en tercera forma normal (3FN)
si y sólo si está en 2FN y todos los atributos no clave dependen de manera no transitiva de
la clave primaria. La tercera forma normal consiste en eliminar las dependencias transiti-
vas. Es decir, se debe eliminar cualquier relación que permita llegar a un mismo dato de
dos o más formas diferentes. Si una relación R(A,B,C) con clave primaria (A), donde C
depende funcionalmente de B, no se encuentra en 3FN, entonces la relación R puede des-
componerse en dos relaciones R1(A,B) y R2(B,C), donde al menos una de ellas se encuen-
tre en 3FN.
• Forma normal de Boycce Codd (FNBC). Se define un determinante como un atributo del
cual depende funcionalmente de manera completa de algún otro atributo. Una relación está
en FNBC si y sólo si todo determinante es una clave candidata. Otra definición equivalente
es: una relación está en FNBC si cualquier atributo sólo facilita información sobre claves
candidatas, y no sobre atributos que no formen parte de ninguna clave candidata. Esto sig-
nifica que no deben existir interrelaciones entre atributos fuera de las claves candidatas. En
realidad son muy pocos los casos de relaciones que se encuentran en 3FN y no están en
FNBC. Este tipo de tablas son aquellas en las que se dan las siguientes circunstancias: 1)
Existan varias claves candidatas. 2) Las claves candidatas son compuestas. 3) Las claves
candidatas se solapan (tienen por lo menos un atributo común). En estos casos, si en una
relación R(A,B,C,D) con claves candidatas (A,B) y (B,C) y tal que A y C dependen fun-
cionalmente una de otra, entonces la relación R se puede descomponer de cualquiera de las
dos siguientes maneras R1(A,C) y R2(B,C,D) o R1(A,C) y R2(A,B,D).
• Cuarta forma normal (4FN). Una relación R se encuentra en cuarta forma normal 4FN si y
sólo si está en FNBC y no existen dependencias multivaluadas. La cuarta forma normal
tiene por objetivo eliminar este tipo de dependencias. En caso de tener una relación R en
FNBC y con dependencias multivaluadas, se puede descomponer sin pérdidas la relación
R, deshaciendo además las dependencias multivaluadas. Sea una relación R(A,B,C) con
las siguientes dependencias multivaluadas B depende funcionalmene de A y C depende
funcionalmene de A. Entonces la relación R puede descomponerse como R1(A,B) y
R2(A,C).
• Quinta forma normal (5FN). Una relación R se encuentra en quinta forma normal 5FN si y
sólo si toda dependencia de reunión en R es una consecuencia de las claves candidatas.
Esto viene a decir que una relación estará en 5FN cuando esté en 4FN y siempre que no
existan restricciones impuestas por el creador. Cuando una tabla se encuentra en 4FN y no
en 5FN la solución es N-descomponerla para deshacer las dependencias de reunión. Este
tipo de dependencias raramente se encuentran en las bases de datos.
Lo primero que hay que hacer siempre que se va a normalizar una relación es trazar un diagrama
de dependencias funcionales de la misma. Para ello lo mejor es localizar las claves de la relación
e ir viendo que, atributos dependen de ellas. Después se intentará ver si existe alguna dependen-
cia entre las claves y por último entre el resto de los atributos. En este caso, el diagrama es extre-
madamente sencillo, tal y como aparece a continuación (las flechas indican dependencia
funcional completa).
dni
La única clave existente es el dni que por el hecho de serlo, proporciona dependencia funcional
completa al resto de los atributos. Además entre ellos no existe ningún tipo de dependencia
debido a que pueden existir las mismas calles en ciudades distintas y a que los nombres pueden
aparecer repetidos aunque cada uno lleve un dni distinto. Con todo esto se pueden hacer las
siguientes afirmaciones:
• La relación se encuentra en 1FN debido a que los dominios son atómicos, es decir sólo se
tiene un dato en cada casilla.
• La relación se encuentra en 2FN debido a que todas las dependencias funcionales son
completas.
• La relación se encuentra en 3FN debido a que no existen dependencias funcionales transi-
tivas.
• La relación se encuentra en FNBC ya que está en 3FN y no se dan las tres características
en cuanto a solapamiento de claves.
• La relación se encuentra en 4FN debido a que no existe ninguna dependencia multiva-
luada.
• Por último afirmar que también se encuentra en 5FN porque no existe ninguna dependen-
cia de reunión.
Ejemplo 2. Normalizar la siguiente relación hasta la 5FN. En dicha relación, se almacena infor-
mación sobre los artículos que un dependiente vende (codigo y cantidad) e información sobre el
propio dependiente (dni, calle y ciudad).
Es fácil darse cuenta que el único conjunto de atributos mediante el cual se puede distinguir una
tupla de otra es el atributo compuesto (dni, codigo) y por tanto no existe ninguna otra clave can-
didata. El diagrama queda entonces como sigue:
dni ciudad
cantidad
codigo
calle
Sin embargo, es sencillo ver que las dependencias de este diagrama no son completas, ya que los
atributos calle y ciudad dependen también del atributo dni por sí solo.
dni ciudad
cantidad
codigo
calle
• La relación se encuentra en 1FN debido a que los dominios son atómicos, es decir sólo se
tiene un dato en cada casilla.
• La relación no se encuentra en 2FN debido a que existen dependencias funcionales que no
son completas. Para solucionar esto se asociarán los atributos A, B, C y D como:
A = (dni), B = (codigo), C = (cantidad), D = (calle, ciudad)
y la relación se descompone en:
R1(A, D)
R
R2(A, B, C)
R1 (dni, calle, ciudad)
R2 (dni, codigo, cantidad)
Ahora habrá estudiar los diagramas de dependencias funcionales de cada relación, y dedu-
cir si R1 y R2 se encuentran en 2FN.
R1 R2
dni
dni
cantidad
codigo
calle ciudad
Como puede verse, las dos relaciones ya se encuentran en 2FN debido a que todas las
dependencias funcionales son completas.
• Las relaciones se encuentran en 3FN debido a que no existen dependencias funcionales
transitivas.
• Las relaciones se encuentran en FNBC ya que está en 3FN y no se dan las tres característi-
cas en cuanto a solapamiento de claves.
• Las relaciones se encuentran en 4FN debido a que no existe ninguna dependencia multiva-
luada.
• Por último afirmar que también se encuentran en 5FN porque no existe ninguna dependen-
cia de reunión.
El resultado entonces de haber normalizado la relación R ha sido la división de esta en otras dos
relaciones llamadas R1 y R2.
14.1 INSTRODUCCIÓN
El objetivo principal de este capítulo, es comentar el proceso a seguir para obtener alguna de las
versiones de MySQL, y dar una serie de nociones mínimas sobre su instalación. También se indi-
can algunas de las ventajas que presenta este sistema de gestión de bases de datos. Otro de los
objetivos del capítulo, es tomar contacto por primera vez con MySQL, desde la consola del orde-
nador, en modo de línea de comandos. En particular, se indica cómo entrar y salir en la ventana
de comandos y cómo utilizar su ayuda. A continuación se pasa a tratar un tema de gran importan-
cia: la asignación de usuarios y privilegios. Cuando se trabaja con bases de datos reales y con
aplicaciones de gestión de bases de datos, es muy importante definir usuarios con distintos privi-
legios, ya que esto ayudará a proteger las bases de datos. Para terminar, se tratan los husos hora-
rios y se presenta un listado de las palabras reservadas en MySQL.
MySQL es un SGBD de libre distribución y de código abierto. Lo que significa que se puede
descargar libremente de Internet (libre distribución) y que cualquier programador puede modifi-
car su código para mejorarlo (código abierto).
El uso de MySQL, excepto en la versión Pro, está sujeto a licencia GNU public license (GPL).
Está licencia permite: 1) El uso de MySQL para crear cualquier tipo de aplicación. 2) Distribuir
copias de los archivos de MySQL, pero no venderlas a otros usuarios. 3) Modificar el código
14.2 INSTALACIÓN Y PRIMEROS PASOS CON MYSQL
fuente de MySQL, pero no distribuir la aplicación con el código modificado. La licencia comer-
cial permite otros usos no reflejados en la licencia GNU.
El primer paso, antes de instalar MySQL, es obtener alguna de sus versiones. Para ello se puede
acceder a la página principal de MySQL: http://www.mysql.com/.
Si, por ejemplo, se quiere descargar la versión 5, se pulsará sobre Download MySQL 5.0, con lo
que se accede a la siguiente ventana:
Bajando por esta ventana, se puede acceder a la versión del sistema operativo deseada (Linux,
Windows, etc).
Una vez descargado el fichero, el siguiente paso es descomprimir su contenido en una carpeta y
ejecutar setup.exe, con lo que se entra en la ventana de instalación.
Se trata de una ventana de bienvenida. Para seguir el proceso de instalación simplemente hay que
hacer clic en el botón next. Terminar de instalar el servidor depende en gran medida de cada caso,
y es mejor remitirse a la documentación facilitada por MySQL junto a cada paquete. Instalar la
versión para Windows es relativamente sencillo. El programa se instalará en una carpeta MySQL
y los ejecutables en una carpeta bin que estará dentro de la anterior.
Durante la instalación de MySQL se pedirá elegir una clave de acceso, esa clave es la que hay
que introducir para iniciar una sesión con MySQL.
El entorno se puede configurar a mano a través del archivo mysql.ini o utilizando el programa de
configuración incluido en la versión. Tras la instalación hace falta instalar el servidor MySQL de
bases de datos. Existen varias servidores posibles (en la carpeta bin): 1) mysqld, compilado con
depuración completa y chequeo automático de colocación de memoria, enlaces simbólicos,
InnoDB y tablas BDB (es el más genérico para cualquier tipo de ordenador). 2) mysqld-opt, opti-
mizado para equipos Pentium (no tiene soporte de tablas transaccionales). 3) mysqld-nt. optimi-
zado para equipos con Windows NT, 2000 y XP con soporte para pipe names. 4) mysql-max,
optimizado con soporte de enlaces simbólicos, InnoDB y tablas BDB. 5) mysql-max-nt, igual que
el anterior pero combinado las capacidades del servidor mysql-nt. Una vez instalado, se estará en
disposición de poder utilizar MySQL desde la consola del ordenador, en modo de línea de
comandos.
Para acceder a las bases de datos, es útil usar un motor o servidor que hace las funciones de intér-
prete entre éstas y las aplicaciones y usuarios. En esta utilidad se pueden destacar las siguientes
ventajas:
• Acceso a las bases de datos, de forma simultánea, por varios usuarios y aplicaciones.
• Seguridad, en forma de permisos y privilegios. Determinados usuarios tendrán permiso
para consultar o modificar ciertas tablas. Esto permite compartir datos sin que peligre la
integridad de la base de datos y protegiendo su contenido.
• Potencia. SQL es un lenguaje muy potente para consulta de bases de datos, usar un motor
ahorrará gran cantidad de trabajo.
• Portabilidad. SQL es también un lenguaje estandarizado, de modo que las consultas
hechas usando SQL son fácilmente portables a otros sistemas y plataformas.
En esta sección se comenzará a trabajar con el sistema de gestión de bases de datos MySQL.
Existen muchas formas de establecer una comunicación con el servidor de MySQL. Por lo gene-
ral se utilizará un API para realizar las consultas con el servidor. En PHP, por ejemplo, este API
está integrado con el lenguaje, y en C/C++ se trata de librerías de enlace dinámico.
En lo que sigue, se utilizará MySQL de forma directa, mediante un cliente ejecutándose en una
consola (una ventana DOS en Windows, o un Shell en otros sistemas).
Para entrar en la consola de MySQL se requieren ciertos parámetros. Hay que tener en cuenta
que el servidor es multiusuario, y que cada usuario puede tener distintos privilegios, tanto de
acceso a tablas como de comandos que puede utilizar. La forma general de iniciar una sesión
MySQL es:
mysql -h host -u usuario -p
Se puede especificar el ordenador donde está el servidor de bases de datos (host) y el nombre de
usuario. Los parámetros -h y -u indican que los valores que los siguen son, respectivamente, el
nombre del host y el nombre de usuario. El parámetro -p indica que se debe solicitar una clave de
acceso. En versiones de MySQL anteriores a la 4.1.9 es posible abrir un cliente de forma anó-
nima sin especificar una contraseña, pero las últimas versiones de MySQL no lo permiten.
Durante la instalación de MySQL se pide elegir una clave de acceso para el usuario root (admi-
nistrador), esa clave es la que hay que introducir para iniciar una sesión con el cliente MySQL.
Enter password: *******
Como se ha indicado el programa mysql, permite distintas opciones de arranque. Para conocer-
las, basta con ejecutar desde la línea de comandos:
mysql --help
Cuando se instala MySQL, se instala también el manual de referencia. Como el objetivo de este
curso no es comentar todos los detalles de MySQL, se debe recurrir a este manual cuando sea
preciso.
Otra forma de obtener información sobre los distintos comandos de MySQL es utilizar la ayuda
de la ventana de comandos. Si, una vez dentro de MySQL se teclea help, aparecerán una serie de
direcciones con información sobre MySQL y la lista de comandos. Si se teclea help contents, se
listarán las distintas categorías de comandos. Si se introduce help ‘categoría’, se listan las sen-
tencias correspondientes, y si se teclea help ‘sentencia’, se presenta su sintaxis.
mysql> help
MySQL utiliza el lenguaje de bases de datos SQL, y sus sentencias serán las que normalmente se
utilizan en el monitor. Sobre los comandos hay que tener en cuenta que: 1) Da lo mismo escribir-
los en mayúsculas o en minúsculas. 2) Para su ejecución, deben terminar con el símbolo “;". 3)
La ejecución ha terminado si en la línea de comandos aparece mysql>. 4) En la misma línea se
pueden colocar dos comandos siempre y cuando los puntos y comas se coloquen de forma ade-
cuada. 5) Una instrucción puede abarcar más de una línea (para informar que no ha terminado la
instrucción, el monitor coloca el símbolo "->", en lugar de mysql>). 6) Una instrucción se puede
anular antes del punto y coma, colocando el texto "\c". 8) Las cadenas de texto literal pueden ir
entre comillas simples o comillas dobles (si se pulsa Intro antes de cerrar la cadena, el monitor lo
índica mostrando '> o "> en lugar de “->” o mysql>.
Una de las sentencias más importantes de SQL es SELECT, que se sirve para realizar consultas.
Esta sentencia, además de permitir seleccionar datos de la bases de datos, se puede utilizar para
conocer variables del sistema, realizar operaciones o conocer el resultados de evaluar funciones,
entre otros.
Así, para conocer la versión que se está utilizando de MySQL y la fecha actual, se usan los pará-
metros VERSIÓN y CURRENTE DATE, respectivamente.
mysql> select version(), current_date;
Cuando se trabaja con bases de datos reales y con aplicaciones de gestión de bases de datos, un
aspecto importante es definir usuarios con distintos privilegios (además del root, que es el admi-
nistrador), lo que ayudará a proteger las bases de datos. Así, se podrán crear usuarios que sólo
tengan posibilidad de consultar datos, de determinadas tablas o bases de datos, pero que no ten-
gan permiso para añadirlos o modificarlos, ni permiso para modificar la estructura de la base de
datos. Otros usuarios podrán insertar datos, y sólo algunos (o mejor, sólo uno) podrán modificar
la estructura de las bases de datos (los administradores).
MySQL permite definir diferentes usuarios, y asignarles, a cada uno de ellos, distintos privile-
gios clasificados en los siguientes niveles:
• Globales. Se aplican al conjunto de todas las bases de datos.
• De base de datos. Se aplican a bases de datos individuales.
• De tabla. Se aplican a tablas individuales.
• De columna. Se aplican a una columna concreta.
• De rutina. Se aplican a los procedimientos almacenados.
En general, es preferible usar GRANT, ya que esta sentencia permite crear usuarios y conceder
privilegios (CREATE USER, sólo permite crear usuarios y los privilegios se asignan con
GRANT).
Donde:
• priv_type [(column_list)], permite definir el tipo de privilegio concedido para determina-
das columnas.
• ON {tbl_name | * | *.* | db_name.*}, permite conceder privilegios en niveles globales, de
base de datos o de tablas.
• TO user [IDENTIFIED BY [PASSWORD] 'password'], permite identificar usuarios.
ON db_name.tbl_name
Para crear usuarios se debe tener el privilegio GRANT OPTION y sólo se pueden conceder los
privilegios que se posean.
El nombre de usuario user consta de dos partes, separadas por el carácter @: nombre@máquina.
La primera es el nombre asignado al usuario y la segunda es el nombre de la máquina (localhost
para referirse al ordenador local), o cualquier otro nombre o bien una IP. La parte de la máquina
es opcional, y si no se pone, el usuario podrá conectarse desde cualquier máquina. Si se crea un
usuario para una máquina o conjunto de máquinas determinado, ese usuario no podrá conectar
desde otras máquinas.
GRANT USAGE ON * TO name@localhost IDENTIFIED BY password;
En este caso, el usuario name sólo podrá entrar desde el mismo ordenador donde se está ejecu-
tando el servidor.
GRANT USAGE ON * TO name@11.24.36.14 IDENTIFIED BY password;
En este otro caso, el usuario name sólo puede conectarse desde un ordenador cuyo IP sea
11.24.36.14.
Aunque asignar una contraseña es opcional, por motivos de seguridad es recomendable hacerlo
siempre. La contraseña se puede escribir entre comillas simples cuando se crea un usuario, o se
puede usar la salida de la función PASSWORD() de forma literal, para evitar enviar la clave en
texto legible. Si al añadir privilegios se usa una clave diferente en la cláusula IDENTIFIED BY,
sencillamente se sustituye la contraseña por la nueva.
FROM user
No se puede eliminar un usuario que tenga privilegios. Para eliminar el usuario primero hay que
revocar todos sus privilegios. Así, para eliminar un usuario que tiene el privilegio SELECT sobre
una determinada tabla, habrá que ejecutar las siguientes sentencias:
REVOKE SELECT ON db_name.tbl_name FROM user;
Cuando el servidor arranca, determina el huso horario del ordenador cliente y lo asigna a la
variable de sistema system_time_zone. Esta variable, indica el huso horario del servidor actual en
el que se está operando. Su valor inicial es SYSTEM, que indica que el huso horario del servidor
es el mismo que el del sistema. El valor inicial puede ser especificado explícitamente con la
Cada cliente que se conecta tiene su propio huso horario asignado, dado por la variable de sesión
time_zone, pero se puede modificar con la sentencia:
SET time_zone = timezone
Los valores actuales de los husos horarios global y por conexión pueden ser recuperados
mediante la sentencia:
SELECT @@global.time_zone, @@session.time_zone
Durante la instalación de MySQL se crean las tablas de husos horarios en la base de datos mysql,
pero no las carga. Esto se debe hacer de forma manual.
Si el sistema tiene su propia base de datos de información horaria, se debe usar el programa
mysql_tzinfo_to_sql para llenar las tablas de husos horarios. En la línea de comandos, hay que
pasar el nombre de la ruta del directorio con la información de husos horarios a
mysql_tzinfo_to_sql y enviar la salida al programa mysql. Ejemplo:
shell> mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql
mysql_tzinfo_to_sql lee los ficheros de husos horarios del sistema y genera sentencias SQL a par-
tir de ellos. MySQL procesa esas sentencias para cargar las tablas de husos horarios.
Para cargar un fichero tz_file, que corresponda a un huso horario llamado tz_name, se utiliza la
sentencia:
shell> mysql_tzinfo_to_sql tz_file tz_name | mysql -u root mysql
Si el huso horario precisa tener en cuenta intervalos de segundos, hay que inicializar la informa-
ción de intervalo de segundos (donde tz_file es el nombre del fichero):
shell> mysql_tzinfo_to_sql --leap tz_file | mysql -u root mysql
Si el sistema no tiene base de datos de husos horarios, como ocurre en Windows, se puede usar el
paquete de tablas de husos horarios prediseñadas que está disponible para su descarga en http://
dev.mysql.com/downloads/timezones.html. Este paquete contiene los ficheros .frm, .MYD y .MYI
para las tablas de husos horarios MyISAM. Estas tablas deben pertenecer a la base de datos mysql,
de modo que deben colocarse esos ficheros en el subdirectirio mysql del directorio de datos del
servidor MySQL. El servidor debe ser detenido mientras se hace esta operación. Este paquete no
se debe utilizar si el sistema tiene una base de datos de husos horarios (usar la utilidad
mysql_tzinfo_to_sql en su lugar), ya que se puede provocar una diferencia en la manipulación de
tiempos entre MySQL y otras aplicaciones del sistema.
Cuando se dan nombres a las bases de datos, tablas, índices, columnas y alias, hay que tener cui-
dado de que dichos nombres no sean palabras reservadas de MySQL, ya que en tal caso, se deben
entrecomillar. A continuación se indican las palabras reservadas en MySQL:
A
ADD, ALL, ALTER, ANALYZE, AND, AS, ASC, ASENSITIVE.
B
BEFORE, BETWEEN, BIGINT, BINARY, BLOB, BOTH, BY.
C
CALL, CASCADE, CASE, CHANGE, CHAR, CHARACTER, CHECK, COLLATE, COLUMN,
CONDITION, CONNECTION, CONSTRAINT, CONTINUE, CONVERT, CREATE, CROSS,
CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP, CURRENT_USER, CURSOR.
D
DATABASE, DATABASES, DAY_HOUR, DAY_MICROSECOND, DAY_MINUTE,
DAY_SECOND, DEC, DECIMAL, DECLARE, DEFAULT, DELAYED, DELETE,
DESC, DESCRIBE, DETERMINISTIC, DISTINCT, DISTINCTROW, DIV, DOUBLE, DROP, DU-
AL.
E
EACH, ELSE, ELSEIF, ENCLOSED, ESCAPED, EXISTS, EXIT, EXPLAIN.
F
FALSE, FETCH, FLOAT, FOR, FORCE, FOREIGN, FROM, FULLTEXT.
G
GOTO, GRANT, GROUP.
H
HAVING, HIGH_PRIORITY, HOUR_MICROSECOND, HOUR_MINUTE, HOUR_SECOND.
I
IF, IGNORE, IN, INDEX, INFILE, INNER, INOUT, INSENSITIVE, INSERT, INT, INTEGER, IN-
TERVAL, INTO, IS, ITERATE.
J
JOIN.
K
KEY, KEYS, KILL.
L
LEADING, LEAVE, LEFT, LIKE, LIMIT, LINES, LOAD, LOCALTIME, LOCALTIMESTAMP,
LOCK, LONG, LONGBLOB, LONGTEXT, LOOP, LOW_PRIORITY.
M
MATCH, MEDIUMBLOB, MEDIUMINT, MEDIUMTEXT, MIDDLEINT,
MINUTE_MICROSECOND, MINUTE_SECOND, MOD, MODIFIES.
N
NATURAL, NOT, NO_WRITE_TO_BINLOG, NULL, NUMERIC.
O
ON, OPTIMIZE, OPTION, OPTIONALLY, OR, ORDER, OUT, OUTER, OUTFILE.
P
PRECISION, PRIMARY, PROCEDURE, PURGE.
R
READ, READS, REAL, REFERENCES, REGEXP, RENAME, REPEAT, REPLACE, REQUIRE,
RESTRICT, RETURN, REVOKE, RIGHT, RLIKE.
S
SCHEMA, SCHEMAS, SECOND_MICROSECOND, SELECT, SENSITIVE, SEPARATOR, SET,
SHOW, SMALLINT, SONAME, SPATIA, SPECIFIC, SQL, SQLEXCEPTION, SQLSTATE, SQL-
WARNING, SQL_BIG_RESULT, SQL_CALC_FOUND_ROWS, SQL_SMALL_RESULT, SSL,
STARTING, STRAIGHT_JOIN
T
15.1 INTRODUCCIÓN
En este tema se trata el proceso para pasar del modelo lógico relacional al modelo físico usando
sentencias SQL y viendo las peculiaridades específicas de MySQL. Una base de datos está for-
mada por el conjunto de relaciones que componen un modelo lógico completo. Desde el punto de
vista de SQL, una base de datos es sólo un conjunto de relaciones o tablas que se distinguen, unas
de otras, por el nombre asociado a cada una de ellas. A nivel de sistema operativo, cada base de
datos se guarda en un directorio diferente.
Cuando se crean bases de datos, tablas, índices, columnas y alias, es necesario asignarles un
nombre. La primera parte de este capítulo, está dedicada a presentar las reglas de asignación de
nombres. A continuación se pasa a la creación de bases de datos y a su eliminación. En el caso de
las tablas, a cada columna se le debe asignar un tipo de dato, es por ello que antes de pasar a la
creación de tablas se indican los tipos disponibles en MySQL. Seguidamente se trata de forma
extensa la creación de tablas y su eliminación. Para finalizar se indica como insertar y modificar
datos en las tablas, y como importar y exportar datos.
Se denotará por identificador a los nombres de bases de datos, tablas, índices, columnas y alias.
La longitud máxima para todos ellos es de 64 bytes, excepto en el caso de nombres de alias que
es de 255 bytes. Para los identificadores de bases de datos y tablas están permitidos todos los
caracteres de nombre de directorio a excepción de (/, \, .). Para el resto están permitidos todos los
caracteres. Ningún identificador puede contener el valor ASCII 0 o un byte con el valor 255. Los
nombres de bases de datos, tablas y columnas no pueden terminar con espacios. Si un identifica-
dor es una palabra reservada o contiene caracteres especiales, se debe entrecomillar, para ello se
15.2 CREACIÓN DE BASES DE DATOS Y TABLAS E INSERCIÓN DE DATOS
utiliza la tilde izquierda. Si el modo del servidor SQL incluye la opción de modo
ANSI_QUOTES, también estará permitido entrecomillar con comillas dobles.
MySQL permite nombres con un único identificador o con múltiples identificadores separados
por puntos. Las partes iniciales de un nombre compuesto actúan como calificadores que afectan
al contexto dentro de cual, se interpreta el identificador final. Si cualquiera de los componentes
de un nombre compuesto requiere entrecomillado, hay que entrecomillar cada uno individual-
mente. No es necesario especificar un prefijo de nombre de tabla o de base de datos para hacer
referencia a una columna a no ser que la referencia pueda ser ambigua. Formas de hacer referen-
cia a una columna:
nombre_columna
nombre_tabla.nombre_columna
nombre_basedatos.nombre_tabla.nombre_columna
En MySQL, las bases de datos corresponden a directorios y a las tablas les corresponde, por lo
menos, un fichero dentro del directorio de la base de datos. Por lo tanto, la distinción entre
mayúsculas y minúsculas dependerá del sistema operativo. Así, los nombres de bases de datos y
tablas no son sensibles al tipo en Windows, y sí lo son en la mayor parte de las variantes de Unix.
En cualquier caso, no se debe hacer referencia a una base de datos o tabla usando diferentes tipos
en la misma consulta. Los nombres de columna, índices y alias de columna no son sensibles al
tipo en ninguna plataforma. Si hay problemas para recordar el tipo de letra permitido es mejor
crear siempre las bases de datos y tablas con nombres que sólo contengan caracteres en minúscu-
las.
El modo en que se almacenan los nombres de tablas y bases de datos en disco y son usados en
MySQL depende de la definición de la variable de sistema lower_case_table_names, la cual se
puede asignar cuando se arranca MySQL. Esta variable puede tomar uno de los valores siguien-
tes: 1) 0, los nombres se almacenan usando los tipos de caracteres utilizados para su creación y
las comparaciones son sensibles al tipo. 2) 1, los nombres se almacenan en minúsculas y las
comparaciones no son sensibles al tipo. 3) 2, los nombres se almacenan usando los tipos de
caracteres utilizados para su creación pero se convierten a minúscula al leerlos y las comparacio-
nes de nombres no son sensibles al tipo.
Si se está usando MySQL para un solo tipo de plataforma, generalmente no será necesario modi-
ficar la variable lower_case_table_names, pero se pueden presentar dificultades si se quieren
transferir tablas entre plataformas que tengan sistemas de ficheros con distintas sensibilidades al
tipo. Para evitar este problema, se puede hacer lower_case_table_names=1 en todos los sistemas
o hacer lower_case_table_names=0 en Unix y lower_case_table_names=2 en Windows (antes
de asignar 1 a lower_case_table_names en Unix, se deben convertir los viejos nombres de bases
de datos y tablas a minúscula antes de reiniciar MySQL).
[create_specification]
create_specification:
Donde db_name es el nombre de la base de datos que se desea crear. Para poder usar esta senten-
cia es preciso tener el privilegio CREATE. Si la base de datos ya existe y no se ha especificado IF
NOT EXISTS, se producirá un error. Las opciones create_specification sirven para especificar
características de las base de datos. Estas características se almacenan en el fichero db.opt en el
directorio de la base de datos. La clausula CHARACTER SET especifica el conjunto de caracteres
por defecto para la base de datos, y la clausula COLLATE especifica el conjunto de reglas de
comparación de caracteres por defecto para la base de datos. En MySQL las bases de datos se
implementan como directorios que contienen los ficheros correspondientes a las tablas de la base
de datos. Como no hay tablas en una base de datos cuando esta es creada, la sentencia CREATE
DATABASE sólo crea un directorio bajo el directorio data de MySQL y el fichero db.opt.
Las siguientes sentencias permiten crear una base de datos denominada prueba, conocer cuántas
bases de datos existen en el sistema y seleccionar una base de datos (en este caso prueba), res-
pectivamente. USE, no es una sentencia SQL, sino una opción de MySQL.
CREATE DATABASE prueba;
SHOW DATABASES;
USE prueba;
Al borrar una base de datos se eliminan las tablas que pueda contener.
Las siguientes sentencias permiten crear una base de datos denominada borrar, comprobar que la
base de datos ha sido creada, eliminar la base de datos borrar y comprobar que ha sido eliminada.
SHOW DATABASES;
SHOW DATABASES;
En MySQL existen diversos tipos de datos que pueden agruparse en las siguientes categorías.
CHAR
Cadena de caracteres de longitud variable. Los valores válidos para M son de 0 a 255. Los espa-
cios al final se eliminan. Si no se especifica la palabra clave BINARY estos valores se ordenan y
comparan sin distinguir mayúsculas y minúsculas.
Entero. Rango con signo entre -128 y 127. Rango sin signo de 0 a 255.
Sinónimos de TINYINT(1).
Entero. Rango con signo de -32768 a 32767. Rango sin signo de 0 a 65535.
Entero. Rango con signo entre -8388608 y 8388607. Rango sin signo, entre 0 y 16777215.
Entero. Rango con signo entre -2147483648 y 2147483647. Rango sin signo entre 0 y
4294967295.
Sinónimo de INT.
Número en coma flotante. precision menor o igual que 24 para números de precisión sencilla y
entre 25 y 53 para números en coma flotante de doble precisión. Son idénticos que los tipos
FLOAT y DOUBLE. FLOAT(X) tiene el mismo rango que los tipos FLOAT y DOUBLE corres-
pondientes, pero el tamaño mostrado y el número de decimales quedan indefinidos.
Sinónimos de DOUBLE.
Número en coma flotante sin empaquetar. Se comporta igual que CHAR, se almacena como una
cadena con un carácter para cada dígito del valor. El punto decimal y el signo '-' para valores
negativos, no se cuentan en M (pero el espacio para estos se reserva). Si D es 0, los valores no
tendrán punto decimal ni decimales. El rango de los valores DECIMAL es el mismo que para
DOUBLE, pero el rango actual para una columna DECIMAL dada está restringido por la elección
de los valores M y D. Si se especifica el modificador UNSIGNED, los valores negativos no están
permitidos. Si se omite D, el valor por defecto es 0. Si se omite M, el valor por defecto es 10.
Sinónimos de DECIMAL.
DATE
DATETIME
Fecha y hora. Rango entre '1000-01-01 00:00:00' y '9999-12-31 23:59:59'. Formato 'AAAA-MM-
DD HH:MM:SS'. Es posible asignar valores de este tipo usando tanto cadenas como números.
TIMESTAMP[(M)]
Tipo timestamp. Rango entre '1970-01-01 00:00:00' y algún momento del año 2037. Formato
'AAAA-MM-DD HH:MM:SS'. Para convertir este valor a un número, basta con sumar el valor 0.
Se puede asignar la fecha y hora actual asignando el valor NULL. El argumento M afecta al modo
en que se visualiza. Los valores se almacenan con cuatro bytes. Los valores de TIMESTAMP(M),
cuando M es 8 ó 14 se devuelven como números y para el resto de valores como cadenas.
TIME
Hora. Rango entre '-838:59:59' y '838:59:59'. Formato 'HH:MM:SS'. Se permite asignar valores
TIME usando tanto cadenas como números.
YEAR[(2|4)]
Año en formato de 2 ó 4 dígitos (por defecto es 4). Rango entre 1901 y 2155, y 0000 en el for-
mato de 4 dígitos. Entre 1970-2069 si se usa el formato de 3 dígitos (70-69). Formato AAAA. Se
permite asignar valores YEAR usando tanto cadenas como números.
TINYBLOB, TINYTEXT
BLOB o TEXT con una longitud máxima de 255 caracteres (28 - 1).
BLOB, TEXT
BLOB o TEXT con una longitud máxima de 65535 caracteres (216 - 1).
MEDIUMBLOB, MEDIUMTEXT
BLOB o TEXT con una longitud máxima de 16777215 caracteres (224 - 1).
LONGBLOB, LONGTEXT
BLOB o TEXT con una longitud máxima de 4294967298 caracteres (232 - 1).
ENUM('valor1','valor2',...)
Contiene un enumerado. Un objeto de tipo cadena que puede tener un único valor, entre una lista
de valores 'valor1', 'valor2', ..., NULL o el valor especial de error "". Un ENUM puede tener un
máximo de 65535 valores diferentes.
SET('valor1','valor2',...)
Contiene un conjunto. Un objeto de tipo cadena que puede tener cero o más valores, cada uno de
los cuales debe estar entre una lista de valores 'valor1', 'valor2', ... Un conjunto puede tener un
máximo de 64 miembros.
[(definición_create,...)]
[opciones_tabla] [sentencia_select]
Sintaxis de definición_create:
definición_columnas
| CHECK (expr)
Sintaxis de definición_columnas:
nombre_col tipo [NOT NULL | NULL] [DEFAULT valor_por_defecto]
[definición_referencia]
Sintaxis de tipo:
TINYINT[(longitud)] [UNSIGNED] [ZEROFILL]
| VARCHAR(longitud) [BINARY]
| MEDIUMTEXT | LONGTEXT
| ENUM(valor1,valor2,valor3,...)
| SET(valor1,valor2,valor3,...)
| tipo_spatial
Sintaxis de nombre_col_index:
nombre_col [(longitud)] [ASC | DESC]
Sintaxis de definición_referencia:
REFERENCES nombre_tbl [(nombre_col_index,...)]
Sintaxis de opción_referencia:
RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT
Sintaxis de opciones_tabla:
opción_tabla [opción_tabla] ...
Sintaxis de opción_tabla:
{ENGINE|TYPE} = {BDB|HEAP|ISAM|InnoDB|MERGE|MRG_MYISAM|MYISAM }
| DELAY_KEY_WRITE = {0 | 1}
| ROW_FORMAT = { DEFAULT|DYNAMIC|FIXED|COMPRESSED|REDUNTANT|COMPACT}
RAID_CHUNKS=valor
RAID_CHUNKSIZE=valor
| UNION = (nombre_tabla,[nombre_tabla...])
[COLLATE nombre_cotejo]
CREATE TABLE crea una tabla con el nombre dado en tbl_name. Para ello, se debe tener el privi-
legio CREATE. Por defecto, la tabla se crea en la base de datos actual. Se producirá un error si la
tabla ya existe y no se especifica IF NOT EXISTS, si no hay una base de datos actual o si la base
de datos no existe. El nombre de la tabla se puede especificar como db_name.tbl_name para crear
una tabla en una base de datos específica. Se puede usar la palabra clave TEMPORARY cuando
se quiere crear una tabla temporal que sólo será visible para la conexión actual y que será borrada
cuando se cierre la conexión (para crear este tipo de tabla, se debe tener el privilegio CREATE
TEMPORARY TABLES). Cada tabla tbl_name se representa mediante ficheros en el directorio de
la base de datos. 1) tbl_name.frn, fichero de definición de formato de tabla. 2) tbl_name.MYD,
fichero de datos. 3) tbl_name.MYI, fichero de índices.
Una vez indicado el nombre de la tabla, la sentencia CREATE TABLE permite definir las colum-
nas que la componen. Para crear una columna dentro de una tabla, hay que indicar su nombre
(nombre_col) y tipo de datos que contiene (tipo). Las siguientes sentencias permiten crear una
tabla, denominada gente, que almacena nombres de personas (cadenas de hasta 40 caracteres) y
sus fechas de nacimiento (tipo fecha).
USE prueba
columna puede tomar dicho valor, o el valor implícito para el tipo de columna, en caso contrario.
El valor por defecto implícito es: 1) 0, para tipos numéricos no declarados con el atributo
AUTO_INCREMENT. 2) El siguiente valor dentro de la secuencia, para columnas
AUTO_INCREMENT. 3) Cero correspondiente al tipo, para fechas y tiempos distintos de TIMES-
TAMP. 4) Hora actual, para la primera columna TIMESTAMP. 5) Cadena vacía, para tipos de
cadena distintos de ENUM. 6) Primero valor de la enumeración, para ENUM. 7) A las columnas
BLOB y TEXT no se les puede asignar un valor por defecto.
CREATE TABLE tabla (columna1 CHAR(20) NOT NULL,
INDEX (columna2(4)));
columna2 (4), significa que sólo se utilizan los cuatro primeros caracteres de columna2 para
crear el índice.
Una clave primaria equivale a un índice de clave única, en la que el valor de la clave no puede
tomar valores NULL (los índices normales y los de claves únicas sí pueden tomar valores
NULL). Las siguientes sentencias son equivalentes:
CREATE TABLE tabla(columna1 INT, columna2 CHAR(10) NOT NULL,
UNIQUE (columna2));
Es imprescindible que la columna que contiene una definición de clave foránea esté indexada.
Pero si no se hace de forma explícita, MySQL lo hará de forma implícita. La definición incluye
las tareas a realizar en el caso de que se elimine una fila en la tabla personas. ON DELETE
<opción>, indica que acciones se deben realizar en la tabla actual si se borra una fila en la tabla
referenciada. ON UPDATE <opción>, es análogo pero para modificaciones de claves. Existen
cinco opciones diferentes: 1) RESTRICT, impide eliminar o modificar filas en la tabla referen-
ciada si existen filas con el mismo valor de clave foránea. 2) CASCADE, borrar o modificar una
clave en una fila en la tabla referenciada con un valor determinado de clave, implica borrar las
filas con el mismo valor de clave foránea o modificar los valores de esas claves foráneas. 3) SET
NULL, borrar o modificar una clave en una fila en la tabla referenciada con un valor determinado
de clave, implica asignar el valor NULL a las claves foráneas con el mismo valor. 4) NO
ACTINO, las claves foráneas no se modifican, ni se eliminan filas en la tabla que las contiene. 5)
SET DEFAULT, borrar o modificar una clave en una fila en la tabla referenciada con un valor
determinado implica asignar el valor por defecto a las claves foráneas con el mismo valor.
SHOW TABLES;
Una vez creadas las tablas, existen sentencias para consultar sus características. Así, se puede ver
la estructura de una tabla usando la sentencia SHOW COLUMNS o DESCRIBE.
SHOW COLUMNS FROM gente;
También se pueden ver las instrucciones utilizadas para crear una tabla, mediante la sentencia
SHOW CREATE TABLE. Si se usa \G en lugar de (;) la salida se muestra en forma de listado, en
lugar de forma de tabla. La sentencia CREATE TABLE mostrada no tiene por qué ser la misma
que se usó al crear la tabla originalmente. MySQL rellena las opciones que se activan de forma
implícita, y usa siempre el mismo formato para crear claves primarias.
SHOW CREATE TABLA gente\G
miento. 6) ADD INDEX, crear índice. 7) ADD PRIMARY KEY, crear clave primaria. 8) DROP
INDEX, eliminar índice. 9) DROP PRIMARY KEY, eliminar clave primaria.
ALTER TABLE tabla CHANGE columna1 columna2 TIPO;
ALTER TABLE tabla DROP INDEX (índice); (DROP INDEX (índice) ON tabla;)
Las siguientes sentencias permiten crear una tabla denominada borrar en la base de datos
prueba, comprobar que la tabla ha sido creada, eliminar la tabla borrar y comprobar que ha sido
eliminada.
USE prueba
SHOW TABLES;
SHOW TABLES;
En esta sección se muestra cómo agregar, modificar o eliminar los datos que contiene una bases
de datos.
(valor3,valor4), (valor5,valor6);
Existe otra sintaxis alternativa, que consiste en indicar el valor para cada columna:
INSERT INTO tabla SET columna3=valor1, columna1=valor2;
Cuando se insertan más de una fila en una única sentencia, se obtiene un mensaje que indica el
número de filas afectadas, el número de filas duplicadas y el número de avisos. Para que una fila
se considere duplicada debe tener el mismo valor que una fila existente para una clave principal o
para una clave única. En tablas en las que no exista clave primaria ni índices de clave única no
tiene sentido hablar de filas duplicadas. Si se intentan insertar dos filas con el mismo valor de la
clave única se produce un error y la sentencia no se ejecuta. Existe una opción que se puede utili-
zar para los casos de claves duplicadas: ON DUPLICATE KEY UPDATE. En este caso se puede
indicar qué se debe hacer si se intenta insertar una fila que ya existe en la tabla.
[INTO] tbl_name
[WHERE where_definition]
[ORDER BY ...]
[LIMIT row_count]
Ejemplos:
UPDATE tabla SET columna=columna*1.05;
También se puede indicar el número de filas a actualizar, utilizando la cláusula WHERE, para
establecer una condición. Sólo las filas que cumplan esa condición serán actualizadas:
UPDATE tabla SET columna1=columna1*1.05 WHERE columna2=valor;
Otra forma de limitar el número de filas afectadas es usar la cláusula LIMIT. Esta cláusula per-
mite especificar el número de filas a modificar. Esta cláusula se puede combinar con WHERE, de
modo que sólo las n primeras filas que cumplan una determinada condición se modifiquen. Tam-
bién se puede asociar a la cláusula ORDER BY. Cuando exista una clave primaria o única, se
usará ese orden por defecto, si no se especifica una cláusula ORDER BY.
UPDATE tabla SET columna=columna-1 LIMIT 2;
[WHERE where_definition]
[ORDER BY ...]
[LIMIT row_count]
Ejemplos:
DELETE FROM tabla;
MySQL permite copiar tablas en diferentes formatos de texto, así como importar datos a partir de
fichero de texto en diferentes formatos. Esto se puede usar para exportar datos de una bases de
datos a otras aplicaciones o para importar datos desde otras fuentes a tablas. También se puede
usar para hacer copias de seguridad y restaurarlas posteriormente.
Donde file_name es el nombre del fichero de salida, que no debe existir, ya que en caso contrario
la sentencia fallará. En cuanto a las opciones de exportación estas son FIELDS y LINES:
FIELDS [TERMINATED BY '\t'] [[OPTIONALLY] ENCLOSED BY '']
[ESCAPED BY '\\' ]
Permite elegir el carácter delimitador que se usará para separar cada columna. Por defecto, el
valor que se usa es el tabulador, pero se pueden utilizar usar ';' y ',', entre otros.
[OPTIONALLY] ENCLOSED BY 'carácter'
Sirve para elegir el carácter usado para entrecomillar cada columna. Por defecto no se entrecomi-
lla ninguna columna, pero se puede elegir cualquier carácter. Si se añade la palabra OPTIONA-
LLY sólo se entrecomillarán las columnas de texto y fecha.
ESCAPED BY 'carácter'
Sirve para indicar el carácter que se usará para escapar aquellos caracteres que pueden dificultar
la lectura posterior del fichero. Por ejemplo, si se terminan las columnas con ',' y no las entreco-
millamos, un carácter ',' dentro de una columna de texto se interpretará como un separador de
columnas. Para evitar esto se puede escapar esa coma con otro carácter. Por defecto se usa el
carácter '\'.
Permite seleccionar el carácter para comenzar cada línea. Por defecto no se usa ningún carácter.
TERMINATED BY 'carácter'
Permite elegir el carácter para terminar cada línea. Por defecto es el retorno de línea, pero se
puede usar cualquier otro carácter o caracteres, por ejemplo '\r\n'.
Así, para obtener un fichero de texto a partir de la tabla, con las columnas delimitadas por ';',
entrecomillando las columnas de texto con '"' y separando cada fila por la secuencia '\r\n', se uti-
lizará la siguiente sentecia:
SELECT * FROM tabla INTO OUTFILE "gente.txt"
[ESCAPED BY '\\' ]]
La cláusula LOCAL indica, que el fichero está en el ordenador del cliente. Si no se especifica el
fichero de texto se buscará en el servidor, concretamente en el mismo directorio donde esté la
base de datos. Esto permite importar desde el ordenador local a otra máquina.
Las cláusulas REPLACE e IGNORE afectan al modo en que se tratan las filas leídas que conten-
gan el mismo valor para una clave primaria o única para una fila existente en la tabla. Si se espe-
cifica REPLACE se sustituirá la fila actual por la leída. Si se especifica IGNORE el valor leído
será ignorado.
La parte INTO TABLA tbl_name indica en qué tabla se insertarán los valores leídos.
Las cláusulas FIELDS y LINES tienen el mismo significado que en SELEC...INTO OUTFILE.
Permiten interpretar correctamente cada fila y cada columna, adaptándonos al formato del
fichero de texto de entrada.
La misma utilidad tiene la cláusula IGNORE número LINES, que permite que las primeras líneas
no se interpreten como datos a importar.
La última parte de la sentencia, permite indicar la columna a la que será asignada cada una de las
columnas leídas.
Por ejemplo, supóngase que se quiere añadir el contenido de un fichero a una tabla, donde sus
dos primeras filas no contienen datos válidos, las columnas están separadas con comas y las
líneas terminan con "\n\r":
Comentario 1
Comentario 2
Valor11, valor12
Valor21, valor22
Consultas
16.1 INTRODUCCIÓN
Este tema está dedicado a las consultas, es decir, a la selección de información utilizando la sen-
tencia SELECT. Básicmente, esta sentencia permite obtener información sobre el contenido de
las columnas que componen las tablas de la base de datos y que verifican una determinada condi-
ción. En las expresiones utilizas se pueden incluir operadores y funciones. La lista de operadores
y funciones se incluye al final del tema. Antes de comenzar con la selección de datos, se reco-
mienda hacer un repaso de dichas secciones..
Las consultas a las bases de datos se realizan mediante la sentencia SELECT. El formato básico
de esta instrucción es:
SELECT columnas FROM tablas WHERE condición
y su sintaxis completa:
SELECT
[HIGH_PRIORITY]
[STRAIGHT_JOIN]
select_expr,...
[FROM table_references
[WHERE where_definition]
[HAVING where_definition]
[PROCEDURE procedure_name(argument_list)]
16.2.2 PROYECCIÓN
Es una operación del álgebra relacional que consiste en seleccionar determinados atributos de
una relación.
SELECT columna1, columna2 FROM tabla;
16.2.5 ALIAS
Se puede asignar un alias para las consultas utilizando AS. Esta palabra se puede omitir pero no
es recomendable, ya que en ocasiones puede ser difícil distinguir entre el olvido de una coma y la
omisión de AS.
16.2.7 SELECCIÓN
Es una operación del álgebra relacional que consistía en seleccionar filas de una tabla que cum-
plen determinadas condiciones. Para ello se utiliza la clausula WHERE. En una cláusula WHERE
se puede usar cualquier función y operador disponible en MySQL, excluyendo las funciones de
grupos que están diseñadas específicamente para usarse en cláusulas GROUP BY y HAVING.
SELECT * FROM tabla WHERE condición;
El producto cartesiano es una operación del álgebra relacional que permite, a partir de dos tablas,
obtener las combinaciones de todas sus filas.
SELECT * FROM tabla1,tabla2;
La coma y JOIN son equivalentes, y las palabras INNER y CROSS son opcionales. La condición
en la cláusula ON puede ser cualquier expresión válida para una cláusula WHERE, de hecho, en
la mayoría de los casos, son equivalentes. La cláusula USING permite usar una lista de atributos
que deben ser iguales en las dos tablas a componer.
ON (tabla1.columna= tabla2.columna);
ON (tabla1.columna= tabla2.columna);
ON (tabla1.columna= tabla2.columna);
FROM tabla1,tabla2
WHERE tabla1.columna=tabla2.columna;
WHERE t1.columna=t2.columna;
ON t1.columna=t2.columna;
Existen dos grupos de composiciones externas: izquierda y derecha, dependiendo de cual de las
tablas se lea en primer lugar.
Es lo mismo usar una composición derecha de las tablas tabla1 y tabla2 que una composición
izquierda de las tablas tabla2 y tabla1. Es decir, la consulta anterior es equivalente a esta otra:
SELECT * FROM tabla2 LEFT JOIN tabla1 USING(columna);
16.2.19 UNIONES
También es posible realizar la operación unión de álgebra relacional entre varias tablas o proyec-
ciones de tablas. Para hacerlo se usa la sentencia UNION que permite combinar varias sentencias
SELECT para crear una única tabla de salida. Las condiciones para que se pueda crear una unión
son las mismas que se vieron al estudiar el álgebra relacional (las relaciones deben tener el
mismo número de atributos y además deben ser de dominios compatibles).
SELECT * FROM tabla1 UNION
SELECT ...
SELECT ...]
Sobre el resultado final no se pueden aplicar otras cláusulas como GROUP BY.
Una expresión regular es una forma de especificar un patrón para una búsqueda compleja.
MySQL soporta operaciones de coincidencia de patrones realizadas con los operadoradores
LIKE y REGEXP en sentencias SQL.
Su resultado son las tuplas de columna de la relación tabla, que empiecen por “g”. Es decir, el
símbolo % hace de comodín.
Expresión Significado
^ Coincidencia en principio de cadena
$ Coincidencia en final de una cadena
. Coincidencia de cualquier carácter
a* Coincidencia de cualquier secuencia de cero o más caracteres
a+ Coincidencia de cualquier secuencia de uno o más caracteres
a? Coincidencia de ninguno o de un carácter
de|abc Coincidencia de cualquiera de las secuencias “de" o "abc"
a{n} Coincide exactamente con n instancias de a
Expresión Significado
a{m,n} Coincide con un número entre m y n de instancias de a
[a-dX] Coincidencia de cualquier carácter que sea cualquiera entre 'a', 'b',
'c', 'd' o 'X.
[^a-dX] Coincidencia de cualquier carácter que que no sea cualquiera entre
'a', 'b', 'c', 'd' o 'X'
[.caracteres.] Coincide con la secuencia de caracteres
[=clase_carácter=] Coinciden todos los caracteres con el mismo valor de colección
[:clase_carácter:] Coincide con todos los caracteres pertenecientes a la clase
[[:<:]] Coincidencias con el principio de palabras
[[:>:]] Coincidencias con el final de palabras
Ejemplos:
SELECT 'pato' REGEXP '^pa'; (resultado, 1)
Para usar una instancia literal de un carácter especial en una expresión regular, hay que prece-
derlo por dos caracteres de barra de bajada (\). El analizador sintáctico de MySQL interpreta una
de las barras, y la librería de expresiones regulares interpreta la otra. Por ejemplo, para buscar la
coincidencia de la cadena "1+2" que contiene el carácter especial '+', sólo la última de las
siguientes expresiones regulares es correcta:
mysql> SELECT '1+2' REGEXP '1+2';
Los nombres de clases estándar son: 1) alnum,caracteres alfanuméricos.2) alpha, caracteres alfa-
béticos. 3) blank,carácteres espacio. 4) cntrl, caracteres de control. 5) digit, dígitos. 6) graph,
caracteres gráficos. 7) lower, caracteres alfabéticos en minúsculas. 8) print, caracteres gráficos o
espacios. 9) punct, caracteres de puntuación. 10). space, espacio, tabulador, cambio de línea y
retorno de línea. 11) upper, caracteres alfabéticos en mayúsculas. 12) xdigit, dígitos hexadecima-
les.
SELECT 'justalnums' REGEXP '[[:alnum:]]+'; (resultado, 1)
16.4 OPERADORES
En MySQL existen diferentes operadores, para cada tipo de datos, y se utilizan para construir
expresiones. Las expresiones se evalúan de izquierda a derecha. Dentro de una expresión el
orden de prioridad entre los operadores (de menos a mayor) es: 1) :=. 2) ||, OR, XOR. 3) &&,
AND. 4) NOT. 5) BETWEEN, CASE, WHEN, THEN, ELSE. 6) =, <=>, >=, >, <=, <, <>, !=, IS,
LIKE, REGEXP, IN. 7) |. 8) &. 9) <<, >>. 10) *, /, DIV, %, MOD. 11) - (unitario), ~ (comple-
mento). 12) !. 13) BINARY, COLLATE. También se pueden utilizar paréntesis para forzar el
orden de evaluación de las operaciones dentro de una expresión. Las expresión entre paréntesis
se evalúan antes que el resto de las operaciones en el mismo nivel de paréntesis.
Operador de asignación :=
Permite asignar un valor a una variable mediante la sentencia SELECT. Una variable sin asignar
será de tipo cadena y tendrá el valor NULL.
SELECT @variable:=valor;
A B A AND D
FALSE FALSE FALSE
FALSE TRUE FALSE
TRUE FALSE FALSE
TRUE TRUE TRUE
FALSE NULL FALSE
NULL FALSE FALSE
TRUE NULL NULL
NULL TRUE NULL
A OR B
A B A OR D
FALSE FALSE FALSE
FALSE TRUE TRUE
TRUE FALSE TRUE
TRUE TRUE TRUE
FALSE NULL NULL
NULL FALSE NULL
TRUE NULL TRUE
NULL TRUE TRUE
A XOR B
A B A XOR D
FALSE FALSE FALSE
FALSE TRUE TRUE
TRUE FALSE TRUE
TRUE TRUE FALSE
FALSE NULL NULL
NULL FALSE NULL
TRUE NULL NULL
NULL TRUE NULL
NOT A
A NOT A
FALSE TRUE
TRUE FALSE
NULL NULL
Operador igualdad =
Compara dos expresiones y da como resultado 1 si son iguales, o 0 si son diferentes. Se pueden
comparar valores de tipos diferentes.
Operadores menor o igual <=, menor <, mayor >, mayor o igual >=
Comparan dos expresiones dan como resultado 1 si se cumple la comparación, o 0 si no se cum-
ple. Cuando se comparan cadenas, se considera menor la cadena que aparezca antes por orden
alfabético. Si son fechas, se considera que es menor cuanto más antigua sea. En el caso de cade-
nas con números la comparación se realiza en el orden en que aparecen.
Operador Símbolo
Suma +
Resta -
Cambio de signo -
Multiplicación *
División /
División entera DIV
Contar bits
Devuelve el número de bits iguales a 1 que contiene el argumento especificado. Sintaxis:
BIT_COUNT()
Equivale a:
NOT (<expresión> LIKE <patrón> [ESCAPE 'carácter_escape'])
Equivalen a:
NOT (<expresión> REGEXP <patrón>)
Operador BETWEEN
Se utiliza para comprobar si una expresión está comprendida en un determinado rango de valo-
res.
<expresión> BETWEEN mínimo AND máximo
Operador COALESCE
Sirve para seleccionar el primer valor no nulo de una lista o conjunto de expresiones.
COALESCE(<expr1>, <expr2>, <expr3>...)
de la lista son enteros, estos se comparan entre si como enteros. 2) Si el valor de retorno se usa en
un contexto real, o si todos los elementos son valores reales, serán comparados como reales. 3) Si
cualquiera de los argumentos es una cadena sensible al tipo (mayúsculas y minúsculas son carac-
teres diferentes), los argumentos se comparan como cadenas sensibles al tipo. 4) En cualquier
otro caso, los argumentos se comparan como cadenas no sensibles al tipo.
GREATEST(<expr1>, <expr2>, <expr3>...)
Operadores IN y NOT IN
Se utilizan para averiguar si el valor de una expresión determinada está dentro de un conjunto
indicado. El operador IN devuelve un valor verdadero, 1, si el valor de la expresión es igual a
alguno de los valores especificados en la lista. El operador NOT IN devuelve un valor falso en el
mismo caso.
IN (<expr1>, <expr2>, <expr3>...)
Operador ISNULL
Equivalente a IS NULL.
ISNULL(<expresión>)
Operador INTERVAL
Se utiliza para calcular el intervalo al que pertenece un valor. Si el valor de la expresión es menor
que límite 1, el operador devuelve el valor 0, si es mayor o igual que límite1 y menor que limite2,
devuelve el valor 1, etc. Todos los valores de los límites deben estar ordenados.
Operador CASE
Se trata de un operador de control de flujo. Existen dos sintaxis para CASE, la primera forma
devuelve el resultado para el valori que coincida con valor y la segunda forma devuelve el resul-
tado para la primera condición verdadera. Si no hay coincidencias, se devuelve el valor asociado
al ELSE, o NULL si no hay parte ELSE.
CASE valor WHEN [valor1] THEN resultado1
Operador BINARY
Se trata de un operador de casting. Convierte una cadena de caracteres en una cadena binaria. Si
se aplica a una cadena que forma parte de una comparación, se distinguirán mayúsculas de
minúsculas. Los espacios al final de la cadena se tienen en cuenta en la comparación. Cuando se
usa en comparaciones, afecta a la comparación en conjunto, es indiferente que se aplique a cual-
quiera de las dos cadenas.
BINARY cadena
16.5 FUNCIONES
Funciones matemáticas
• ABS. Devuelve el valor absoluto
• ACOS. Devuelve el arcocoseno
• ASIN. Devuelve el arcoseno
• ATAN y ATAN2. Devuelven el arcotangente
• CEILING y CEIL. Redondeo hacia arriba
• COS. Coseno de un ángulo
• COT. Cotangente de un ángulo
• CRC32. Cálculo de comprobación de redundancia cíclica
• DEGREES. Conversión de grados a radianes
• EXP. Cálculo de potencias del número e
• FLOOR. Redondeo hacia abajo
• LN. Logaritmo natural
• LOG. Logaritmo en base arbitraria
• LOG10. Logaritmo en base 10
• LOG2. Logaritmo en base dos
• MOD o %. Resto de una división entera
• PI. Valor del número pi
• POW o POWER. Valor de potencias
• RADIANS. Conversión de radianes a grados
• RAND. Valores aleatorios
• ROUND. Cálculo de redondeos
• SIGN. Devuelve el signo
Funciones de cadenas
• ASCII. Valor de código ASCII de un carácter
• BIN. Converión a binario
• BIT_LENGTH. Cálculo de longitud de cadena en bits
• CHAR. Convierte de ASCII a carácter
• CHAR_LENGTH o CHARACTER_LENGTH. Cálculo de longitud de cadena en caracte-
res
• COMPRESS. Comprime una cadena de caracteres
• CONCAT. Concatena dos cadenas de caracteres
• CONCAT_WS. Concatena cadenas con separadores
• CONV. Convierte números entre distintas bases
• ELT. Elección entre varias cadenas
• EXPORT_SET. Expresiones binarias como conjuntos
• FIELD. Busca el índice en listas de cadenas
• FIND_IN_SET. Búsqueda en listas de cadenas
• HEX. Conversión de números a hexadecimal
• INSERT. Inserta una cadena en otra
• INSTR. Busca una cadena en otra
• LEFT. Extraer parte izquierda de una cadena
• LENGTH u OCTET_LENGTH. Calcula la longitud de una cadena en bytes
• LOAD_FILE. Lee un fichero en una cadena
• LOCATE o POSITION. Encontrar la posición de una cadena dentro de otra
• LOWER o LCASE. Convierte una cadena a minúsculas
• LPAD. Añade caracteres a la izquierda de una cadena
• LTRIM. Elimina espacios a la izquierda de una cadena
• MAKE_SET. Crea un conjunto a partir de una expresión binaria
• OCT. Convierte un número a octal
• ORD. Obtiene el código ASCII, incluso con caracteres multibyte
• QUOTE. Entrecomilla una cadena
• REPEAT. Construye una cadena como una repetición de otra
• REPLACE. Busca una secuencia en una cadena y la sustituye por otra
• REVERSE. Invierte el orden de los caracteres de una cadena
• RIGHT. Devuelve la parte derecha de una cadena
• RPAD. Inserta caracteres al final de una cadena
• RTRIM. Elimina caracteres blancos a la derecha de una cadena
Funciones de fecha
• ADDDATE. Suma un intervalo de tiempo a una fecha
• ADDTIME. Suma tiempos
• CONVERT_TZ. Convierte tiempos entre distintas zonas horarias
• CURDATE o CURRENTDATE. Obtener la fecha actual
• CURTIME o CURRENT_TIME. Obtener la hora actual
• DATE. Extraer la parte correspondiente a la fecha
• DATEDIFF. Calcula la diferencia en días entre dos fechas
• DATE_ADD. Aritmética de fechas, suma un intervalo de tiempo
• DATE_SUB. Aritmética de fechas, resta un intervalo de tiempo
• DATE_FORMAT. Formatea el valor de una fecha
• DAY o DAYOFMONTH. Obtiene el día del mes a partir de una fecha
• DAYNAME. Devuelve el nombre del día de la semana
• DAYOFWEEK. Devuelve el índice del día de la semana
• DAYOFYEAR. Devuelve el día del año para una fecha
• EXTRACT. Extrae parte de una fecha
• FROM_DAYS. Obtener una fecha a partir de un número de días
• FROM_UNIXTIME. Representación de fechas UNIX en formato de cadena
• GET_FORMAT. Devuelve una cadena de formato
• HOUR. Extrae la hora de un valor time
• LAST_DAY. Devuelve la fecha para el último día del mes de una fecha
• MAKEDATE. Calcula una fecha a partir de un año y un día del año
• MAKETIME. Calcula un valor de tiempo a partir de una hora, minuto y segundo
• MICROSECOND. Extrae los microsegundos de una expresión de fecha/hora o de hora
• MINUTE. Extrae el valor de minutos de una expresión time
Funciones de encriptado
• AES_ENCRYPT y AES_DECRYPT. Encriptar y desencriptar datos usando el algoritmo
oficial AES
• DECODE. Desencripta una cadena usando una contraseña
• ENCODE. Encripta una cadena usando una contraseña
• DES_DECRYPT. Desencripta usando el algoritmo Triple-DES
• DES_ENCRYPT. Encripta usando el algoritmo Triple-DES
• ENCRYPT. Encripta str usando la llamada del sistema Unix crypt()
• MD5. Calcula un checksum MD5 de 128 bits para la cadena string
• PASSWORD u OLD_PASSWORD. Calcula una cadena contraseña a partir de la cadena
en texto plano
• SHA o SHA1. Calcula un checksum SHA1 de 160 bits para una cadena
Funciones de información
• BENCHMARK. Ejecuta una expresión varias veces
• CHARSET. Devuelve el conjunto de caracteres de una cadena
• COERCIBILITY. Devuelve el valor de restricción de colección de una cadena
• COLLATION. Devuelve la colección para el conjunto de caracteres de una cadena
• CONNECTION_ID. Devuelve el ID de una conexión
• CURRENT_USER. Devuelve el nombre de usuario y el del host para la conexión actual
• DATABASE. Devuelve el nombre de la base de datos actual
• FOUND_ROWS. Calcular cuántas filas se hubiesen obtenido en una sentencia SELECT
sin la cláusula LIMIT
• LAST_INSERT_ID. Devuelve el último valor generado automáticamente para una
columna AUTO_INCREMENT
• USER o SESSION_USER o SYSTEM_USER. Devuelve el nombre de usuario y host
actual de MySQL
• VERSION. Devuelve la versión del servidor MySQL
Miscelánea
• DEFAULT. Devuelve el valor por defecto para una columna
• FORMAT. Formatea el número según la plantilla '#,###,###.##
• GET_LOCK. Intenta obtener un bloqueo con el nombre dado
• INET_ATON. Obtiene el entero equivalente a la dirección de red dada en formato de cuar-
teto con puntos
• INET_NTOA. Obtiene la dirección en formato de cuarteto con puntos dado un entero
• IS_FREE_LOCK. Verifica si un nombre de bloqueo está libre
• IS_USED_LOCK. Verifica si un nombre de bloqueo está en uso
• MASTER_POS_WAIT. Espera hasta que el esclavo alcanza la posición especificada en el
diario maestro
• RELEASE_LOCKLibera un bloqueo
• UUIDDevuelve un identificador único universal
Funciones de grupos
• AVG. Devuelve el valor medio
• BIT_AND. Devuelve la operación de bits AND para todos los bits de una expresión
• BIT_OR. Devuelve la operación de bits OR para todos los bits de una expresión
• BIT_XOR. Devuelve la operación de bits XOR para todos los bits de una expresión
• COUNT. Devuelve el número de valores distintos de NULL en las filas recuperadas por
una sentencia SELECT
• COUNT DISTINCT. Devuelve el número de valores diferentes, distintos de NULL
• GROUP_CONCAT. Devuelve una cadena con la concatenación de los valores de un grupo
• MIN. Devuelve el valor mínimo de una expresión
• MAX. Devuelve el valor máximo de una expresión
• STD o STDDEV. Devuelve la desviación estándar de una expresión
• SUM. Devuelve la suma de una expresión
• VARIANCE. Devuelve la varianza estándar de una expresión
Tecnología PHP
17.1 INTRODUCCIÓN
Si fuese necesario definir PHP en una sola línea, podría decirse que se trata de un lenguaje inter-
pretado de alto nivel embebido en páginas HTML (o XHTML) y ejecutado en el servidor.
Aunque existe una multitud de lenguajes y entornos de desarrollo concebidos para Internet, PHP
se ha convertido en uno de los lenguajes, del lado del servidor, más ampliamente utilizados para
el desarrollo de páginas dinámicas junto con ASP, JSP, ColdFusion y Perl. En los últimos años, el
número de servidores que utilizan PHP se ha disparado. De hecho, según datos de Netcraft, en
Agosto de 2004 eran casi 17 millones de dominios los que usaban PHP.
A finales de 1997 se libera PHP/FI 2.0, pasando de ser el proyecto de una sola persona al desa-
rrollo de un equipo. Tuvo un seguimiento estimado de varios miles de usuarios en todo el mundo.
con aproximadamente 50.000 dominios informando que lo tenían instalado, lo que sumaba alre-
dedor del 1% de los dominios de Internet.
En junio de 1995 se liberó oficialmente PHP 3.0. anunciado como sucesor oficial de PHP/FI 2.0,
si bien había sido completamente reescrito por Andi Gutmans y Zeev Zuraski. Una de las mejores
características de PHP 3.0 que atrajo a docenas de desarrolladores a unirse y enviar nuevos
módulos de extensión era su gran extensibilidad, además de proveer a los usuarios finales de una
sólida infraestructura para muchísimas bases de datos, protocolos y APIs. En su apogeo, PHP 3.0
estaba instalado en aproximadamente un 10% de los servidores Web en Internet.
La última y actual versión de PHP, liberada en Noviembre de 2005 es la 5.1.1. Está basada en el
nuevo motor Zend 2. el cual ha vuelto a ser reescrito por completo. Entre sus características y
novedades más resaltables está el completo soporte para la programación orientada a objetos
(que a buen seguro satisfará a los más apasionados y ortodoxos seguidores de este paradigma de
la programación). También incorpora la gestión de excepciones, una nueva libreria de XML
(libxml12), soporte nativo para el sistema gestor de bases de datos SQLite y mejoras en la ges-
tión de las cadenas de caracteres. PHP 5.0 soporta también MySQLi. una nueva ampliación de
MySQL ( diseñada para trabajar con la versión 4.1.2 o superior), la cual, además de la interfaz
habitual, encierra una interfaz basada en objetos.
El otro lenguaje utilizado para el diseño de páginas dinámicas de servidor y ampliamente exten-
dido es ASP. Es un lenguaje derivado de Visual Basic (aunque se puede programar en otros len-
guajes como VBScript y JScript) desarrollado por Microsoft. Evidentemente, se emplea
principalmente sobre plataformas que funcionan bajo sistemas operativos Windows (aunque
desde hace poco tiempo existe un software de SUN, Sun ONE Active Server Pages, anterior-
mente conocido como Chili Soft ASP, que permite trabajar con ASP en plataformas Unix/Linux).
PHP es en las plataformas Unix/Linux lo que ASP en las plataformas Windows. De hecho,
ambos lenguajes se insertan en documentos HTML haciendo uso de la emulación de etiquetas
(otros lenguajes como Perl deben generar toda la página HTML de respuesta). Pero lo cierto, es
que, a pesar de sus semejanzas, las diferencias entre ambos lenguajes son muchas. Diferencias
que hacen que la balanza se vaya inclinando hacia PHP como una mejor solución para implemen-
tar aplicaciones Web.
La principal diferencia es que ASP es una tecnología propietaria de Microsoft, mientras que PHP
sigue la filosofia Open Source. Esto hace que ASP esté pensado para funcionar principalmente
sobre plataformas Microsoft, a pesar de que existan soluciones (con un coste económico elevado)
como Sun ONE ASP que permiten su utilización sobre Unix/Linux. Sin embargo, PHP permite
que sin ningún problema, se puedan migrar las aplicaciones Web entre todos los sistemas opera-
tivos y servidores en los que funciona.
La filosofía del producto comercial de ASP influye además en que gran cantidad del software
adicional necesario para complementar una aplicación Web suponga un coste económico adicio-
nal, por ejemplo ASPEncrypt (necesario para la encriptación), ServerObject´s Qmail (gestor de
correo electrónico) o Artisans SAFileup (necesario para le gestión de descargas de ficheros). Sin
embargo, en PHP todas estas opciones están incluidas de forma gratuita.
Hay que tener en cuenta que la filosofía Open Source de PHP hace que a lo largo del mundo exis-
tan gran cantidad de equipos comprobando el producto, lo cual permite actualizar el producto
con nuevas versiones y revisiones que solventan sus problemas de una forma mucho más rápida.
A nivel técnico, se pueden dar muchas razones a favor de PHP: entre ellas, una mayor rapidez de
ejecución o una gestión de memoria más acertada. ASP, debido a su propia contrucción (basada
en una arquitectura COM), nunca podrá llegar a ser tan rápido como PHP. Todas las operaciones
ASP están controladas por objetos COM (Response, Request, ADO,File System...). Sin embargo,
PHPestá construido de forma modular; esto quiere decir que todos sus componentes se ejecutan
en el mismo espacio de memoria que PHP. De este modo, el código PHP puede ejecutarse más
rápidamente al no sufrir la sobrecarga impuesta por la comunicación con los diferentes objetos
COM y procesos que soporta ASP. Además, cada compilador de ASP se ejecuta en su propio
proceso, de modo que al comienzo de una etiqueta ASP, se produce un cambio de contexto para
salir del parser HTML y elegir el compilador apropiado, volviendo a realizar un salto de con-
texto al encontrar una etiqueta de cierre ASP para volver de nuevo al parser HTML.
Algunos de los problemas de ASP se resuelven en parte con la última versión del producto
ASP.NET. Si bien hay que tener en cuenta que este producto no puede ser considerado como un
lenguaje de programación de páginas Web, sino más bien como una herramienta de desarrollo de
aplicaciones Web (una de las principales realizaciones es la flexibilidad a la hora de elegir el len-
guaje de programación a utilizar, ASP.NET trabaja con lenguajes de script como VBScript, JSS-
cript; PerlScript y Python y con lenguajes compilados como VB, C#, C, Cobol, Smalltalk y
Lisp).
Instalación
18.1 INSTALACIÓN
Debido a que el editor que se utilizará en el curso es Dreamweaver, el cual corre sobre la plata-
forma Windows, se hará en este apartado una breve descripción de como instalar de manera inte-
grada los productos Apache, MySQL y PHP ya que de no disponer de más de un computador, es
del todo probable que se utilice el mismo ordenador como sistema cliente-servidor.
No obstante, si se desea instalar estos productos sobre una máquina real o virtual (VMWare)
corriendo Linux, se recomienda la lecturan del capítulo 1 del libro de texto PHP5.
A grandes rasgos, ejecutar un programa CGI le supone a la máquina donde se está ejecutando el
servidor Web llamar al sistema operativo para que realice las siguientes tareas básicas:
1 Cargar el programa en memoria.
2 Anotarlo en la lista de tareas.
3 Lanzar su ejecución.
4 Esperar a que termine.
5 Descargarlo de la memoria y de la lista de tareas.
18.2 INSTALACIÓN
Es de perogrullo: tantas veces como un cliente pida la ejecución de un programa CGI, tantas
veces se repetirán estas acciones en la máquina servidora.
Por otro lado, se puede pensar en un SAPI como un protocolo que permite acceder directamente
a las funciones internas del servidor; por tanto, a través del SAPI se pueden añadir nuevas funcio-
nalidades a un servidor Web (por ejemplo, acceso a bases de datos, autenticación de usuarios,
cacheo de páginas, generación de imágenes al vuelo, etc). Lo más interesante de esta caracterís-
tica es que todas estas nuevas funcionalidades se van a ejecutar de forma más rápida y eficiente
ya que lo van a hacer en el espacio de memoria del propio servidor. Esto significa que las ejecu-
ciones de los programas las hará el propio servidor Web y, por tanto, serán mucho más rápidas y
eficaces.
Existen varios tipos de API´s: Apache API para el servidor Apache, ISAPI de Microsoft para su
producto Internet Information Server, NSAPI de AOL para el servidor iPlanet (antes, Netscape
Enterprise Server) y WSAPI que es el SAPI del servidor Website Pro de O’Reilly.
Además del bajo rendimiento, la versión CGI presenta innumerables problemas de seguridad
asociados.
PHP está portado para las versiones de Windows de 32 bits, esto es, Windows 95/98/Me y Win-
dows NT/2000/XP/2003.
En el momento de la edición de este capítulo, la última versión liberada y estable para Windows
es la 2.0.55 la cual se bajará de la dirección http://httpd.apache.org/download.cgi. El fichero en
cuestión es el apache_2.0.55-win32-x86-no_ssl.msi. El nombre del fichero permite saber dos
cosas: que será ejecutado por Microsoft System Installer (extensión msi), y que no incorpora las
librerías Secure Sockets Layer necesarias para instalar un servidor seguo con encriptación: sufijo
_no_ssl.
Antes de lanzar la ejecución del fichero msi desde el explorador de archivos, si hubiera un servi-
dor Apache ya instalado ( y a demás estuviese funcionando), lo primero que habría que hacer es
detener su ejecución. La instalación de Apache en Windows resulta muy sencilla, basta seguir las
indicaciones y rellenar algunos campos de formulario.
En la misma pantalla se nos pide además si queremos que este paquete se instale como servicio
de Windows (se ejecutará de manera automática al arrancar el equipo) en el puerto 80, o bien,
que se instale como una copia para el usuario desde el que se está realizando la instalación y en el
puerto 8080. Se recomienda la primera opción.
Una vez rellenado el formulario aparecerá una pamtalla en la que se nos pedirá el tipo de instala-
ción que deseamos hacer. Elegimos Custom fundamentalmente para ver el directorio donde se
instala y alguna cosa más. Por lo general lo mejor es dejar todo por defecto.
El directorio por omisión donde se instalan todos los ficheros de Apache es c:\Archivos de pro-
grama\Apache Group2\Apache2; allí se crearán entre otros los directorios conf, htdocs (directo-
rio raiz por defecto de los documentos Web), bin, logs,etc.
Las operaciones de arrancar y parar el servidor se pueden realizar de tres maneras distintas:
• La primera de ellas es a través del programa monitor que viene con la instalación de Apa-
che Inicio-->Archivos de Programa--> Apache HTTP Server 2.0.55-> Control Apa-
che Server-> Monitor Apache Servers.
• Si está instalado como servicio de Windows, se puede hacer desde el entorno de servicios
del sistema operativo.
• También desde una ventana MS-DOS, donde para arrancarlo habrá que ejecutar el
comando:
- net start apache2
- net stop apache2
Para obtener este último, en la misma carpeta c:\php-5.1.2-win32, hacemos una copia de
php.ini-recommended sobre php.ini, y lo editamos según nuestras necesidades (ahora lo
veremos). Por ejemplo, para que PHP sea capaz de encontrar las librerias dinámicas que
ofrecen funcionalidades adicionales (acceso a base de datos, criptografía, generación de
documentos en formato PDF, etc.) necesitamos primero modificar la directiva extension_
dir con la ruta donde se encuentran todas las librerias dinámicas, y luego descomentar la
línea correspondiente a la funcionalidad que queramos. Concretamente, ahora que PHP5
no incorpora por defecto el interfaz de acceso a un servidor MySQL, las modificaciones
que habrá que hacer a php.ini serán:
extension_dir = “c:/php-5.1.2-win32/ext/”
extension = php_mysqli.dll
Además, es necesario copiar la librería dinámica lybmysqli.dll, que se encuentra en la car-
peta de la distribución de PHP, en el directorio c:\windows\system32.
Para que Apache sepa dónde encontrar el fichero de configuracion de PHP (php.ini) modi-
ficamos la directive PHPIniDir:
PHPIniDir “c:/php-5.1.2-win32/”
A continuación, veremos que pasos son los necesarios para hacer la instalación de PHP,
bajo Apache en Windows en modo SAPI
Comprobación de la instalación
Para verificar que PHP se está ejecutando, arrancamos Apache, editamos un fichero que
contenga las tres lineas siguientes:
<?
phpinfo()
?>
en la carpeta "c:\archivos de programa\apache group\apache2\htdocs" con el nombre
'prueba.php', por ejemplo, y con un navegador nos conectamos a esa pagina (http://local-
host/prueba.php).
El resultado, si todo ha ido bien, seria el que aparece en la siguiente imagen (Fig. 18.2)
Luego, nos cambiamos a dicho directorio y ejecutamos el programa setup.exe el cual hará la ver-
dadera instalación de este paquete.
El directorio por omisión donde se instala MySQL es c:\mysql. En esta carpeta encontraremos,
entre otros, los directorios bin (donde se almacenan los programas para arrancar y parar el servi-
dor), data (donde se almacenan las bases de datos) y doc (documentacion muy util relativa a la
instalacion, mantenimiento, etc).
Si, por el motivo que fuese, necesitáramos instalar la aplicación en un directorio distinto a
c:\mysql, deberemos incluir en el fichero de configuracion c:\my.cnf las siguientes lineas:
[mysqld]
basedir=UNIDAD:/ruta-instalacion/
datadir=UNIDAD:/ruta-datos/
Para evitar que desde fuera de nuestra máquina sepan que tenemos levantado un servidor
MySQL podemos poner la directiva bind-address=127.0.0.1 en el fichero de configuración
my.ini, o añadirla como opción en la linea de comandos. De cualquiera de las dos formas, el ser-
vidor MySQL solo atenderá en el interfaz de red local.
Unix es el nombre genérico con el que se denomina a sistemas operativos tales como GNU/
Linux, Solaris (Sun Microsistems), True64 Unix (Compaq), HPUX (HP), AIX (IBM), etc.); esto
es, con este término no nos referimos a un único sistema operativo, sino a una amplia familia.
Tanto es asi, que es frecuente encontrarse con expresiones del tipo *ix o u*ix cuando queremos
referirnos a Unix.
De entre todas estas versiones de Unix elegimos GNU/Linux por varios motivos: fiabilidad, esta-
bilidad, robustez (como todos los Unix), pero, sobre todo, por su precio: es gratuito. La versión
más extendida de Linux/GNU es la que corre en arquitecturas Intel, aunque existen versiones que
se pueden instalar y ejecutar en maquinas Alpha de Compaq, McIntosh de Apple, Sparc de Sun
Microsystems, mainframes S/390 de IBM, etc.
Es habitual que las distribuciones de muchas aplicaciones vengan ya precompiladas (en formato
binario o en formato RPM, RedHad Package Manager) para distintas arquitecturas. Pero, preci-
samente por la amplia diversidad de U*ix que podemos encontrarnos, vamos a ver la instalación
de estos paquetes de la forma más genérica posible: desde los fuentes.
19.1 INTRODUCCIÓN
La sintaxis de PHP es muy parecida a otros lenguajes de programación muy extendidos como C,
JAVA, Perl o, incluso, el lenguaje de script JavaScript. Por tanto, todos aquellos que estén fami-
liarizados con estos lenguajes, no les será en absoluto complicado el aprendizaje de las instruc-
cions y sentencias que presenta el lenguaje PHP.
Finalmente, PHP ofrece, como veremos, las características básicas de un lenguaje orientado a
objetos, pero sin las complejas realizaciones que a compañan a estos lenguajes como Java y C++.
19.2.1 DELIMITADORES
PHP está muy relacionado con el lenguaje de hipertextos HTML; tanto es así que el código PHP
aparece normalmente insertado dentro de un documento HTML. El documento PHP una vez
interpretado correctamente en el servidor, genera una página HTML que será enviada al cliente
tal y como muestra la figura (Fig. 19.1).
19.2 FUNDAMENTOS DEL LENGUAJE -I
echo es el comando que permite visualizar por pantalla una variable, cadena de caracteres,
etc.
Una vez guardado el fichero como prueba2.php en la carpeta htdocs de Apache, es posible ejecu-
tarlo introduciendo en el navegador la URL http://127.0.0.1/prueba2.php.
Como se puede observar en el ejemplo anterior, el código PHP se halla inmerso dentro de un
documento HTML que da formato a la página. Habitualmente, encontraremos código PHP inser-
tado en cualquier parte del documento HTML y aparecerá tantas veces como sea necesario. Cada
uno de los bloques de código PHP, al ser procesado, generará una salida en el documento HTML
resultado, justo en la posición en que ese bloque está.
Esto no tiene por qué ser siempre así, es decir, el código PHP también puede formar parte de un
documento que no contenga ninguna etiqueta HTML. De esta manera, el siguiente código produ-
cirá la misma salida que el ejemplo anterior
<?php
echo "<h2>PHP funciona</h2>";
?>
19.2.2 COMENTARIOS
Para introducir comentarios dentro del código, PHP ofrece la posibilidad de hacerlo de tres for-
mas diferentes que también son utilizadas por otros lenguajes. Las siguientes porciones de
código nos muestran la utilización de estos diferentes tipos de comentarios.
<HTML>
<HEAD>
<TITLE>Prueba Comentarios</TITLE>
</HEAD>
<BODY>
<CENTER>
<H2>
<?php
// Comentario inicial
echo "Primer tipo de comentarios"; // Comentario tipo C, C++
// Comentario final
?>
<BR>
<?php
/* Comentario inicial */
echo "Segundo tipo de comentarios"; /* Comentario tipo C, C++ */
/*
Comentario
Final
*/
?>
<BR>
<?php
# Comentario inicial
echo "Tercer tipo de comentarios"; # Comentario tipo shell
# Comentario Final
?>
</H2>
</CENTER>
</BODY>
</HTML>
Tal y como puede verse en el código anterior, es posible realizar comentarios de una sola línes
(caracter //), multilinea (/* ..... */) o tipo shell (caracter #).
El finde sentencia se marca en todas las instrucciones con el caracter punto y coma (;) o bien
aprovechando la etiqueta de cierre (?>), puesto que se asume que el final de la inclusión de
código limita la introducción de nuevas instrucciones.
Para comenzar a programar en PHP, es necesario conocer más detallez de su sintaxis como son:
tipos de variables que puede aceptar el lenguaje, definición de constantes y tipo y uso de los ope-
radores. Además de las breves reseñas que se darán a continuación, se recomienda la lectura del
capítulo 2 del libro de texto.
19.3.1 VARIABLES
Las variables son una parte fundamental de todo lenguaje de programación. En ellas se almace-
nan valores con los que se puede operar, se pueden comparar entre sí y se puede hacer variar el
flujo del programa en función de su valor. Vamos a ver cómo trabajar con variables en PHP.
Declaración y uso
Al contrario que en la mayoría de lenguajes de programación, en PHP NO hace falta declarar las
variables antes de usarlas: tras la primera aparición en el código quedan declaradas. En PHP
todas las variables llevan delante el signo del dólar ‘$’. Por ejemplo:
$var_1 = 123;
$var_2 = ’hola’;
$var_3 = $var_1 * 2;
$mivar = 12;
settype($mivar, "double");
Variables predefinidas
PHP ofrece una gran cantidad de variables predefinidas a cualquier script que se ejecute en su
sistema. Estas variables, guardan información relativa del entorno de ejecución del intérprete y
del propio PHP. Dependen de factores como el tipo de servidor en el que se ejecuta el intérprete
de PHP, la versión y su configuración entre otras cuestiones.
Estas variables se pueden clasificar, por tanto, en dos grandes grupos: por una parte las que el
entorno, el servidor Web, le pasa al intérprete PHP y, por otra parte, las que el intérprete pone a
disposición del programador. Veamos algunas de las variables más utilizadas.
• SERVER_NAME. Indica el nombre del equipo servidor sobre el que se ejecuta el script.
• SERVER_PORT. Indica el puerto del equipo servidor que usa el servidor Web para la
comunicación.
• SERVER_SOFTWARE. Indica qué software está siendo utilizado en el equipo servidor.
• REMOTE_PORT. Contiene el puerto que utiliza el peticionario para comunicarse con el
servidor Web.
• REMOTE_ADDR. Contiene la dirección remota desde la que se realiza la petición.
• DOCUMENT_ROOT. Indica el directorio raiz del documento bajo el que se ejecuta el
script.
• HTTP_REFERER. Contiene la dirección de la página (en caso de haberla) desde la que
el navegador saltó a la página actual.
Estas variables se importan desde el espacio de nombres global de PHP desde el entorno en el
que se está ejecutando el intérprete de PHP. La mayoría es proporcionada por el intérprete de
comandos en el que se está ejecutando PHP. Otras variables de entorno son las CGI, para las que
no importa si PHP se está ejecutando como un módulo del servidor o como un intérprete CGI.
La siguiente lista muestra algunas de las variables que PHP ofrece al programador para facilitar
su tarea.
• argv. Array con los elementos que se pasan al script.
• argc. Indica el número de argumentos que se pasan al script.
• PHP_SELF. Indica el nombre del fichero que contiene el script en ejecución, salvo que se
ejecute PHP como intérprete en la línea de comandos, en cuyo caso no estará disponible.
• _COOKIES. Array asociativo (posteriormente se estudiará) con las variables pasadas a
través de cookies.
• _GET. Array asociativo con las variables pasadas a través del método GET.
• _POST. Array asociativo con las variables pasadas a través del método POST.
Además hace uso de un tipo lógico aunque no aparece definido como tal en las sintaxis del len-
guaje:
• boolean.
Enteros
Los números enteros son casi siempre de 32 bits, con signo (salvo en algunas arquitecturas). El
entero más grande representable es, por tanto, 231 y el menor posible es el -(231) + 1 (más/menos
dos mil millones aproximadamente). También se pueden representar números enteros directa-
mente en notación octal, hexadecimal o binaria:
<?
$decimal = 42;
$octal = 0755; // Con un 0 delante
$hexadecimal = 0x45D0D0AF; // Con 0x delante
?>
La función echo muestra por defecto siempre la información en decimal, a pesar de que interna-
mente ésta se haya almacenado en la variable con formato distinto. Ya se verán posteriormente
funciones de PHP que permiten formatear la salida.
Coma flotante
Números en coma flotante de 64 bits, según formato estándar de IEEE (salvo algunas arquitectu-
ras que no lo soportan).
<?
$pi = 3.1416; // Notación normal
$cinco_millones_y_medio = 5.5e6; // Notación científica
Cadenas
Las cadenas son cadenas de texto ASCII normal y corriente (no Unicode). El tamaño máximo de
una cadena viene limitado únicamente por la cantidad de memoria disponible para el proceso de
PHP que se ejecute en ese momento. No existe el tipo carácter.
Las cadenas se encierran bien en comillas simples (‘ ‘) o bien comillas dobles (“ “). Las diferen-
cias son:
• Las comillas simples no tienen en cuenta ningúun carácter de escape, excepto \ (que se
escapa por una comilla simple) y \\ (que se escapa por una contrabarra).
• Las comillas dobles hacen expansión de variables. Esto es, cualquier nombre de variable
(con dólar incluido) que haya dentro de una cadena con comillas dobles será sustituido por
su valor, siempre y cuando la variable sea de un tipo simple (no compuesto).
• Dentro de comillas dobles, no es necesario escapar la comilla simple.
<?
$nombre = ‘Pepe’;
echo ’Hola $nombre<br>’;
$frase = "Hola $nombre<br>";
echo $frase;
echo "Hola \$nombre<br>";
echo "Las cadenas pueden
ocupar varias líneas
sin ningún problema, incluyendo
saltos de línea, pero
hay que tener cuidado de
cerrar las comillas!";
?>
Los caracteres de escape son \n, \r, \t, \\, \”, \’, \$ y \x00, donde “00 ”es un número hexadecimal,
lo que se sustituye por el carácter ASCII correspondiente.
Las cadenas en PHP son “binary-safe”, es decir, pueden amacenar contenido que no sea texto, sin
riesgo de perder información (recordemos el \0 de C). Esto permite trabajar con imágenes, sonido
y otros formatos de información.
Nulo
El tipo nulo sólo tiene un valor posible: NULL. Se suele usar como valor de retorno para signifi-
car que no hay datos (lo cual es distinto de un cero decimal, o de una cadena vacía).
Arrays
Los arrays o matrices son estructuras que permiten el almacenamiento de un conjunto de datos
bajo un mismo nombre; son una construcción tradicional de los lenguajes de programación. Se
puede definir un array o matriz como un conjunto ordenado de elementos identificados por un
índice, de modo que en cada posición marcada por el índice el array contiene un valor.
Se pueden contruir tantos índices como se quiera aunque el uso habitual de los arrays es en forma
de matriz unidimensional. En PHP la longitud de un array se modifica de forma dinámica siem-
pre que se le añade un elemento.
En PHP, los arrays pueden estar compuestos de elementos de diferente naturaleza y su primer
elemento o posición es la 0. Además, existen unos arrays especiales denominados asociativos en
los que el índice es un valor de tipo string, de modo que cada posición está definida por el par
(clave, valor), pudiendo acceder al contenido (valor) a través de la clave.
La imagen anterior (Fig. 19.3) nos muestra dos posibles estructuras de arrays como un conjunto
de elementos cada uno de los cuales tiene asociada una posición o una clave.
Para manejar un array de forma global, utilizaremos el nombre asignado a la variable que lo con-
tiene y, para manejar cada uno de sus elementos, tendremos que hacer referencia a su posición o
clave dentro del conjunto global.
A modo de introducción y para familiarizarnos con su uso, vamos a ver un ejemplo en el que se
muestra como definir y manejar los arrays de la forma más sencilla. Si bien, dada la importancia
que estos componentes tienen en la programación con PHP, los veremos en detalle más adelante.
<HTML>
<HEAD>
<TITLE>Variables con matrices</TITLE>
</HEAD>
<BODY>
<CENTER>
<H2>Trabajando con matrices o <I>arrays</I></H2>
<?php
$matriz1[0]="cougar";
$matriz1[1]="ford";
// la tercera posición del array esta vacía
// por eso le asignamos una cadena sin contenido
$matriz1[2]="";
$matriz1[3]="2.500";
$matriz1[4]="V6";
$matriz1[5]=182;
$matriz1[]=182;
// para añadir el último elemento a una matriz
// no es necesario poner el número de índice
Objetos
Si se tiene un conocimiento de la programación orientada a objetos, se entenderá mejor el con-
cepto de objeto; no obstante, a modo de introducción, diremos que un objeto es una estructura
que mantiene en si misma tanto sus características básicas (denominadas propiedades), como las
posibles funcionalidades que admite (denominadas métodos). En capítulos posteriores veremos
con más detalle este tipo de datos, así como la forma en la que se declaran, crean y utilizan dentro
de PHP.
Conversión de tipos
Como antes comentamos, PHP es un lenguaje debilmente tipado, es decir, puede contener distin-
tos tipos o valores a lo largo de su vida. Por tanto, en PHP el tipo de una variable se determina
por el contexto. Asi, una variable a la que se le asigna un valor entero será de tipo integer; si,
seguidamente, sobre esa misma variable se le asigna una cadena de caracteres, la variable en
cuestión pasará a ser de tipo string. Además, cuando operamos con variables de distinto tipo, el
intérprete de PHP tiende a homogeneizar sus diferentes tipos en función de la operación que se
pretende realizar y de los operandos que forman parte de ella.
Un caso muy claro es el que se produce con el operador suma "+". Veámoslo con un ejemplo:
<HTML>
<HTML>
<HEAD>
<TITLE>Conversión automática de tipos</TITLE>
</HEAD>
<BODY>
<CENTER>
<H2>Conversión de tipos automática</H2>
<?php
$numero=19;
$cadena1="21";
$cadena2="23abc";
$cadena3="2211.5";
$suma=$numero+$cadena1;
echo "El resultado de sumar $numero y '$cadena1' es: $suma <BR>";
$suma=$numero+$cadena2;
echo "El resultado de sumar $numero y '$cadena2' es: $suma <BR>";
$suma=$numero+$cadena3;
echo "El resultado de sumar $numero y '$cadena3' es: $suma <BR>";
$suma=$cadena1+$cadena2;
echo "El resultado de sumar '$cadena1' y '$cadena2' es: $suma
<BR>";
$suma=$cadena1+$cadena3;
echo "El resultado de sumar '$cadena1' y '$cadena3' es: $suma
<BR>";
?>
</CENTER>
</BODY>
</HTML>
El intérprete intentará convertir las cadenas en valores numéricos para que éstos se puedan sumar
correctamente (una cadena que no pueda convertirse a un valor numérico es evaluada con el
valor 0 para poder operar aritméticamente con ella). El resultado que obtenemos lo podernos ver
en la siguiente imagen (Fig. 19.5):
Además de la conversión automática realizada por el intérprete de PHP, es posible convertir las
variables de un tipo a otro cuando el programador lo desee. Se trata de obligar a que una variable
sea evaluada con un tipo concreto. Es similar a la conversión de tipos que se da en el lenguaje C
y que se denomina comúnmente como casting. Para ello se escribe entre paréntesis el tipo
deseado (integer, float, string, boolean, array, object) antes de la variable a la que se pretende
convertir. En el siguiente ejemplo se ven algunas conversiones de tipos:
<HTML>
<HEAD>
<TITLE>Casting de tipos</TITLE>
</HEAD>
<BODY>
<CENTER>
<H2>Conversión de tipos por <I>casting</I></H2>
<?php
$cadena="3.1416 es el valor de Pi";
echo "El valor de \$cadena es: <B> $cadena </B><BR><BR>";
$aux=(integer)$cadena;
echo "El resultado de convertirla en entero es: $aux <BR>";
$aux=(double)$cadena;
echo "El resultado de convertirla en doble es: $aux <BR>";
?>
</CENTER>
</BODY>
</HTML>
Como podemos observar en la siguiente imagen (Fig. 19.6), el casting de la cadena inicial a
entero nos devuelve un valor de tipo integer en un caso y de tipo float en el otro. De igual forma,
podríamos haber convertido la cadena inicial en cualquiera de los restantes tipos con los que tra-
baja PHP.
Variables de variables
Consiste en reutilizar el valor de las variables como nombre de otra variable al mismo tiempo.
Las variables de variables se pueden establecer y usar dinámicamente; de hecho, habitualmente
se utilizan en scripts en los que se genera código de forma dinámica. El siguiente ejemplo mues-
tra la utilización de este tipo de variables:
<HTML>
<HEAD>
<TITLE>Variables de Variables</TITLE>
</HEAD>
<BODY>
<CENTER>
<H2>Variables de variables</H2>
<?php
$cadena="modelo";
echo "El valor de \$cadena es: <B> $cadena </B><BR>";
echo 'Después de asignar a $$cadena "Cougar" ...<BR><BR>';
$$cadena="Cougar";
echo "El valor de \$\$cadena es: $$cadena <BR>";
echo "El valor de \$modelo es: $modelo <BR>";
?>
</CENTER>
</BODY>
</HTML>
La siguiente imagen muestra el resultado de visualizar el ejemplo anterior:
• gettype (variable): Devuelve el tipo de dato pasado comno parámetro, pudiendo devolver
corno valor: integer, float, string, array, class, object y unknown type.
• settype (variable, tipo) : Establece el tipo de dato a guardar en una variable. Tiene dos
argumentos: el nombre de la variable y el tipo que se quiere establecer. Con esta función
podernos realizar conversiones de un tipo de datos a otro. Devolverá valor true si ha tenido
éxito; en caso contrario, devolverá false.
• isset (variable) : Indica si una variable ha sido inicializada con un valor, en cuyo caso
devuelve true y, en caso contrario, devuelve false.
• unset (variable) : Destruye una variable liberando los recursos dedicados a dicha variable.
Es necesario indicar corno parámetro el nombre de la variable a destruir.
• empty (variable) : Devuelve valor true si la variable aún no ha sido inicializada, o bien,
tiene un valor igual a 0 o es una cadena vacía y, en caso contrario, devuelve false.
• is_int(variable), is_integer(variable), is_long(variable): Estas funciones devuelven true
si la variable pasada como argumento es de tipo integer; en caso contrario, devuelven
false.
• is_float(variable), is_real(variable), is_double(variable): Estas funciones devuelven
true si la variable pasada como argumento es de tipo float; en caso contrario, devuelven
false.
• is_numeric (variable) : Esta función devuelve true si la variable pasada como argumento
es un número o una cadena numérica; en caso contrario, devuelve false.
• is_bool (variable) : Esta función devuelve true si la variable pasada como argumento es
de tipo lógico; en caso contrario, devuelve false.
• is_array (variable) : Esta función devuelve true si la variable pasada como argumento es
de tipo array en caso contrario, devuelve false.
• is_string (variable) : Esta función devuelve true si la variable pasada como argumento es
de tipo string; en caso contrario, devuelve false.
• is_obj ect (variable) : Esta función devuelve true si la variable pasada corno argumento es
de tipo obj ect; en caso contrario, devuelve false.
• intval(variable,base), floatval(variable), strval(variable): Estas funciones sirven para
realizar conversiones de tipos (casting), de modo que convierten a integer, float o string,
respectivamente, el valor de la variable que se le pasa como parámetro. Estas funciones no
pueden utilizarse para convertir arrays u objetos. En particular, la función intval( ) puede
recibir además un segundo parámetro que representa la base a utilizar en la conversión
(10-decimal, 8-octal y 16-hexadecimal), tomando por defecto la base 10 de los números
decimales.
<HTML>
<HEAD>
<TITLE>Casting de tipos</TITLE>
</HEAD>
<BODY>
<CENTER>
<H2>Conversión de variables</H2>
<?php
$cadena="38E6";
echo "El valor de \$cadena es: <B> $cadena </B><BR><BR>";
$aux=intval($cadena);
echo "El resultado de convertirla en entero es: $aux <BR>";
$aux=intval($cadena,8);
echo "El resultado de convertirla en entero octal: $aux <BR>";
$aux=intval($cadena,16);
echo "El resultado de convertirla en entero hexadecimal: $aux
<BR>";
$aux=doubleval($cadena);
19.3.4 CONSTANTES
Una constante es una variable que mantiene el mismo valor durante toda la ejecución del pro-
grama. Se puede asegurar que la constante mantiene siempre el mismo valor; en ninguna parte
del script se puede cambiar el valor de una constante una vez que se define. De hecho, los inten-
tos de cambio provocan errores.
Para hacer referencia a las constantes, no es necesario anteponer el carácter $ al nombre, ya que
no se trata de una variable. Bastará con hacer referencia a ellas con el nombre con el que se defi-
nieron. En caso de necesitar redefinir el valor de una variable, habrá que volver a utilizar la fun-
ción define( ) . Veamos un ejemplo del uso de las variables:
<HTML>
<HEAD>
<TITLE>Constantes</TITLE>
</HEAD>
<BODY>
<CENTER>
<H2>Trabajando con constantes</H2>
<?php
define("euro",166.386);
echo "El valor de la constante 'euro' es: <B>". euro ."</B><BR>";
echo "Luego 1€ son ".euro."ptas.<BR><BR>";
echo "La constante 'centimo' ";
echo (defined("centimo"))?"está".centimo:"no está";
echo " definida<BR>";
define("centimo",1.66);
echo "El valor de la constante 'centimo' es: <B>". centimo ."</
B><BR><BR>";
?>
</CENTER>
</BODY>
</HTML>
Constantes predefinidas
El propio intérprete de PHP tiene un conjunto de constantes predefinidas y siempre disponibles
para el programador. No se podrán definir constantes propias de nuestros programas con los mis-
mos nombres ya que se tomará por defecto la constante predefinida. Algunas de estas constantes
son:
• PHP VERSION: Cadena que representa la versión del intérprete de PHP en uso.
• PHP OS: Cadena con el nombre del sistema operativo en el que se está ejecutando el
intérprete de PHP.
• TRUE: Verdadero.
• FALSE: Falso.
• E_ERROR: Información sobre errores distintos a los de interpretación del cual no es posi-
ble recuperarse.
19.3.5 EXPRESIONES
Las expresiones son la base principal de PHP, que es, en sí, un lenguaje orientado a expresiones,
ya que casi todo en él es una expresión. La forma más ajustada de definir qué es una expresión
es: "cualquier cosa que tiene o produce un valor".
Una expresión puede ser algo tan simple como un número o una variable, o puede incluir muchas
variables, constantes, operadores y funciones conjuntamente. Las expresiones como grupo, si son
correctas, son evaluadas a un valor simple. Este valor resultante debe ser clasificado dentro de
uno de los tipos de datos que maneja PHP (integer, float, string, boolean, array, object).
Las expresiones más básicas son las variables y las constantes. Otro tipo de expresiones lo for-
man las expresiones de comparación que se evalúana 0 ó 1 correspondiendo con el valor false o
true, respectivamente. También tenemos las expresiones que surgen corno resultado de la combi-
nación de operador y operandos. Así, podríamos continuar enumerando todos los posibles tipos
de expresiones.
19.3.6 OPERADORES
Los operadores en PHP son muy parecidos a los de otros lenguajes como C, Java y JavaScript. Se
utilizan para determinar un valor, o bien, para obtener un valor final a partir de uno o más operan-
dos. Podemos encontrar varios tipos de operadores, que se clasifican según su uso en los grupos
que veremos a continuación.
Operadores aritméticos
Estos operadores funcionan igual que en la aritmética básica y se pueden aplicar a las variables y
constantes numéricas. Son los siguientes:
• +
• -
• *
• /
• %: Resto de la división entera.
Operadores de asignación
El operador de asignación más utilizado es "="; su función básica es asignar un valor a una varia-
ble, para que de este modo se pueda conservar dicho valor en memoria. El operador de asigna-
ción es un operador binario que siempre toma la forma:
variable = expresión
Este operador de asignación hace que la variable de la izquierda tome el valor de la expresión de
la derecha. Este operador lo hemos utilizado básicamente hasta ahora para asignar valores a las
variables con las que hemos trabajado. PHP soporta otros operadores de asignación, que real-
mente son una combinación del operador de asignación básico con operadores aritméticos y con
el operador de concatenación de cadenas. La siguiente tabla resume los operadores de asigna-
ción:
Operadores de cadenas
A lo largo de los ejemplos anteriores hemos utilizado el operador de concatenación de cadenas
representado por un punto (" . "); como hemos comprobado, devuelve como resultado la concate-
nación de sus operandos izquierdos y derechos; también hemos visto el operador de concatena-
ción y asignación, representado por un punto seguido del signo de igualdad (" . ="). Como su
funcionalidad es la vista hasta el momento, no es necesario profundizar más en estos operadores.
20.1 INTRODUCCIÓN
No todos los problemas que se nos plantean tienen una solución basada en la ejecución secuen-
cial de instrucciones; por eso, es necesario dotar a los lenguajes de programación de herramientas
que los permitan adaptarse a las diferentes situaciones o condiciones que se pueden dar a la hora
de intentar resolver un problema.
Las estructuras de control o sentencias de control nos permiten modificar el flujo de ejecución
básico del programa, es decir, gracias a ellas la ejecución no tiene por qué ser totalmente secuen-
cial, vamos a poder controlar el flujo lógico de cualquier programa. Estas estructuras nos permi-
ten bifurcar el flujo del programa y así ejecutar unas partes u otras de código según se cumplan
una serie de condiciones, hacer que un determinado código no llegue a ejecutarse nunca o que lo
haga tantas veces como queramos.
A continuación enumeramos las distintas estructuras de control que nos podemos encontrar en un
programa PHP. Son comunes en cuanto a concepto en la mayoría de los lenguajes de programa-
ción de alto nivel y casi idénticas a las que presentan lenguajes como C, C++, Java y también
Perl.
Son las estructuras de control más sencillas, se basan en el uso de la sentencia if . . . else y en las
diferentes formas que ésta puede presentar. Utilizando estas sentencias, somos capaces de hacer
que el programa elija entre dos caminos de ejecución diferentes en función de la evaluación de
una expresión lógica.
20.2 FUNDAMENTOS DEL LENGUAJE - II
20.2.1 IF
Es una de las más utilizadas e importantes en la mayoría de los lenguajes de programación. Su
sintaxis es la siguiente:
if (condicion)
{ [sentencias]
}
El intérprete de PHP lo que hace es evaluar la condicion, que debe ser una expresión lógica y, si
resulta verdadera, se ejecutarán las sentencias comprendidas entre las llaves "{" y "}" y, si es
falsa, PHP ignorará las sentencias y seguirá con la ejecución normal del programa. es decir, nos
permite tomar decisiones en torno a una condición.
Las sentencias i f se pueden anidar, es decir, podemos poner dentro de un bloque if otras senten-
cias if, lo cual proporciona una flexibilidad completa para ejecuciones condicionales. Haciendo
uso de ifs sanidados, el siguiente código da el mismo resultado que el mostrado en el ejemplo
anterior:
<HTML>
<HEAD>
<TITLE>Estructuras de Control</TITLE>
</HEAD>
<BODY>
<CENTER>
<H2>Sentencia <I>if</I></H2>
<?php
$a=3;
$b=7;
$c=9;
echo "<BR>Los tres números a comparar son: ";
echo "<B>$a, $b </B>y<B> $c</B><BR><BR>";
echo " y el mayor es el <B>";
if ($a>$b){
if($a>$c){
echo $a;
}
}
if ($b>$a){
if($b>$c){
echo $b;
}
}
if ($c>$a){
if($c>$b){
echo $c;
}
}
echo "</B>";
?>
</CENTER>
</BODY>
</HTML>
20.2.2 IF...ELSE
A menudo nos interesa ejecutar un código distinto si la evaluación de la expresión que acompaña
a la instrucción if no es cierta. Utilizamos entonces la sentencia if ... else; ésta consta de un blo-
que if que se ejecuta cuando la expresion se evalúa a true y de un bloque else cuyas instrucciones
se ejecutan cuando se evalúa a false. La sintaxis de la instrucción if ... else es la siguiente:
if (expresion)
{ sentencias
} else {
sentencias
}
20.2.3 IF...ELSEIF
Hay muchas ocasiones en que se quiere evaluar una nueva comprobación utilizando una senten-
cia if dentro del cuerpo de una sentencia else; para estos casos se puede utilizar la sentencia elseif
que nos permite combinar ambas sentencias en una sola. La sintaxis de la sentencia if . . . elseif es
la siguiente:
if (expresión)
{ sentencias
} elseif (expresión)
{ sentencias
}
[elseif (expresión)
{ sentencias }]...
[else {
sentencias } ]
La sentencia elseif se ejecuta si, y sólo si, se evalúa a true y la expresión if precedente y cualquier
expresión elseif precedente se evalúan a falce. Su comportamiento, por lo demás, coincide con el
de las sentencias if anteriores.
El siguiente ejemplo nos muestra un posible uso de esta estructura aplicado al ejemplo anterior:
<HTML>
<HEAD>
<TITLE>Estructuras de Control</TITLE>
</HEAD>
<BODY>
<CENTER>
<H2>Sentencia <I>if</I></H2>
<?php
$a=3;
$b=7;
$c=9;
echo "<BR>Los tres números a comparar son: ";
echo "<B>$a, $b </B>y<B> $c</B><BR><BR>";
if ($a>$b){
if($a>$c){
$elmayor=$a;
}
else {
$elmayor=$c;
}
}
elseif($b>$c){
$elmayor=$b;
}
else {
$elmayor=$c;
}
echo " y el mayor es el <B>$elmayor</B>";
?>
</CENTER>
</BODY>
</HTML>
20.2.5 SWITCH
La sentencia switch se utiliza para comparar un dato con un conjunto de posibles valores. Esta
tarea se puede realizar utilizando múltiples sentencias if o con una sentencia if...elseif múltiple,
pero la sentencia switch es mucho más legible y nos permite especificar un conjunto de senten-
cias por defecto, en el caso de que el dato no tenga un valor con que compararlo (equiparable a la
cláusula else de la sentencia if). La sintaxis de la sentencia switch es la siguiente:
switch ($variable) {
case valorl: [sentencias;]
[break;]
case valor2: [sentencias;]
[break;]
case valorN: [sentencias;]
[break;]
[ default: sentencias;]
}
En el caso de que el valor de la variable no coincida con ninguna cláusula case, se ejecutará la
opción default. Esta opción se puede omitir del switch y, entonces, no habría ninguna acción por
defecto. La sentencia break dentro de cada una de las cláusulas case permite que, una vez encon-
trado el valor buscado, no se sigan realizando más comparaciones; fuerza la finalización de la
sentencia switch. Si no se utiliza la sentencia break dentro de las cláusulas case, la ejecución de
una cláusula continúa por la siguiente.
switch($dia){
case "Mon": echo "Lunes";
break;
case "Tue": echo "Martes";
break;
case "Wed": echo "Miércoles";
break;
case "Thu": echo "Jueves";
break;
case "Fri": echo "Viernes";
break;
case "Sat": echo "Sábado";
break;
default: echo "Domingo";
}
echo "</B>";
?>
</CENTER>
</BODY>
</HTML>
La utilización de bucles dentro de un script sirve para muchos propósitos. Un uso sencillo, pero
habitual, es utilizar los bucles para contar. También se utilizan para recorrer objetos o estructuras
compuestas por más de un elemento, como ocurre con las estructuras de tipo array.
20.3.1 FOR
Esta instrucción nos permite realizar un conjunto de instrucciones un determinado número de
veces. Es una de las estructuras de control sintácticamente más complejas de PHP.
• exp_condición define una o más condiciones que han de cumplirse (evaluarse a true) para
poder ejecutar las sentencias encerradas entre las llaves. Mientras estas condiciones sean
ciertas, se estarán ejecutando las sentencias delimitadas entre llaves. La expresión se eva-
lúa antes de cada iteración y, si no se cumple la condición, ya no se ejecutan las sentencias.
Es muy importante comprobar la corrección de esta expresión porque, si inicialmente no
se cumple el cuerpo de la sentencia, no llegaría a ejecutarse nunca y si, al contrario, siem-
pre se evalúa a true, estaríamos ante un caso de bucle infinito. Suele tener la forma:
$variable <= límite
<HEAD>
<TITLE>Estructuras de Control</TITLE>
</HEAD>
<BODY>
<CENTER>
<H2>Sentencia <I>for</I></H2>
<?php
echo "la suma de los 10 primeros números enteros es:";
$suma=0;
for($i=1;$i<=10;$i++){
$suma+=$i;
echo ($i==10)?"$i = ":"$i+";
}
echo "<B>$suma</B>";
?>
</CENTER>
</BODY>
</HTML>
20.3.2 FOREACH
Esta sentencia nos permite recorrer las estructuras de tipo array de una forma sencilla, obte-
niendo en cada paso de la iteración uno de sus elementos componentes. También se suele utilizar
para traducir tablas de tipo hash, tal y como veremos más adelante.
El siguiente ejemplo nos muestra dos formas de recorrer un array. En la primera se utiliza un
bucle for y en la segunda un bucle foreach. Comno podernos observar en el segundo caso, no es
necesario conocer la cantidad de elementos que conforman el array, puesto que la sentencia man-
tiene un puntero interno para recorrerlo:
<HTML>
<HEAD>
<TITLE>Estructuras de Control</TITLE>
</HEAD>
<BODY>
<CENTER>
<H2>Sentencia <I>foreach</I></H2>
<?php
// creamos el array y llenamos de datos
$matriz[0]="cougar";
$matriz[1]="ford";
// posición sin contenido
$matriz[2]=null;
$matriz[3]="2.500";
$matriz[4]="V6";
$matriz[5]=182;
?>
<TABLE BORDER="1" CELLPADDING="2" CELLSPACING="2">
<TR ALIGN="center" BGCOLOR="yellow">
<?php
for($i=0;$i<6;$i++){
echo "<TD> $matriz[$i] </TD>";
}
?>
</TR>
<TR ALIGN="center" BGCOLOR="yellow">
<?php
foreach($matriz as $valor){
echo "<TD> $valor </TD>";
}
?>
</TR>
</TABLE>
</CENTER>
</BODY>
</HTML>
Corno podernos observar, aunque una posición del array esté vacía (la posición 2), el recorrido
no la salta, si bien una posición no utilizada (posición 5) no aparece en este tipo de recorridos.
Finalmente, se debe decir que esta sentencia se puede aplicar también a un arrue de tipo asocia-
tivo, en el que el índice de cada elemento no es de tipo numérico.
20.3.3 WHILE
La sentencia while actúa de forma muy parecida a la sentencia for, pero se diferencia de ésta en
que no incluye en su declaración la inicialización de la variable de control del bucle ni su incre-
mento o decremento. Por tanto, dicha variable se deberá declarar antes del bucle while y su incre-
mento o decremento se deberá realizar dentro del cuerpo de dicho bucle. La sintaxis de la
instrucción while es la siguiente:
while (condición)(
sentencias;
}
Con esta instrucción se va a poder ejecutar un conjunto de instrucciones un indeterminado
número de veces, siempre y cuando el resultado de comprobar la condición sea verdadera (debe
ser una expresión que se evalúe a un valor lógico). Si la condición se evalúa a true, se ejecutan
las sentencias del cuerpo del bucle; después de ejecutarlas, se volverá a evaluar la condición, de
forma que, si ésta sigue cumpliéndose, se volverán a ejecutar las sentencias. Esto se repite hasta
que la condición se evalúa a false, en cuyo caso no se ejecutarán las sentencias del cuerpo del
bucle y continuará la ejecución del script por la instrucción siguiente a la sentencia while.
<HTML>
<HEAD>
<TITLE>Estructuras de Control</TITLE>
</HEAD>
<BODY>
<CENTER>
<H2>Sentencia <I>while</I></H2>
<?php
echo "la suma de los 10 primeros números enteros es: ";
$suma=0;
$i=1;
while($i<=10){
$suma+=$i;
echo ($i==10)?"$i = ":"$i+";
$i++;
}
echo "<B>$suma</B>";
?>
</CENTER>
</BODY>
</HTML>
Como podemos observar en el código, la inicialización de la variable que se utiliza para controlar
el final del bucle, $i, se realiza fuera de él, mientras que su actualización forma parte de las ins-
trucciones del cuerpo de la sentencia while. Es muy importante comprobar la corrección de la
condición porque, si inicialmente no se cumple, el cuerpo de la sentencia no llegaría a ejecutarse
nunca y si, por el contrario, siempre se evalúa a true, estaríamos ante un caso de bucle infinito.
20.3.4 DO...WHILE
Esta sentencia funciona exactamente igual que el bucle while, excepto que la condición no se
comprueba hasta que se ha realizado una iteración (la condición se comprueba al final de cada
iteración). Esto garantiza que, al menos, el cuerpo del bucle se realiza una vez, aunque la expre-
sión condición se evalúe a false. Como siempre, condición debe ser una expresión que se evalúe
a un valor lógico.
Asimismo, es posible que nos interese que la ejecución del cuerpo del bucle no contemple siem-
pre las mismas instrucciones, es decir, que, al alcanzar una cierta posición dentro del cuerpo del
bucle, las sentencias restantes no se ejecuten y que vuelva a evaluarse de nuevo la expresión del
bucle (si existe) continuando con la siguiente iteración; para ello, utilizaremos la instrucción con-
tinue.
Las instrucciones break y continue se pueden utilizar dentro de los cuerpos de todas las senten-
cias de control de bucles, desde el for hasta el do..while.
El siguiente ejemplo nos muestra la utilización de la instrucción break para finalizar la ejecución
de un bucle:
<HTML>
<HEAD>
<TITLE>Estructuras de Control</TITLE>
</HEAD>
<BODY>
<CENTER>
<H2>Sentencia <I>break</I></H2>
<?php
$numero=6;
echo "<BR><B>$numero!</B> = ";
$factorial=1;
while (1){
echo $numero." x ";
$factorial*=$numero;
$numero--;
if ($numero==1){
break;
}
}
echo "1 = <B>$factorial</B>";
?>
</CENTER>
</BODY>
</HTML>
Como podemos observar en el código, la condición de salida del bucle nunca se cumple; por
tanto, estaríamos ejecutando un bucle infinito de no ser por la existencia de la instrucción break
dentro de su cuerpo.
Como podernos observar en el código, sólo cuando encontrarnos un número divisible por 3 y por
5, éste se muestra por pantalla a través de la instrucción echo; en el resto de las ocasiones, la ins-
trucción continue hace que la ejecución salte a la siguiente iteración del bucle sin tener en cuenta
las instrucciones que aparecen por debajo de ella. El resultado se muestra en la figura (Fig. 20.6).
Finalmente, se debe comentar que ambas sentencias admiten un parámetro opcional con el que
podemos indicar el número de estructuras de control que deben saltarse en caso de que en el
código existan anidamientos de bucles. Esto nos permite decidir el nivel de ruptura que queremos
dentro del bucle cuando se ejecuta alguna de estas dos sentencias. Las sentencias break y conti-
nue, por defecto, sólo saltan un nivel de anidamiento, el del bucle más interno que las contiene
(consultar libro de texto y manual on line).
Las funciones que abordarnmos en esta sección deben incluirse dentro de las estructuras de con-
trol del lenguaje, puesto que pueden influir en gran manera en el flujo de ejecución e interpreta-
ción de los scripts que las contengan (sobre todo si los ficheros a incluir contienen a su vez
código PHP). Deben ser consideradas más bien corno construcciones del lenguaje, no como sim-
ples funciones.
Esta facilidad del lenguaje se utiliza principalmente para la definición de librerías comunes a
varios scripts, permitiendo, de este modo, una reutilización y mantenimiento del código más
óptimos. La naturaleza del fichero externo a incluir puede ser de cualquier tipo PHP, HTML,
TXT, etc.
20.4.1 INCLUDE()
Esta función incluye y evalúa un fichero externo cada vez que es interpretada. Ambos pasos, la
inclusión del fichero externo y su posterior evaluación, se realizan cada vez que el flujo del pro-
grama llega a una línea que contenga la llamada a esta función. En caso de que el fichero a incluir
no exista o su referencia sea errónea, la función genera un aviso o warning, continuando con la
ejecución por la siguiente instrucción.
include(“nombre de fichero”)
Cuando un archivo se incluye con include() , el intérprete sale del modo PHP y entra en modo
HTML al principio del archivo referenciado, y vuelve de nuevo al modo PHP al acabar de leer
dicho archivo. Por esta razón, cualquier código dentro del archivo referenciado que debiera ser
ejecutado como código PHP debe ser encerrado dentro de etiquetas válidas de comienzo y fin de
PHP
Todas las funciones y variables definidas con anterioridad a la llamada a la función include() son
accesibles para el código presente en el fichero importado. De igual forma, todos los elementos
definidos en el código PHP del fichero incluido estarán disponibles para el script llamante una
vez se haya terminado la lectura y ejecución del fichero incluido.
El ámbito de las variables que se definen en los scripts del fichero incluido depende del lugar
desde el que se realiza la llamada. Si la llamada se realiza desde el cuerpo de una función, las
variables tendrán ámbito local (a no ser que estén definidas con el modificador global); en cual-
quier otro caso tendrán ámbito global.
La función include( ) puede utilizarse en combinación con otras estructuras de control de flujo.
El contenido del fichero se incluirá y evaluará sólo cuando se interprete la llamada. Si el flujo de
ejecución del script nunca alcanza la línea en la que se realiza la llamada, el fichero nunca será
incluido. Cuando esta función se utiliza dentro de estructuras de bucle o condicionales, siempre
debe aparecer entre llaves, pues, en otro caso, podría obtenerse un resultado no deseado.
20.4.2 INCLUDE_ONCE()
Su funcionamiento es idéntico al de la función include O , con la única salvedad de que esta fun-
ción sólo cargará y evaluará cada script una vez como máximo. Con esta función nos aseguramos
de que un fichero sólo se ha cargado una vez a lo largo de la interpretación de nuestro script, evi-
tando, de este modo, los errores producidos por la redefinición de funciones o la reasignación de
valores a variables.
Ejercicio: Idear un ejemplo con dos ficheros en los que se ponga de manifiesto las diferen-
cias entre include() e include_once().
20.4.3 REQUIRE()
Esta función se comporta en líneas generales corno la función include() , pero con las siguientes
salvedades:
1 require( ) sólo incluye el fichero referenciado, es decir, no lo interpreta. Su comporta-
miento es equivalente a la directiva #include del lenguaje C.
2 require() no puede ser utilizado con estructuras condicionales o de control de bucles por-
que el contenido del fichero referenciado se incluye antes de que se evalúe la sentencia que
lo contiene y se incluye siempre aunque la condición que lo contiene no se cumpla. No
obstante, si la línea en la que aparece require() no se ejecuta, tampoco se ejecutará el
código del archivo al que esta llamada haga referencia.
3 En caso de que el fichero referenciado por require() no exista, se genera un error fatal que
no nos permite continuar con la ejecución del script.
4 Se desaconseja pasar variables corno parámetros de la función require() , si bien este tipo
de construcción funciona.
Cadenas
21.1 INTRODUCCIÓN
Como vimos en temas anteriores, una cadena está formada por cero o más caracteres encerrados
entre dobles comillas (" ") o entre comillas simples (‘ ‘). Es obligatorio utilizar siempre el mismo
tipo de comilla para rodear cada cadena, aunque en algunos casos se puede entremezclar el uso
de los dos tipos de entrecomillado, principalmente para insertar una cadena literal dentro de otra
(aunque para este tipo de acciones también se utiliza el enmascarado (escuped) de las comillas,
es decir, anteponer a las comillas el carácter "\").
Se debe recordar que, cuando utilizamos comillas dobles, podemos incluir dentro de la cadena
nombres variables o caracteres especiales que serán evaluados (sustituidos por sus respectivos
valores) a la hora de mostrar la información, cosa que no ocurre si introducimos nombres de
variables dentro de una cadena encerrada entre comillas simples.
En el siguiente ejemplo se verá el comportamiento de PHP ante cadenas con comillas dobles o
simples, y cómo insertar una comilla doble dentro de una cadena delimitada por comillas dobles:
<HTML>
<HEAD>
<TITLE>Trabajando con Cadenas</TITLE>
21.2 CADENAS
</HEAD>
<BODY>
<CENTER>
<H2>Comillas dobles y simples</H2>
<?php
$cadena='un tesoro';
echo "la cadena '$cadena' contiene: $cadena<br><br>";
echo "la cadena \"$cadena\" contiene: $cadena<br><br>";
echo 'la cadena "$cadena" contiene: $cadena<br><br>';
?>
</CENTER>
</BODY>
</HTML>
Comenzamos con las funciones que nos permiten visualizar y formatear cadenas de caracteres,
permitiéndonos gestionar, de este modo, la salida de los datos por pantalla:
• echo(cadena), print(cadena) : No son funciones propiamente dichas, sino construcciones
del lenguaje. Ambas muestran información por la salida estándar; no soportan ningún atri-
buto de formato de salida y sólo admiten una única cadena corno argumento en su llamada
(cuando necesitamos pasar más de un argumento a cualquiera de estas funciones, debere-
mos utilizar las comillas).
• printf(formato [, argumentos] ): Imprime información por la salida estándar soportando
diferentes formatos de salida. Admite múltiples tipos de argumentos a visualizar.
Imprime una cadena cuya estructura depende del formato descrito en el argumento for-
mato. Esta cadena está formada por una ristra de caracteres, algunos de los cuales se mos-
trarán directamente, mientras que otros, los que van precedidos por el carácter "%",
conocidos corno especificaciones de conversión, son utilizados para formatear la informa-
ción.
El siguiente ejemplo nos muestra la utilidad de esta función para formatear resultados en panta-
lla:
<HTML>
<HEAD>
<TITLE>Trabajando con Cadenas</TITLE>
</HEAD>
<BODY>
<CENTER>
<H2>Función <I>printf</I></H2>
<?php
$euro=166.386;
printf ("%s--- %02d/%02d/%04d ---","<B>Convertidor de Euros ", 3,
4, 2001);
echo "</B><BR><BR>";
for ($i=100;$i<1100;$i+=100)
printf("%4d Ptas. -> %02.2f €%s",$i,$i/$euro,"<BR>");
?>
</CENTER>
</BODY>
</HTML>
No se debe abusar del uso de estas funciones cuando no haya que aplicar un formato especí-
fico a los datos o el formato no sea importante, porque se obtienen mejores resultados
haciendo uso de la función echo y concatenando las cadenas con el operador ". ".
Podemos acceder a cada uno de los caracteres que componen una cadena haciendo referencia a la
posición que ocupan dentro de ella, de igual modo a como referenciamos los diferentes compo-
nentes de una matriz o array. Para ello, se hace indispensable conocer el tamaño de la cadena a
recorrer.
• strlen(cadena): Devuelve la longitud de la cadena pasada como argumento. El siguiente
ejemplo nos muestra un modo básico de recorrer los diferentes componentes de una
cadena:
<HTML>
<HEAD>
<TITLE>Trabajando con Cadenas</TITLE>
</HEAD>
<BODY>
<CENTER>
<H2>Función <I>strlen</I></H2>
<?php
$cadena="Saludos";
echo "<TABLE BORDER='1'CELLPADDING='2' CELLSPACING='2'>\n";
echo "<TR BGCOLOR='yellow'><TD>Carácter</TD><TD>Posición</TD></
TR>\n";
for($i=0;$i<strlen($cadena);$i++)
echo "<TR ALIGN='center'><TD>".$cadena[$i]."</TD><TD>".$i."</
TD></TR>\n";
echo "</TABLE>\n";
?>
</CENTER>
</BODY>
</HTML>
Una de las operaciones más habituales sobre las cadenas es la búsqueda de caracteres y subcade-
nas componentes, para su posterior tratamiento. Dentro de este tipo de funciones destacan las
siguientes:
• strstr(cadena, cadBusq), strchr(cadena, cadBusq):Busca la aparición de una cadena dentro
de otra y devuelve la subcadena comprendida entre la primera aparición de la cadena bus-
cada (incluyéndola) hasta el final de la cadena en la que se realiza la búsqueda. En caso de
no encontrar la cadena, devuelve una cadena vacía. La búsqueda diferencia entre mayús-
culas y minúsculas.
• strrchr (cadena, cadBusq) : Busca la aparición de un carácter (aunque se utilice una
cadena de búsqueda sólo tiene en cuenta su primer carácter) en una cadena y devuelve la
subcadena comprendida entre la última aparición del carácter (incluido) hasta el final de la
Otra operación común con cadenas es compararlas para saber cuál es mayor. Dentro de este tipo
de funciones destacan las siguientes:
• strcmp(cad1, cad2) : Compara dos cadenas y devuelve un valor menor que 0, si la segunda
cadena es mayor que la primera: mayor que 0, en caso contrario, y 0, si ambas cadenas son
iguales. La comparación distingue entre mayúsculas y minúsculas.
• strcasecmp(cad1 , cad2) : Se comporta igual que strcmp( ) , excepto en que no diferencia
mayúsculas de minúsculas.
• strncmp(cad1, cad2 , long) : Funciona como strcmp() , sólo que permite comparar los long
primeros caracteres de dos cadenas. Si alguna cadena es menor que el número de caracte-
res a comparar, se usará su longitud como long para la comparación. Diferencia mayúscu-
las de minúsculas.
• strnatcmp(cadl , cad2) : Se comporta igual que strcmp( ), excepto en que utiliza una com-
paración "natural" de las cadenas alfanuméricas. Distingue entre mayúsculas y minúscu-
las.
• strnatcasecmp(cadí , cad2) : Se comporta igual que strnatcmp(), excepto en que no dife-
rencia entre mayúsculas y minúsculas.
No siempre nos interesan todos los caracteres que componen una cadena, sino que sólo estamos
interesados en trabajar con un conjunto. Para ello contarnos con un conjunto de funciones prepa-
radas para extraer subcadenas de una cadena original. Entre las más utilizadas están:
• substr(cadena, inicio [ , tamaño] ) : Devuelve la subcadena que se encuentra a partir de
una posición dada y llega hasta el final de la cadena original, pudiendo de forma opcional
decidir el tamaño de la subcadena a recuperar. Los argumentos enteros pueden ser núme-
ros negativos de modo que:
- Una posición de inicio con valor negativo significa que se debe comenzar desde el
final de la cadena.
- Un tamaño con valor negativo indica cuántos caracteres del final de la cadena no se
tendrán en cuenta.
<HTML>
<HEAD>
<TITLE>Trabajando con Cadenas</TITLE>
</HEAD>
<BODY>
<CENTER>
<H2>Funciones <I>substr</I></H2>
<?php
$cadena="abcdefghi";
$ini1 = 2;
$ini2 = -2;
$tam1 = 3;
$tam2 = -3;
echo "<TABLE BORDER='1'CELLPADDING='2' CELLSPACING='2'>\n";
echo "<TR ALIGN='center'><TD BGCOLOR='yellow'>cadena</TD>";
echo "<TD>$cadena</TD></TR>\n";
echo "<TR ALIGN='center'>";
echo "<TD BGCOLOR='yellow'>substr(cadena,$ini1)</TD>";
echo "<TD>".substr($cadena,$ini1)."</TD></TR>\n";
echo "<TR ALIGN='center'>";
echo "<TD BGCOLOR='yellow'>substr(cadena,$ini1,$tam1)</TD>";
echo "<TD>".substr($cadena,$ini1,$tam1)."</TD></TR>\n";
echo "<TR ALIGN='center'>";
echo "<TD BGCOLOR='yellow'>substr(cadena,$ini2)</TD>";
echo "<TD>".substr($cadena,$ini2)."</TD></TR>\n";
echo "<TR ALIGN='center'>";
echo "<TD BGCOLOR='yellow'>substr(cadena,$ini1,$tam2)</TD>";
echo "<TD>".substr($cadena,$ini1,$tam2)."</TD></TR>\n";
echo "</TABLE>\n";
?>
</CENTER>
</BODY>
</HTML>
para que el intérprete de PHP los considere como a otro cualquiera. Para realizar operaciones con
caracteres especiales, PHP cuenta con las siguientes funciones:
$datos = strtok($cadena,$patron);
echo "<TABLE BORDER='1'CELLPADDING='2' CELLSPACING='2'>\n";
echo "<TR ALIGN='center'>";
echo "<TD BGCOLOR='yellow'>cadena</TD><TD>$cadena</TD>\n";
echo "<TR ALIGN='center'>"; echo "<TD COLSPAN='2'
BGCOLOR='yellow'>substr_count(cadena,'$patron')</TD>";
echo "</TR>\n";
while($datos){
echo "<TR ALIGN='center'>";
echo "<TD BGCOLOR='yellow'>subcadena</TD>";
echo "<TD>$datos</TD></TR>\n";
$datos=strtok($patron);
}
echo "</TABLE>\n"
?>;
</CENTER>
</BODY>
</HTML>
Gran parte de las cadenas con las que trabaja PHP tienen como función convertirse en partes de
un documento HTML que será enviado al usuario. Para facilitar algunas de los problemas que
tiene la transformación de texto en código HTML válido, PHP proporciona las siguientes funcio-
nes entre otras:
• htmlspecialchars(cadena) : Se encarga de convertir los caracteres con un significado espe-
cial en HTML en entidades HTML según la tabla siguiente.
• htmlentities(cadena) : Es similar a la función anterior, salvo que esta función traduce todos
los caracteres a su correspondiente entidad en HTML.
• str_repeat (cadena, num_veces ) : Recibe corno argumento una cadena y un número entero
para devolver, a continuación, la cadena repetida tantas veces corno indique el número
entero.
• strrev (cadena) : Devuelve la cadena invertida.
Arrays
22.1 INTRODUCCIÓN
Los arrays o matrices forman una parte muy importante de la programación en PHP ya que per-
miten manejar grupos de valores relacionados: nos permiten almacenar múltiples valores en una
sola estructura y, de esta forma, asociarlos bajo una misma denominación. Como veremos, PHP
tiene gran cantidad de funciones cuyos parámetros, tanto de llamada como de resultados, son
variables de tipo array. En especial, son ampliamente utilizados en las funciones ligadas a las
bases de datos.
En este tema profundizaremos en los distintos tipos de arrays que podemos definir, escalares y
asociativos, tanto unidimensionales como multidimensionales, y las distintas formas de hacerlo.
Veremos las principales funciones para su manejo y tratamiento.
Un array escalar, o simple, está formado por un conjunto de valores ordenados respecto a un
índice de tipo entero. Este índice indicará la posición del elemento dentro de esta colección orde-
nada, de modo que, en cada posición marcada por el índice dentro del array, haya un valor.
Existen diferentes formas de crear arrays. La más sencilla consiste en asignar el valor de cada
elemento de manera explícita, es decir, indicando cada uno de los valores que lo componen e,
incluso, la posición que ocupan dentro del array. El siguiente ejemplo nos muestra estas dos for-
mas equivalentes de definir el mismo array:
<HTML>
<HEAD>
<TITLE>Trabajando con Matrices</TITLE>
</HEAD>
<BODY>
22.2 ARRAYS
<CENTER>
<H2>Arrays <I>simples</I></H2>
<?php
$matriz1[0]="cougar";
$matriz1[1]="ford";
$matriz1[2]="";
$matriz1[3]="2.500";
$matriz1[4]="V6";
$matriz1[5]=172;
$matriz2[]="cougar";
$matriz2[]="ford";
$matriz2[]="";
$matriz2[]="2.500";
$matriz2[]="V6";
$matriz2[]=172;
?>
<TABLE BORDER="1" CELLPADDING="2" CELLSPACING="2">
<TR ALIGN="center" BGCOLOR="yellow">
<TD>índice</TD>
<?php
for($i=0;$i<=5;$i++)
echo "<TD>$i</TD>";
?>
</TR>
<TR ALIGN="center">
<TD BGCOLOR="yellow">$matriz1</TD>
<?php
echo "<TD> $matriz1[0] </TD>";
echo "<TD> $matriz1[1] </TD>";
echo "<TD> $matriz1[2] </TD>";
echo "<TD> $matriz1[3] </TD>";
echo "<TD> $matriz1[4] </TD>";
echo "<TD> $matriz1[5] </TD>";
?>
</TR>
<TR ALIGN="center">
<TD BGCOLOR="yellow">$matriz2</TD>
<?php
echo "<TD> $matriz2[0] </TD>";
echo "<TD> $matriz2[1] </TD>";
echo "<TD> $matriz2[2] </TD>";
echo "<TD> $matriz2[3] </TD>";
echo "<TD> $matriz2[4] </TD>";
echo "<TD> $matriz2[5] </TD>";
?>
</TR>
</TABLE>
</CENTER>
</BODY>
</HTML>
Como observamos en el código anterior, un array puede combinar elementos de naturaleza dis-
tinta: en el ejemplo, valores enteros y cadenas de caracteres (que deben aparecer entrecomilla-
dos) e, incluso, elementos vacíos. El resultado se muestra en la siguiente imagen :
Cuando, al generar el array, no indicamos la posición de sus elementos, éstos se van situando
secuencialmente respecto a la última asignación realizada sobre el array. La asignación numérica
de posiciones dentro del array no tiene por qué ser secuencial, es decir, podemos definir el orden
numérico que nos interese.
La otra forma de definir arrays es utilizar el constructor array ( ) proporcionado por el lenguaje.
Este constructor no es una función regular; tiene la siguiente definición:
array array (mixed valores,...)
El siguiente ejemplo nos muestra cómo utilizar este constructor para definir el mismo array que
en ejemplos anteriores:
<HTML>
<HEAD>
<TITLE>Trabajando con Matrices</TITLE>
</HEAD>
<BODY>
<CENTER>
<H2>El constructor <I>array</I></H2>
<?php
$matriz1 = array("cougar","ford",null,"2.500","V6",172);
?>
<TABLE BORDER="1" CELLPADDING="2" CELLSPACING="2">
<TR ALIGN="center" BGCOLOR="yellow">
<TD>índice</TD>
<?php
for($i=0;$i<=5;$i++)
echo "<TD>$i</TD>";
?>
</TR>
<TR ALIGN="center">
<TD BGCOLOR="yellow">$matriz1</TD>
<?php
echo "<TD> $matriz1[0] </TD>";
echo "<TD> $matriz1[1] </TD>";
echo "<TD> $matriz1[2] </TD>";
echo "<TD> $matriz1[3] </TD>";
echo "<TD> $matriz1[4] </TD>";
echo "<TD> $matriz1[5] </TD>";
?>
</TR>
</TABLE>
</CENTER>
</BODY>
</HTML>
El constructor array ( ) también nos permite asignar los elementos del array en el orden en que
queramos. Para ello, indicamos el índice, seguido del símbolo "=>" y el valor del elemento. Por
ejemplo:
<HTML>
<HEAD>
<TITLE>Trabajando con Matrices</TITLE>
</HEAD>
<BODY>
<CENTER>
<H2>El constructor <I>array</I></H2>
<?php
$matriz1 = array("cougar","ford",null,"2.500","V6",172);
$matriz2 = array(2=>"cougar","ford",1=>null,0=>"2.500","V6",172);
?>
<TABLE BORDER="1" CELLPADDING="2" CELLSPACING="2">
<TR ALIGN="center" BGCOLOR="yellow">
<TD>índice</TD>
<?php
for($i=0;$i<=5;$i++)
echo "<TD>$i</TD>";
?>
</TR>
<TR ALIGN="center">
<TD BGCOLOR="yellow">$matriz1</TD>
<?php
echo "<TD> $matriz1[0] </TD>";
echo "<TD> $matriz1[1] </TD>";
echo "<TD> $matriz1[2] </TD>";
echo "<TD> $matriz1[3] </TD>";
echo "<TD> $matriz1[4] </TD>";
echo "<TD> $matriz1[5] </TD>";
?>
</TR>
<TR ALIGN="center">
<TD BGCOLOR="yellow">$matriz2</TD>
<?php
echo "<TD> $matriz2[0] </TD>";
echo "<TD> $matriz2[1] </TD>";
echo "<TD> $matriz2[2] </TD>";
echo "<TD> $matriz2[3] </TD>";
echo "<TD> $matriz2[4] </TD>";
echo "<TD> $matriz2[5] </TD>";
?>
</TR>
</TABLE>
</CENTER>
</BODY>
</HTML>
Como se muestra en la imagen anterior (Fig. 22.2), los elementos a los que no se les asigna explí-
citamente un índice toman la posición secuencial relativa a la última asignación de posición den-
tro del array.
A diferencia de los arrays simples, los arrays asociativos (también conocidos como tablas hash o
arrays indexados por cadena) están formados por un conjunto de valores que están ordenados res-
pecto a un índice de tipo string, es decir, una cadena de caracteres. De este modo, nuestro array
va a estar compuesto por pares clave-valor, siendo necesario proporcionar la clave para poder
acceder al valor almacenado en el array.
De igual forma que ocurre con los arrays simples, podernos utilizar el constructor del lenguaje
array ( ) para definirlos, o bien, hacerlo especificando de forma explícita cada uno de sus compo-
nentes. El siguiente ejemplo nos muestra ambas posibilidades:
<HTML>
<HEAD>
<TITLE>Trabajando con Matrices</TITLE>
</HEAD>
<BODY>
<CENTER>
<H2>Arrays <I>asociativos</I></H2>
<?php
$matriz1 = array("modelo"=>"cougar","marca"=>"ford",
"fecha"=>null,"cc"=>"2.500","motor"=>"V6",
"potencia"=>172);
$matriz2['modelo']="cougar";
$matriz2['marca']="ford";
$matriz2['fecha']=null;
$matriz2['cc']="2.500";
$matriz2['motor']="V6";
$matriz2['potencia']=182;
?>
<TABLE BORDER="1" CELLPADDING="2" CELLSPACING="2">
<TR ALIGN="center" BGCOLOR="yellow">
<TD></TD>
<TD>Modelo</TD>
<TD>Marca</TD>
<TD>Fecha</TD>
<TD>CC</TD>
<TD>Motor</TD>
<TD>Potencia</TD>
</TR>
<TR ALIGN="center">
<TD BGCOLOR="yellow">$matriz1</TD>
<?php
echo "<TD>".$matriz1['modelo']."</TD>";
echo "<TD>".$matriz1['marca']."</TD>";
echo "<TD>".$matriz1['fecha']."</TD>";
echo "<TD>".$matriz1['cc']."</TD>";
echo "<TD>".$matriz1['motor']."</TD>";
echo "<TD>".$matriz1['potencia']."</TD>";
?>
</TR>
<TR ALIGN="center">
<TD BGCOLOR="yellow">$matriz2</TD>
<?php
echo "<TD>".$matriz2['modelo']."</TD>";
echo "<TD>".$matriz2['marca']."</TD>";
echo "<TD>".$matriz2['fecha']."</TD>";
echo "<TD>".$matriz2['cc']."</TD>";
echo "<TD>".$matriz2['motor']."</TD>";
echo "<TD>".$matriz2['potencia']."</TD>";
?>
</TR>
</TABLE>
</CENTER>
</BODY>
</HTML>
PHP nos permite definir arrays multidimensionales mediante la combinación de arrays unidi-
mensionales (que pueden ser tanto de tipo escalar, como asociativos). Los siguientes ejemplos
nos muestran las diferentes formas de definirlos.
• Array multidimensional de tipo escalar:
<HTML>
<HEAD>
<TITLE>Trabajando con Matrices</TITLE>
</HEAD>
<BODY>
<CENTER>
<H2>Arrays <I>multidimensionales</I></H2>
<?php
$matriz1[0][0] = "peseta";
$matriz1[0][1] = 166.386;
$matriz1[1][0] = "dolar";
$matriz1[1][1] = 0.96;
$matriz2[0] = array("peseta",166.386);
$matriz2[1] = array("dolar",0.96);
$matriz3 = array(array("peseta",166.386),array("dolar",0.96));
?>
<TABLE BORDER="1" CELLPADDING="2" CELLSPACING="2">
<TR ALIGN="center" BGCOLOR="yellow">
<TD></TD>
<TD>Moneda</TD>
<TD>Cambio €</TD>
</TR>
<?php
for($i=0;$i<2;$i++){
echo "<TR ALIGN='center'>";
echo "<TD BGCOLOR='yellow'>\$matriz1[$i]</TD>";
for($j=0;$j<2;$j++){
echo "<TD>".$matriz1[$i][$j]."</TD>";
}
echo "</TR>";
}
for($i=0;$i<2;$i++){
echo "<TR ALIGN='center'>";
echo "<TD BGCOLOR='yellow'>\$matriz2[$i]</TD>";
for($j=0;$j<2;$j++){
echo "<TD>".$matriz2[$i][$j]."</TD>";
}
echo "</TR>";
}
for($i=0;$i<2;$i++){
echo "<TR ALIGN='center'>";
echo "<TD BGCOLOR='yellow'>\$matriz3[$i]</TD>";
for($j=0;$j<2;$j++){
echo "<TD>".$matriz3[$i][$j]."</TD>";
}
echo "</TR>";
}
?>
</TABLE>
</CENTER>
</BODY>
</HTML>
<BODY>
<CENTER>
<H2>Arrays <I>multidimensionales</I></H2>
<?php
$matriz1['peseta']['moneda'] = "peseta";
$matriz1['peseta']['cambio'] = 166.386;
$matriz1['dolar']['moneda'] = "dolar";
$matriz1['dolar']['cambio'] = 0.96;
$matriz2['peseta']=array("moneda"=>"peseta","cambio"=>166.386);
$matriz2['dolar']=array("moneda"=>"dolar","cambio"=>0.96);
$matriz3 = array("peseta"=>array("moneda"=>"peseta","cambio"=>166.386),
"dolar"=>array("moneda"=>"dolar","cambio"=>0.96));
?>
<TABLE BORDER="1" CELLPADDING="2" CELLSPACING="2">
<TR ALIGN="center" BGCOLOR="yellow">
<TD></TD>
<TD>Moneda</TD>
<TD>Cambio €</TD>
</TR>
<?php
echo "<TR ALIGN='center'>";
echo "<TD BGCOLOR='yellow'>\$matriz1</TD>";
echo "<TD>".$matriz1['peseta']['moneda']."</TD>";
echo "<TD>".$matriz1['peseta']['cambio']."</TD>";
echo "</TR>";
echo "<TR ALIGN='center'>";
echo "<TD BGCOLOR='yellow'>\$matriz1</TD>";
echo "<TD>".$matriz1['dolar']['moneda']."</TD>";
echo "<TD>".$matriz1['dolar']['cambio']."</TD>";
echo "</TR>";
echo "<TR ALIGN='center'>";
echo "<TD BGCOLOR='yellow'>\$matriz2</TD>";
echo "<TD>".$matriz2['peseta']['moneda']."</TD>";
echo "<TD>".$matriz2['peseta']['cambio']."</TD>";
echo "</TR>";
echo "<TR ALIGN='center'>";
echo "<TD BGCOLOR='yellow'>\$matriz2</TD>";
echo "<TD>".$matriz2['dolar']['moneda']."</TD>";
echo "<TD>".$matriz2['dolar']['cambio']."</TD>";
echo "</TR>";
echo "<TR ALIGN='center'>";
echo "<TD BGCOLOR='yellow'>\$matriz3</TD>";
echo "<TD>".$matriz3['peseta']['moneda']."</TD>";
echo "<TD>".$matriz3['peseta']['cambio']."</TD>";
echo "</TR>";
echo "<TR ALIGN='center'>";
echo "<TD BGCOLOR='yellow'>\$matriz3</TD>";
echo "<TD>".$matriz3['dolar']['moneda']."</TD>";
echo "<TD>".$matriz3['dolar']['cambio']."</TD>";
echo "</TR>";
?>
</TABLE>
</CENTER>
</BODY>
</HTML>
$matriz2[0]=array("moneda"=>"peseta","cambio"=>166.386);
$matriz2[1]=array("moneda"=>"dolar","cambio"=>0.96);
$matriz3 = array(array("moneda"=>"peseta","cambio"=>166.386),
array("moneda"=>"dolar","cambio"=>0.96));
?>
<TABLE BORDER="1" CELLPADDING="2" CELLSPACING="2">
<TR ALIGN="center" BGCOLOR="yellow">
<TD></TD>
<TD>Moneda</TD>
<TD>Cambio €</TD>
</TR>
<?php
for($i=0;$i<2;$i++){
echo "<TR ALIGN='center'>";
echo "<TD BGCOLOR='yellow'>\$matriz1</TD>";
echo "<TD>".$matriz1[$i]['moneda']."</TD>";
echo "<TD>".$matriz1[$i]['cambio']."</TD>";
echo "</TR>";
}
for($i=0;$i<2;$i++){
echo "<TR ALIGN='center'>";
echo "<TD BGCOLOR='yellow'>\$matriz2</TD>";
echo "<TD>".$matriz2[$i]['moneda']."</TD>";
echo "<TD>".$matriz2[$i]['cambio']."</TD>";
echo "</TR>";
}
for($i=0;$i<2;$i++){
echo "<TR ALIGN='center'>";
echo "<TD BGCOLOR='yellow'>\$matriz3</TD>";
echo "<TD>".$matriz3[$i]['moneda']."</TD>";
echo "<TD>".$matriz3[$i]['cambio']."</TD>";
echo "</TR>";
}
?>
</TABLE>
</CENTER>
</BODY>
</HTML>
Como hemos visto en los ejemplos anteriores, una operación habitual a realizar cuando trabaja-
mos con arrays es recorrerlos para obtener sus elementos, para modificarlos o trabajar con ellos.
Una vez conocido el número de elementos del array, podemos utilizar un bucle para ir reco-
rriendo sus elementos, tal y como muestra el siguiente ejemplo, en el que nos permite recorrer un
array multidimensional:
<HTML>
<HEAD>
<TITLE>Trabajando con Matrices</TITLE>
</HEAD>
<BODY>
<CENTER>
<H2>Arrays función <I>count</I></H2>
<?php
$matriz1[0][0] = "peseta";
$matriz1[0][1] = 166.386;
$matriz1[1][0] = "dolar";
$matriz1[1][1] = 0.96;
$matriz1[2][0] = "marco";
$matriz1[2][1] = 1.85;
?>
<TABLE BORDER="1" CELLPADDING="2" CELLSPACING="2">
<TR ALIGN="center" BGCOLOR="yellow">
<TD></TD>
<TD>Moneda</TD>
<TD>Cambio 1€</TD>
</TR>
<?php
for($i=0;$i<count($matriz1);$i++){
echo "<TR ALIGN='center'>";
echo "<TD BGCOLOR='yellow'>\$matriz1[$i]</TD>";
for($j=0;$j<count($matriz1[$i]);$j++){
echo "<TD>".$matriz1[$i][$j]."</TD>";
}
echo "</TR>";
}
?>
</TABLE>
</CENTER>
</BODY>
</HTML>
Otra función relacionada con el recorrido de arrays es sizeof (), que obtiene el número de elemen-
tos del array pasado como argumento en la llamada a la función.
$matriz2['modelo']="cougar";
$matriz2['marca']="ford";
$matriz2['fecha']=null;
$matriz2['cc']="2.500";
$matriz2['motor']="V6";
$matriz2['potencia']=182;
?>
Como podemos observar en la siguiente imagen (Fig. 22.3), el recorrido del segundo array (en
orden inverso) se detiene en el instante en que se encuentra un elemento vacío, mientras que el
primero se muestra completamente.
• each (matriz) : Se usa para recorrer arrays (sobre todo los asociativos), pues devuelve un
par de valores correspondientes a la clave y al valor asociado a esa clave. Además, avanza
el puntero interno hasta el siguiente elemento. Si el puntero interno apunta a la última posi-
ción del array, la ejecución de esta función devuelve false.
• list ( ) : Asigna una lista de variables en una sola operación. Suele utilizarse en combina-
ción con la función anteriormente vista, each () .
El siguiente ejemplo muestra el recorrido por dos arravs no secuenciales haciendo uso de ambas
funciones:
<HTML>
<HEAD>
<TITLE>Trabajando con Matrices</TITLE>
</HEAD>
<BODY>
<CENTER>
<H2>Arrays funciones <I>each y list</I></H2>
<?php
$matriz1[3]="cougar";
$matriz1[5]="ford";
$matriz1[7]="2.500";
$matriz1[ ]="V6";
$matriz1[ ]=172;
$matriz2['modelo']="cougar";
$matriz2['marca']="ford";
$matriz2['fecha']=null;
$matriz2['cc']="2.500";
$matriz2['motor']="V6";
$matriz2['potencia']=182;
?>
<TABLE BORDER="0" CELLPADDING="4" CELLSPACING="6">
<TR ALIGN="center"><TD>
<TABLE BORDER="1" CELLPADDING="2" CELLSPACING="2">
<TR ALIGN="center" BGCOLOR="yellow">
<TD>Posición</TD><TD>Valor</TD></TR>
<?php
while(list($pos,$valor)=each($matriz1)){
echo "<TR ALIGN='center'><TD>".$pos."</TD>";
echo "<TD>".$valor."</TD></TR>";
}
?>
</TABLE></TD><TD>
Como podemos observar en la siguiente imagen (Fig. 22.4), el recorrido de ambos arrays es com-
pleto independientemente de que tengan elementos vacíos:
• array_keys (matriz) : Devuelve las claves que forman el array matriz. Admite un paráme-
tro opcional que nos permite seleccionar sólo las claves cuyo valor coincida con un patrón
dado.
• array_values (matriz) : Devuelve los valores que forman parte del array pasado como
parámetro.
Veremos a continuación varias funciones que PHP pone a nuestra disposición para poder ordenar
los elementos de un array, ya que es frecuente que necesitemos tener los elementos de un array
ordenados para después, por ejemplo, poder listarlos en orden alfabético.
Podemos comprobar el resultado de la ejecución del código anterior en la figura (Fig. 22.5).
Para evitar este efecto lateral en el que se redefinen los índices, tanto para los arravs escalares
corno asociativos, podemos usar las siguientes funciones:
• asort (matriz) : Ordena alfanuméricamente los valores de los elementos de un arrav de
mayor a menor, pero manteniendo la relación existente entre los índices y sus valores aso-
ciados. Esto es posible debido a que la ordenación se hace sobre los elementos del array y
no sobre los índices.
• arsort (matriz) : realiza la ordenación inversa.
<HTML>
<HEAD>
<TITLE>Trabajando con Matrices</TITLE>
</HEAD>
<BODY>
<CENTER>
<H2>Arrays funciones <I>asort y arsort</I></H2>
<?php
$matriz1[0]="Madrid";
$matriz1[1]="Zaragoza";
$matriz1[2]="Bilbao";
$matriz1[3]="Valencia";
$matriz1[4]="Lerida";
$matriz1[5]="Alicante";
?>
<TABLE BORDER="0" CELLPADDING="4" CELLSPACING="6">
<TR ALIGN="center"><TD>
<TABLE BORDER="1" CELLPADDING="2" CELLSPACING="2">
<TR ALIGN="center" BGCOLOR="yellow">
<TD>Posición</TD><TD>Valor</TD></TR>
<?php
asort($matriz1);
while(list($pos,$valor)=each($matriz1)){
echo "<TR ALIGN='center'><TD>".$pos."</TD>";
echo "<TD>".$valor."</TD></TR>";
}
?>
</TABLE></TD><TD>
<TABLE BORDER="1" CELLPADDING="2" CELLSPACING="2">
<TR ALIGN="center" BGCOLOR="yellow">
<TD>Posición</TD><TD>Valor</TD></TR>
<?php
arsort($matriz1);
while(list($pos,$valor)=each($matriz1)){
• ksort (matriz) : Ordena alfanuméricamente las claves de un array de menor a mayor man-
teniendo las correlaciones entre clave y valor asociado. La función que realiza la ordena-
ción inversa es krsort (matriz).
• usort (matriz, func_comparar) : Ordena los valores de un array según el criterio de la fun-
ción pasada por el usuario como argumento. La función hay que pasarla como una cadena
de caracteres, es decir, entre comillas (las funciones se verán en profundidad en un tema
posterior).
• uksort (matriz, func_comparar) : Ordena las claves de un array en base a una función
pasada por el usuario como argumento, manteniendo las correlaciones existentes entre
clave y valor asociado. La función de comparación debe devolver un entero menor, igual o
mayor que cero, si el primer argumento es, respectivamente, menor que, igual que o mayor
que el segundo. Si los dos argumentos resultan ser iguales, su orden en la matriz ordenada
será cualquiera.
• uasort (matriz, func_comparar) : Ordena los valores de un array según el criterio de la fun-
ción pasada por el usuario como argumento, manteniendo las correlaciones entre clave y
valor asociado.
Veremos a continuación un grupo de funciones que nos serán de gran utilidad a la hora de traba-
jar con un arras ya existente.
• compact ( ) : Esta función recibe como argumento una lista de variables que han sido pre-
viamente definidas, que pueden aparecer como cadenas de caracteres o como arrays y
devuelve un nuevo array en el que los índices son los nombres de las variables y el conte-
nido de los elementos del array son sus correspondientes valores.
Funciones
23.1 FUNCIONES
La mayor parte de las secciones del código de un script PHP deben ser ejecutadas tan pronto
como dicho script es interpretado pero, otras veces, es preferible que el código actúe después de
que se haya producido alguna acción específica o sólo si se dispara un evento. También es habi-
tual que partes del código se repitan un número indeterminado de veces durante la ejecución del
script PHP. Estas necesidades hacen que nazca la idea de dividir el código de un script en partes
menores, para que cada una de las cuales sirva a un propósito específico e individual.
Una función PHP es simplemente una sección separada de código a la que se le ha dado un nom-
bre (cualquier instrucción PHP válida puede aparecer en el cuerpo de la función, incluso la lla-
mada a otra función o la definición de clases). Utilizando este nombre, en un script se puede
llamar a esta sección de código tantas veces como se quiera y en los momentos en que se nece-
site. Por tanto, las funciones dividen las tareas que debe hacer un script, agrupando instrucciones
relacionadas para la ejecución de una tarea. Esta estructuración del código nos permite escribir
scripts más sencillos, legibles y fáciles de entender.
Las funciones pueden recibir valores desde las sentencias que las llaman. Estos valores se deno-
minan parámetros o argumentos y pueden devolver valores. Los parámetros, como veremos más
adelante, se usarán como variables locales dentro del bloque de sentencias que conforman la fun-
ción.
La palabra reservada function se utiliza para especificar un nombre, nombreFunción, el cual sirve
como identificador para el conjunto de sentencias comprendidas entre las llaves. Encerrados
entre paréntesis y separados por comas, se encuentran los nombres de los parámetros, que son
los que recibirán los valores con los que es llamada la función. Técnicamente, los argumentos
son variables que contienen informacion necesaria para que la función realice correctamente su
labor y que son pasados a ella en la sentencia de llamada. Aunque no se incluyan parámetros, en
la declaración de la función deben escribirse los paréntesis. Las sentencias, que conforman el
núcleo de la función, son ejecutadas cada vez que se llama a la función.
El siguiente ejemplo nos muestra de una forma sencilla cómo definir y llamar a una función.
Como podemos observar, se trata de una función declarada sin parámetros:
<HTML>
<HEAD>
<TITLE>Trabajando con Funciones</TITLE>
</HEAD>
<BODY>
<CENTER>
<H2>Funciones de Usuario<I></I></H2>
<?php
function cuentaAtras(){
for($i=10;$i>0;$i--)
echo $i,"...<BR>";
echo "¡ Booooom !";
}
?>
<TABLE BORDER="0" CELLPADDING="4" CELLSPACING="6">
<TR ALIGN="center">
<TD BGCOLOR="#FFBBAA">
<?php
cuentaAtras();
?>
</TD>
<TD BGCOLOR="#FFFBAD">
<?php
cuentaAtras();
?>
</TD>
</TR>
</TABLE>
</CENTER>
</BODY>
</HTML>
Otra forma de solucionar este problema es utilizar variables globales (las veremos en una
próxima sección del tema) que puedan ser modificadas tanto dentro, como fuera de la función.
Pero esto incrementa la confusión del código y su mantenimiento, pues se hace más difícil seguir
su comportamiento.
El siguiente ejemplo muestra una modificación de la función presente en el código anterior para
que el inicio de la cuenta pueda ser configurable por el usuario. Como podemos observar, los
parámetros se utilizan como variables dentro del cuerpo de la función:
<HTML>
<HEAD>
<TITLE>Trabajando con Funciones</TITLE>
</HEAD>
<BODY>
<CENTER>
<H2>Funciones de Usuario<I></I></H2>
<?php
function cuentaAtras($inicio){
for($i=$inicio;$i>0;$i--)
echo $i,"...<BR>";
echo "¡ Booooom !";
}
?>
<TABLE BORDER="0" CELLPADDING="4" CELLSPACING="6">
<TR ALIGN="center">
<TD BGCOLOR="#FFBBAA">
<?php
cuentaAtras(8);
?>
</TD>
<TD BGCOLOR="#FFFBAD">
<?php
cuentaAtras(5);
?>
</TD>
</TR>
</TABLE>
</CENTER>
</BODY>
</HTML>
Dado que en la llamada pasamos valores a la función, esta información puede suministrarse
mediante una lista de variables y/o constantes separadas por comas.
PHP permite pasar los parámetros de tres formas distintas: por valor (el comportamiento por
defecto que hemos visto en los ejemplos anteriores), por referencia y con parámetros por defecto.
Para indicar qué parámetros se pasan por referencia, hay que marcarlos en la definición de la fun-
ción, anteponiendo el símbolo ampersand (&) al nombre del parámetro.
Cuando se usan parámetros por defecto, éstos tienen que situarse los últimos en la declaración, es
decir, a la derecha de cualquier parámetro normal: de otra manera, las cosas no funcionarán de la
forma esperada. Cuando se utiliza el valor por defecto de un parámetro, obligatoriamente han de
utilizarse todos los valores por defecto de todos aquellos parámetros que se encuentren a su dere-
cha.
$mifinal=0;
echo $mensaje;
}
?>
<TABLE BORDER="0" CELLPADDING="4" CELLSPACING="6">
<TR ALIGN="center">
<TD BGCOLOR="#FFBBAA">
<?php
// $mifinal vale 0
cuentaAtras(6,$mifinal);
// $mifinal vale 2
?>
</TD>
<TD BGCOLOR="#FFFBAD">
<?php
// $mifinal vale 2
cuentaAtras(8,$mifinal,"¡ Despierta !");
// $mifinal vale 4
?>
</TD>
</TR>
</TABLE>
</CENTER>
</BODY>
</HTML>
Para poder hacerlo, se utiliza la palabra reservada return acompañada de una expresión. En el
instante en que aparece dentro del cuerpo de una función una sentencia con esta palabra reser-
vada, la función deja de ejecutarse para devolver el flujo de ejecución al punto del programa
donde se llamó a la función. Si después de return hay más líneas de código, dichas líneas no se
ejecutarán nunca; por eso, es habitual que aparezca como última instrucción del cuerpo de la fun-
ción.
PHP nos permite definir funciones en las que el número de parámetros no está fijado a priori, es
decir, en PHP se consiente que una función reciba como parámetro una lista de valores de longi-
tud variable. No se necesita de una sintaxis específica, pero su funcionamiento se basa en el
siguiente conjunto de funciones definidas en PHP:
• func_num_args ( ) : Devuelve el número de argumentos pasados a la función.
• func_get_args ( ) : Devuelve un array con los argumentos pasados a la función.
$elmayor=($dato1>$dato2)?$dato1:$dato2;
for($i=2;$i<$num_args;$i++)
$elmayor=($elmayor>$args[$i])?$elmayor:func_get_arg($i);
return $elmayor;
}
?>
<TABLE BORDER="0" CELLPADDING="4" CELLSPACING="6">
<TR ALIGN="center">
<TD BGCOLOR="#FFFBAD">
<?php
echo "El mayor de 17, 5, 22 y 19 es <BR><H2>".elMayor(17,5,22,19)."</
H2>";
?>
</TD>
</TR>
</TABLE>
</CENTER>
</BODY>
</HTML>
Son una herramienta muy útil de PHP que permite implementar, entre otras cosas, retrollamadas
(callbacks) y tablas de llamadas. Su funcionamiento es el siguiente: si una variable tiene unos
paréntesis añadidos al final, PHP buscará una función con el mismo nombre que el contenido de
la variable e intentará ejecutarla.
function aEuros($dato){
return sprintf("%02.2f",$dato/166.386);
}
function aDolares($dato){
return sprintf("%02.2f",$dato/195.6);
}
function aYens($dato){
return sprintf("%02.2f",$dato/206.36);
}
?>
<TABLE BORDER="1" CELLPADDING="2" CELLSPACING="2">
<TR ALIGN="center" BGCOLOR="YELLOW">
<TD>Pesetas</TD><TD>Euros</TD><TD>Dólares</TD><TD>Yens</TD>
</TR>
<?php
for($i=0;$i<sizeof($precios);$i++){
echo "<TR ALIGN='center'>";
echo "<TD>$precios[$i]</TD>";
for($j=0;$j<sizeof($array_func);$j++){
$funcion=$array_func[$j];
echo "<TD>".$funcion($precios[$i])."</TD>";
}
echo "</TR>";
}
?>
</TABLE>
</CENTER>
</BODY>
</HTML>
Se dice que una función es recursiva cuando en algún punto de su cuerpo se llama a sí misma.
Hay que tener cuidado al escribir una función recursiva, ya que puede ocurrir que se llame a sí
misma indefinidamente. Por tanto, es esencial asegurarse de implementar una forma adecuada de
terminar la recursión: es lo que se denomina como condición de parada.
La recursión nos vale para solucionar algunos problemas complejos; un ejemplo típico de recur-
sión es hallar el factorial de un número.
El siguiente ejemplo nos muestra cómo implementarlo en PHP (de forma recursiva y no recur-
siva):
<HTML>
<HEAD>
<TITLE>Trabajando con Funciones</TITLE>
</HEAD>
<BODY>
<CENTER>
<H2>Funciones de Usuario<I></I></H2>
<?php
function factorial($numero){
if ($numero==0) return 1;
return $numero * factorial($numero-1);
}
function factorial2($numero){
echo "$numero! = ";
for($factorial=1;$numero>1;$numero--){
$factorial*=$numero;
echo "$numero x ";
}
echo "1 = $factorial";
return $factorial;
}
?>
<TABLE BORDER="1" CELLPADDING="2" CELLSPACING="2">
<TR ALIGN="center" BGCOLOR="YELLOW">
<TD>F. Recursiva</TD>
<TD>Función No Recursiva</TD>
</TR>
<TR ALIGN="center">
<TD><?php echo factorial(2); ?></TD>
<TD><?php factorial2(2); ?></TD>
</TR>
<TR ALIGN="center">
<TD><?php echo factorial(3); ?></TD>
<TD><?php factorial2(3); ?></TD>
</TR>
<TR ALIGN="center">
<TD><?php echo factorial(4); ?></TD>
<TD><?php factorial2(4); ?></TD>
</TR>
<TR ALIGN="center">
<TD><?php echo factorial(5); ?></TD>
<TD><?php factorial2(5); ?></TD>
</TR>
</TABLE>
</CENTER>
</BODY>
</HTML>
24.1 INTRODUCCIÓN
Es muy importante en muchos problemas y aplicaciones llevar un control con la fecha y la hora
en un determinado momento, o bien, conocer la fecha para saber si tenemos que ejecutar un pro-
grama u otro...; existe un montón de circunstancias donde es necesario conocer estos datos. PHP
nos ofrece una gran variedad de funciones para abordar con mayor rapidez y de una forma más
sencilla los distintos problemas relacionados con el manejo de fechas y tiempos que nos puedan
ir saliendo a la hora de realizar nuestros programas.
En casi todos los sistemas informáticos hay una fecha de inicio común, a partir de la cual se
empieza a contar el tiempo. En el caso de los sistemas UNIX la fecha elegida como comienzo es
el día 1 de enero de 1970 a las 00:00:00 GMT, fecha que se conoce como el principio de la era
UNIX. El contador de tiempo se conoce como marca de tiempo (timestamp) y representa el
número de segundos transcurridos desde una fecha dada. En PHP todas las funciones de fecha/
hora que trabajan con marcas de tiempo hacen referencia a esta fecha.
• date (formato [ , timestamp] ) : Esta función nos permite darle un formato específico a una
cadena que contendrá una fecha y una hora. Acepta como parámetros una cadena de for-
mato y un parámetro timestamp; si éste se omite, se tomará el instante de ejecución de la
orden. Hay una serie de parámetros que tienen un significado propio y son reconocidos
dentro de la cadena de formato. Estos caracteres son:
Los caracteres distintos a los que aparecen en la tabla, que estén dentro de la cadena for-
mato, se imprimirán tal cual aparecen. Para que los caracteres utilizados en la cadena for-
mato se puedan imprimir, es necesario enmascararlos, es decir, deben ir precedidos del
carácter "V".
• getdate ( [timestamp]) : Esta función devuelve un array asociativo que contiene informa-
ción sobre la fecha y hora asociadas a la marca de tiempo, timestamp, pasada como pará-
metro. En caso de no pasar ningún parámetro a la función, ésta obtendrá la marca de
tiempo del instante en que se ejecuta. La estructura del array asociativo devuelto es la
siguiente:
• gettimeofday ( ) : Esta función obtiene la hora actual en un array asociativo, cuya estruc-
tura contiene los siguientes campos:
• gmdate ( format [, timestamp] ) : Esta función es muy parecida a la función date ( ) ante-
riormente vista, con una salvedad: la hora devuelta por esta función tiene formato GMT
(Greenwich Mean Time).
• gmmktime(hora, min, seg, mes, dia, anio [,is_dst]): Es muy parecida a la función mktime(),
a excepción de que los parámetros que se pasan en la llamada a la función representan la
fecha en formato GMT.
• gmstrftime (format, timestamp) : Da formato a una fecha/hora GMT según las convencio-
nes locales. Al igual que en las funciones anteriores, la fecha devuelta es la de GMT; por lo
demás, es muy parecida a la función strftime ( ).
• microtime (void) : Devuelve una cadena compuesta de dos elementos "msec sec". La
segunda parte, sec, representa los segundos transcurridos desde la fecha inicial de referen-
cia, es decir, el 1 de enero de 1970 a las 00:00:00, mientras que la primera parte, msec,
representa los microsegundos restantes. Ambas porciones se devuelven en unidades de
segundo.
• mktime (hora, min, seg, mes, dia, anio [ , isdst]) : Esta función devuelve la marca de
tiempo (el número de segundos transcurridos desde el 1 de enero de 1970 a las 00:00:00),
correspondiente a la fecha y hora pasadas a la función como parámetros. Esta función es
especialmente útil para realizar cálculos matemáticos con las fechas o validaciones de
ellas.
Es muy importante tener en cuenta que esta función posee la característica avanzada de
calcular la marca de tiempo para parámetros que estén fuera de rango: aproxima los datos
introducidos a la fecha más cercana correcta, es decir, cuando ejecutamos la función sobre
una fecha incorrecta, por ejemplo, "32 de marzo de 2001", obtendremos el valor de times-
tamp correspondiente al "1 de abril de 2002".
También hay que tener en cuenta que la función admite que el parámetro anio sea codifi-
cado como un valor de dos dígitos. En este caso, la función realiza la siguiente equipara-
ción automática de fechas: los valores comprendidos entre 0 y 69 se ajustan a los años
2000 a 2069 y los valores entre 70 y 99, a los años 1970 a 1999.
Existe una última aclaración de esta función consistente en que el último día de cada mes
puede indicarse como el día "0" del mes anterior.
• strftime (format [ , timestamp] ) : Esta función nos permite dar un formato específico de
hora y fecha a la marca de tiempo que se le pasa como parámetro. En caso de no propor-
cionar este parámetro, se tomará por defecto la marca de tiempo correspondiente al ins-
tante en que se ejecuta la función. Los formatos posibles a tener en cuenta se especifican
en la siguiente tabla:
• strtotime (cad_fecha [ , timestamp] ) : Esta función traduce una cadena que contiene un
texto en inglés que hace referencia a una fecha en su correspondiente marca de tiempo
relativa a la marca de tiempo dada en el parámetro opcional timestamp, o bien, a la marca
de tiempo actual, si este parámetro no se proporciona en la llamada a la función. Esta fun-
ción se comporta de acuerdo con la sintaxis de fechas de GNU; por tanto, se le pueden
pasar como argumento cadenas del tipo now, next Friday, +1 day, etc.
A través de un programa de ejemplo que mostrará un calendario con el mes deseado por el usua-
rio, vamos a ver la utilización habitual de las funciones de fecha y hora vistas en este capítulo.
El ejemplo consta de dos ficheros, uno primero de HTML que contiene un formulario en el que el
usuario podrá introducir el día, mes y año de una fecha en particular. El código de esta primera
página es el siguiente:
<HTML>
<HEAD>
<TITLE>Funciones de Fecha y Hora</TITLE>
<STYLE>
TABLE {font-family:Verdana;font:12px;}
INPUT {text-align:right;}
</STYLE>
</HEAD>
<BODY>
<CENTER>
<H2>Funciones de Fecha y Hora</H2><BR><HR>
<FORM METHOD="GET" ACTION="fechas1.php">
<TABLE CELLPADDING="0" CELLSPACING="0">
<TR BGCOLOR="YELLOW" ALIGN="CENTER"><TD>Dia</TD><TD>Mes</TD><TD>Año</TD></TR>
<TR>
<TD><INPUT TYPE="TEXT" NAME="dia" MAXLENGTH="2" SIZE="3"></TD>
<TD><INPUT TYPE="TEXT" NAME="mes" MAXLENGTH="2" SIZE="3"></TD>
<TD><INPUT TYPE="TEXT" NAME="anio" MAXLENGTH="4" SIZE="5"></TD>
</TR>
</TABLE><BR>
<INPUT TYPE="SUBMIT" VALUE="Obtener Calendario">
</FORM><HR>
<CODE>
<B>NOTA:</B>Cualquier dato no codificado
<BR>se tomará como el valor
<BR>correspondiente de la fecha actual
</CODE>
</CENTER>
</BODY>
</HTML>
El segundo fichero del ejemplo es el script, que se encarga de generar, a partir de la fecha dada en
el formulario, el calendario del mes que contiene dicha fecha (si el usuario no proporciona nin-
guna fecha, el programa asume la del día en curso).
<HTML>
<HEAD>
<TITLE>Funciones de Fecha y Hora</TITLE>
<style>
body {font: 12px Verdana;}
table {font: 12px Verdana;color:orange;text-align:right;}
tr.cabecera {background-color:#808080;color:#F8F8F8;font-weight:bold;}
tr.semana {background-color:#FFFBAD;color:#808080;font-weight:bold;}
a {text-decoration:none;color:orange;}
a.marcado {background-color:green;}
a.festivo {color:#B00000;}
a.opc {color:gray;font-weight:bold;}
p.error {font:14px;color:red;font-weight:bold;}
</style>
</HEAD>
<?php
$meses_txt=array("","Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio", "Agosto","Septiem-
bre","Octubre","Noviembre","Diciembre");
$dias_txt=array("L","M","X","J","V","S","D");
?>
<BODY>
<CENTER>
<H3>Funciones de Fecha y Hora</H3>
<?php
$hoy=getdate();
$dia=!empty($_GET['dia'])?$_GET['dia']:$hoy['mday'];
$mes=!empty($_GET['mes'])?$_GET['mes']:$hoy['mon'];
$anio=!empty($_GET['anio'])?$_GET['anio']:$hoy['year'];
if($anio<=99) $anio+=2000;
if(!checkdate($mes,$dia,$anio)||$anio<1971){
echo "<HR><P CLASS='error'>ERROR: La fecha introducida no es válida...</P>";
echo "<BR>< <A HREF='fechas1.html'>volver</A> ><HR>";
} else {
// obtenemos el día de la semana del primer día del mes
$primer_dia=actualiza_dia_semana(date("w",mktime(0,0,0,$mes,1,$anio)));
// obtenemos el último día del mes
$ultimo_dia=date("t",mktime(0,0,0,$mes,1,$anio));
$url = "fechas1.php?dia=$dia&mes=$mes&anio=".($anio+1);
echo "<A CLASS='opc' HREF='$url'>año+</A> >";
echo "<BR>< <A CLASS='opc' HREF='fechas1.html'>nueva fecha</A> ></PRE>";
}
?>
</CENTER>
</BODY>
</HTML>
Vamos a ver pormenorizadamente cada una de las acciones que realiza el código. Lo primero que
hacemos es recuperar la información enviada desde el cliente para procesarla. Del código del pri-
mer fichero HTML podemos observar que hemos elegido utilizar el método GET (se estudiarán
los formularios en capítulos posteriores):
Antes de pasar a validar la fecha, se hace una última comprobación con el año mandado por el
usuario; si éste se compone de dos dígitos solamente, se le complementa hasta cuatro sumándole
2000.
if($anio<=99) $anio+=2000;
Una vez que la fecha ha sido recuperada y completada, se valida a través de la función checkdate.
Además, se comprueba que el año proporcionado no sea inferior a 1970. Hay que tener en cuenta
que, aunque la fecha esté correctamente formada, si el año es anterior a 1970 (año de comienzo
de la era UNIX), todas las funciones que generan una marca de tiempo de tipo UNIX fallarían:
if(!checkdate($mes,$dia,$anio)||$anio<1971){
echo "<HR><P CLASS='error'>ERROR: La fecha NO valida</P>";
echo "<BR>< <A HREF='fechas1.html'>volver</A> ><HR>";
} else {
//tratamiento de la fecha correcta
Si la comprobación ha validado la fecha, pasamos a generar el calendario del mes que contiene
dicha fecha. Lo primero que hacemos es recuperar algunos datos esenciales para poder generar
correctamente el calendario.
• Día de la semana del primer día del mes (almacenado en la variable $primer_dia): para
ello, utilizamos las funciones date ( ) y mktime ( ) . Con esta última obtenemos la marca de
tiempo del primer día del mes de la fecha dada. Este valor se pasa a su vez como argu-
mento a la función date ( ) indicándole en la llamada, a través de la opción de formato "w",
que lo que deseamos obtener es el día de la semana. El valor devuelto varía entre 0 para el
domingo y 6 para el sábado. Comno dicho valor no coincide con la estructura de semana
que deseamos utilizar (el lunes comno primer día de la semana), llamamos a la función
actualiza_dia_semana ( ) , que se encarga de actualizarlo con nuestras preferencias.
$primer_dia=actualiza_dia_semana(date("w",mktime(0,0,0,$mes,1,$anio)));
• Número de días del mes (almacenado en la variable $ultimo_dia): para ello, utilizamos
también la misma combinación de funciones date ( ) y mktime ( ) que anteriormente, sólo
que esta vez solicitarmos a través de la opción de formato "t" una información diferente:
$ultimo_dia=date("t",mktime(0,0,0,$mes,1,$anio));
Una vez obtenidos estos valores, podemos generar el calendario del mes deseado. Para ello
vamos a utilizar una tabla en la que la primera fila corresponde a una columna que contiene el
nombre del mes y el año consignados en la fecha:
// escritura de la tabla que representa el calendario de un MES
echo "<TABLE BORDER='0' CELLPADDING='2' CELLSPACING='0' WIDTH='50%'>\n";
// escribir la cabecera que incluye el mes y el año del calendario
echo "<TR CLASS='cabecera'>";
echo "<TD COLSPAN='7'>",$meses_txt[$mes]," $anio</TD></TR>\n";
Cabe destacar que el array $meses_txt, del cual se obtiene el nombre del mes solicitado en caste-
llano, pues de las funciones proporcionadas por PHP sólo podemos obtener información textual
en inglés, tiene una primera posición vacía para hacer coincidir el número de mes proporcionado
por el usuario con su posición dentro del array.
meses_txt=array("","Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio",
"Agosto","Septiembre","Octubre","Noviembre","Diciembre");
Las siguientes filas están compuestas de siete columnas cada una: una por día. La primera de
estas filas contiene una etiqueta por cada uno de los días de la semana:
// escribir la cabecera que indica los días de la semana
echo "<TR CLASS='semana'>";
for ($i=0; $i<7; $i++)
echo "<TD>$dias_txt[$i]</TD>";
echo "</TR>\n<TR>";
A partir de aquí se completan las diferentes filas con cada una de las semanas que componen el
mes. Hay que tener en cuenta que en la primera y última de estas filas se pueden producir colum-
nas vacías, puesto que es habitual que un mes no comience en lunes, o bien, no acabe en
domingo. Por esto, el código que genera el calendario debe considerar si se produce esta circuns-
tancia.
25.1 INTRODUCCIÓN
En este capítulo vamos a ver cómo PHP procesa o gestiona la información que el cliente (el
navegador) envía, a través del uso de formularios, al servidor y cómo éste genera una respuesta
adecuada a la petición solicitada.
Aunque sabemos que PHP puede funcionar desde la línea de comandos, su uso principal está
relacionado con los sitios Web; de hecho, PHP puede ser definido como un servicio complemen-
tario a los proporcionados por los servidores Web. Estos servidores fundamentan su funciona-
miento en el uso del protocolo HTTP, del Protocolo de Transferencia de Hipertextos. Por ello,
para entender el funcionamiento de las técnicas que se proponen en este capítulo, se hace necesa-
rio un conocimiento previo del protocolo HTTP.
Éste es un sencillo protocolo cliente-servidor que articula los intercambios de información entre
los clientes los servidores web a través de operaciones simples de tipo solicitud/respuesta. Bási-
camente controla el modo en el que los clientes web solicitan recursos de los servidores web y el
modo en que éstos les envían dichos recursos de vuelta. Todos los recursos proporcionados por
un servidor web (documentos HTML, gráficos, videos, ficheros de sonido...) están asociados a
un URL o Localizador Uniforme de Recursos.
Las peticiones siempre cuentan con cabecera y, en algunas ocasiones, con cuerpo; sin embargo,
las respuestas en la mayoría de las ocasiones cuentan con ambos componentes. La estructura de
estos mensajes se puede resumir en la siguiente tabla:
Comandos HTTP
La primera línea de un mensaje de petición, el comando HTTP, tiene la siguiente estructura:
método_HTTP URL_recurso versión del_protocolo
A pesar de contar con todos los métodos enumerados en la tabla anterior, los más utilizados son
get, post y head, además de ser los más estándares. Algunos de los métodos restantes están en
desuso o tienen una utilización experimental.
Resultados de la petición
Ante cada petición, el servidor HTTP genera un mensaje de respuesta en el que inserta una pri-
mera línea denominada línea de estado en la que se informa sobre el resultado de la operación. El
formato de esta primera línea del mensáje es la siguiente:
Es decir, la versión empleada del protocolo HTTP, un código numérico de tres cifras que indica
el estado de la solicitud y un texto que contiene una breve descripción del código cíe estado
devuelto.
Existen cinco categorías de mensajes de estado, codificadas en función del primer dígito del
código; éstas son:
//$cabecera=getallheaders();
$cabecera=apache_request_headers();
echo "<TABLE BORDER='1' WIDTH='80%'><TR BGCOLOR='yellow'>";
echo "<TD>Campo</TD><TD>Contenido</TD></TR>";
foreach($cabecera as $campo => $contenido)
echo "<TR><TD>$campo</TD><TD>$contenido</TD></TR>";
echo "</TABLE>";
?>
</CENTER>
</BODY>
</HTML>
PHP también nos proporciona funciones para la gestión de las cabeceras; éstas son: header(),
para enviar cabeceras http, y headers_sent ( ) , para confirmar que las cabeceras han sido envia-
das correctamente. Su sintaxis es la siguiente:
header (cadena [, reemplazar[, http_reponse_code]])
headers_sent()
El primer parámetro opcional de la función header ( ), de carácter booleano, nos permite indicar
si la cabecera debe reemplazar a una cabecera similar previamente fijada o, por el contrario, debe
añadir una nueva cabecera del mismo tipo (el valor por defecto es true). El segundo parámetro
opcional, un valor entero, fuerza el código de respuesta que debe enviarse al procesar la solicitud.
El siguiente ejemplo nos permite indicar al navegador que el contenido de la información que se
le envía es de tipo XML:
<?php
header("Content-type: application/xml");
?>
<alumno>
<matricula>x0500</matricula>
<nombre>Jorge</nombre>
<apellidos>Tejedor Cerbel</apellidos>
<datos_personales>
<direccion tipo="calle">Hermosilla</direccion>
<num>9</num>
<piso>7</piso>
<puerta>A</puerta>
<provincia>Madrid</provincia>
<poblacion>Madrid</poblacion>
<codpostal>28005</codpostal>
</datos_personales>
<datos_academicos>
<asignatura>Sistemas Operativos</asignatura>
<estado>aprobada</estado>
<nota>9.0</nota>
</datos_academicos>
</alumno>
Corno se puede observar, de los ejemplos anteriores la función header ( ) debe aparecer antes de
que se genere cualquier tipo de contenido en el documento, puesto que va a definir un compo-
nente de las cabeceras HTTP del mensaje.
La variable global $_SERVER es un array asociativo que contiene, entre otras, toda la informa-
ción de las cabeceras tanto de petición como de respuesta.
<body>
<h1 align="center">Variable $_SERVER </h1>
<?php
echo "<table border='1' width='80%' cellpadding='2'>";
foreach($_SERVER as $clave=>$valor){
echo "<TR>";
echo "<TD> $clave </TD>";
echo "<TD> $valor </TD>";
echo "</TR><BR>";
}
echo "</table>";
?>
</body>
</html>
Un uso habitual de las cabeceras HTTP en conjunción con los campos PHP_AUTH_USER y
PHP_AUTH_PW de la variable $_SERVER nos permite realizar una autentificación básica de
usuarios para el acceso a recursos restringidos. El siguiente ejemplo muestra su funcionamiento:
<?php
if (!isset($_SERVER[PHP_AUTH_USER])) {
header('WWW-Authenticate: Basic realm="WebPHP"');
header('HTTP/1.0 401 Unauthorized');
echo '<CENTER><H2>Acceso restringido...</H2>';
echo '<HR>Es necesario contar con autorización para acceder a este recurso.<BR>';
echo '<BR>Póngase en contacto con el ';
echo '<A HREF="mailto:'.$_SERVER[SERVER_ADMIN].'">admninistrador</A><BR><HR>';
echo '</CENTER>';
exit;
} elseif (($_SERVER[PHP_AUTH_USER]!='cursoPHP')||($_SERVER[PHP_AUTH_PW]!='acceso')) {
header('WWW-Authenticate: Basic realm="WebPHP"');
header('HTTP/1.0 401 Unauthorized');
echo '<CENTER><H2>Acceso restringido...</H2>';
echo '<HR>Es necesario contar con autorización para acceder a este recurso.<BR>';
echo '<BR>Póngase en contacto con el ';
echo '<A HREF="mailto:'.$_SERVER[SERVER_ADMIN].'">admninistrador</A><BR><HR>';
echo '</CENTER>';
exit;
} //else {
// Acceso concedido...
// echo '<CENTER><H2>Acceso concedido...</H2></CENTER>';
// exit;
//}
?>
Esta primera sección pretende ser un resumen de los conceptos más importantes asociados a la
definición de formularios en HTML. Como ya sabemos (repasar tema XHTML), un formulario
HTML es una sección de un documento que contiene texto normal, etiquetas HTML y elementos
especiales llamados controles (casillas de verificación o checkboxes, radiobotones o radiobu-
ttons, menús desplegables, etc.) y rótulos (labels) asociados a estos controles.
El conjunto de datos del formulario que se envía al agente servidor es una secuencia de parejas
nombre_ de_ control /valor construida a partir de los elementos del formulario. Cada uno de los
controles tiene asociado un nombre que viene dado por su atributo name. De igual forma, cada
control tiene tanto un valor inicial, como un valor actual, que son ambos cadenas de caracteres.
En general (excepto en el caso del elemento textarea), el valor inicial de un control puede especi-
ficarse con el atributo value del elemento de control. El valor actual del control se iguala en un
primer momento al valor inicial y, a partir de ese momento, el valor actual del control puede ser
modificado a través de la interacción con el usuario y/o mediante scripts que se ejecuten en el
cliente. El valor inicial de un control no cambia. Así, cuando se reinicializa el formulario, el
valor actual de cada control se iguala a su valor inicial. Si el elemento de control no tiene un
valor inicial, se le asigna el valor nulo.
El método get debería usarse cuando el formulario es idempotente (es decir, cuando no tiene
efectos secundarios). Muchas búsquedas en bases de datos no tienen efectos secundarios visibles
y constituyen aplicaciones ideales del método get. Si el servicio asociado con el procesamiento
de un formulario causa efectos secundarios (por ejemplo, si el formulario modifica una base de
datos o la suscripción a un servicio), debería usarse el método post.
PHP, a través de un conjunto de variables globales, es capaz de recuperar el conjunto de datos del
formulario que han sido enviados desde el cliente (esto es, el navegador) para, después, poder
trabajar con ellos. Las tres variables principales para realizar esta operación son:
El script encargado de procesar dicha información (valor del atributo action del formulario) es el
siguiente:
<HTML>
<HEAD>
<TITLE>Formularios</TITLE>
</HEAD>
<BODY>
<CENTER>
<?php
$metodo=$_SERVER['REQUEST_METHOD'];
$cad_consulta=$_SERVER['QUERY_STRING'];
Ejercicio. Realizar el ejemplo anterior utilizando el método POST. ¿Qué diferencias se pro-
ducen?.
arrays y, como tales, recorrerlos para obtener sus claves y respectivos valores. Esta característica
también se puede usar para recuperar los valores de un campo select de tipo múltiple.
Como podemos ver en el formulario, se definen dos variables de tipo array (una de ellas de tipo
asociativo).
</CENTER>
</BODY>
</HTML>
Ejercicio. Realizar el ejemplo anterior utilizando un único fichero. Consultar libro de texto.
Como comentarnos anteriormente, el protocolo HTTP está definido de forma que nunca se alma-
cena información acerca de las conexiones y desconexiones que haya habido entre cliente y ser-
vidor, es un protocolo stateless. Por tanto, cuando necesitarnos que algún dato o información de
relevancia (preferencias del usuario, número de accesos, recursos visitados...) esté disponible
entre diferentes conexiones, es necesario implementar un mecanismo que nos permita almacenar
y acceder a dicha información. Para llevar a cabo dicha facilidad, tenernos varias soluciones
posibles:
• Hacer uso de elementos de formularios ocultos. Efectivamente, si enviamos esta informa-
ción en campos ocultos de un formulario (elementos input de tipo hidden), podremos
manejarlos entre las diferentes páginas de nuestra aplicación y arrastrar esa información de
una página a otra. El problema principal que presenta esta posible solución es que los datos
tendrán vigencia, existirán, mientras el cliente esté navegando y, además, lo haga de una
manera ordenada, esto es, siga la secuencia de páginas prevista en la aplicación.
• Almacenar la información en el servidor. Esta solución nos permite que, si el usuario deja
de navegar, cuando retome el uso de nuestra aplicación Web, sus datos los tendremos dis-
ponibles. El único problema de esta solución está en el hecho de que un número muy
grande de usuarios supone, por parte del servidor, la reserva de gran cantidad de recursos
de almacenamiento, por tanto, es una solución válida cuando el número de posibles usua-
rios de nuestra aplicación Web no vaya a ser alto.
• Almacenar la información en los equipos clientes. Esta solución es la más utilizada en las
aplicaciones Web puesto que el almacenamiento se realiza en los equipos clientes y el ser-
vidor no debe preocuparse por la reserva de recursos. Además, se potencia la distribución
natural de la información. El problema principal que presenta es el de la integridad de la
información, puesto que el servidor no puede asegurar que los datos almacenados (supues-
tamente) en el equipo cliente están disponibles en el instante en que son requeridos. A
estas estructuras de información que se almacenan en el equipo cliente se las denomina
cookies.
nan y resto de características propias de una operación de lectura/escritura sobre disco dependen
en gran manera del sistema operativo y del navegador que tenga instalado el equipo cliente. De
igual forma, la posibilidad de hacer uso de cookies depende de que el software utilizado para
acceder a la aplicación Web (normalmente un navegador) cuente con esta característica y que,
además, esté habilitada.
La siguiente tabla (Tabla 25.9) nos muestra la estructura básica de una cookie:
Es muy importante tener en cuenta que todo el tratamiento de las cookies se realiza en la cabe-
cera del mensaje HTTP y, por tanto, deben ser manejadas antes de que se envíe cualquier otra
información al navegador (la parte del cuerpo del mensaje HTTP); en caso contrario, obtendre-
mos un error.
Por otra parte, el valor de una cookie tiene preferencia sobre los valores pasados mediante un for-
mulario, es decir, cuando un formulario y una cookie hacen uso de los mismos identificadores,
los valores de las cookies sobrescribirán los valores de las entradas del formulario.
Para acceder al contenido, se hará uso de una variable global, tal y como veremos más adelante.
Creación de cookies
Corno se puede observar en la definición de la función setcookie ( ), cada uno de los parámetros
coincide con los elementos que componen la estructura básica de una cookie. También vemos
que el único argumento obligatorio en la llamada a la función es el nombre que se le asigna a la
cookie. Sin embargo, en el caso de la creación es necesario, al menos, que se le asigne un valor
inicial.
Cuando no queramos hacer uso de los parámetros de tipo string, se deben reemplazar con la
cadena vacía (““) y los de tipo int, con un valor 0. Si no usamos el parámetro caducidad, se
tomará por defecto el tiempo que dure la sesión de trabajo activa en el navegador. De igual modo,
si no se utilizan los parámetros ruta y dominio, se tomarán por defecto el camino y el dominio del
servidor en los cuales se ha creado la cookie.
Eliminación de cookies
Como ya sabernos, para borrar una cookie, usamos la misma función que para crearla:
setcookie ( )
sólo que en este caso la llamada a la función sólo contendrá como parámetro el nombre de la coo-
kie que deseamos eliminar del sistema.
setcookie(“nombre_de_la_cookie”);
Consulta de contenidos
Para poder acceder a los contenidos de las cookies, PHP proporciona una variable global consis-
tente en un array asociativo formado por todas las variables pasadas a través de las cookies. Es la
variable $_COOKIE:
$_COOKIE["nombre_ de la cookie"]
Una vez que conocemos los tres pasos esenciales para trabajar con cookies, vamos a ver un ejem-
plo que hace uso de esta técnica para implementar un contador de accesos. Nuestro primer script
contendrá la creación y actualización de la cookie:
<?php
$accesos=1;
if(isset($_COOKIE["num_accesos"])){
$accesos=$_COOKIE["num_accesos"]+1;
}
setcookie("num_accesos",$accesos,time()+3600);
?>
<HTML>
<HEAD>
<TITLE>Trabajando con Cookies</TITLE>
</HEAD>
<BODY>
<CENTER>
<H2>Trabajando con cookies</H2><br>
<H3>Contador de accesos</H3>
<?php
if($accesos>1)
echo "Has accedido a esta página <B>$accesos</B> veces";
else
echo "Es la primera vez que accedes a esta página";
?>
<BR><BR><BR>
<PRE><A HREF="cookies1.php">Actualizar</A> | <A HREF="cookies2.php">Eliminar</A></PRE>
</CENTER>
</BODY>
</HTML>
Corno podernos observar, la cookie creada, num_accesos, tiene un tiempo de expiración de una
hora (3.600 segundos). El segundo script contiene la eliminación de la cookie creada para alber-
gar el contador:
<?php
setcookie("num_accesos");
?>
<HTML>
<HEAD>
<TITLE>Trabajando con Cookies</TITLE>
</HEAD>
<BODY>
<CENTER>
<H2>Trabajando con cookies</H2><br>
<H3>Contador de accesos borrado</H3>
<BR><BR><BR>
<PRE><A HREF="cookies1.php">volver</A></PRE>
</CENTER>
</BODY>
</HTML>
Ejercicio. Realizar el ejercicio de la pag. 145 del libro de texto (cookies con múltiples valo-
res).
A lo largo de este tema hemos visto que teníamos tres formas básicas de hacer que la información
generada en un script estuviera disponible en scripts diferentes al de creación: utilizando formu-
larios, pasando las variables y sus valores a través de la URL, o bien, definiendo cookies. Estos
métodos no son todo lo útiles que desearíamos cuando los scripts que deben compartir la infor-
mación no se ejecutan secuencialmente, o bien, están distantes los unos de los otros dentro del
flujo de ejecución normal de nuestra aplicación. Aunque, a priori, el uso de cookies parece ade-
cuado para solventar este problema (pueden ser consultadas en cualquier momento hasta su eli-
minación del sistema de cliente), hay que tener en cuenta que no todos los navegadores tienen
disponible esta funcionalidad y que, incluso teniéndola, ésta puede aparecer deshabilitada por
parte del usuario.
Para solventar esta situación, PHP proporciona las variables de sesión, que son variables que
estarán disponibles en las diferentes peticiones a lo largo del intervalo de tiempo que el usuario
necesite para hacer uso de nuestra aplicación. Son algo así como variables globales a la aplica-
ción entera pues van a estar accesibles para todos los programas de la aplicación. El ciclo de vida
de una sesión comienza en el instante en que el usuario se conecta a nuestra aplicación y acaba en
el instante en que sale de la aplicación, cierra el navegador, o bien, permanece un lapso de tiempo
(fijado por el sistema) sin interaccionar con la aplicación.
Todas las variables de sesión se almacenan en el servidor, por tanto, en un momento dado, podre-
mos tener muchas variables con el mismo nombre pero con contenidos diferentes. Para evitar
confusiones, cada variable de sesión está vinculada a una única sesión/usuario, que se identifica
con un identificador de sesión único. El modo de mantener de forma persistente este identifica-
tivo a lo largo de la sesión es utilizar cookies, o bien, propagarlo a través de la URL.
El modo principal de activar el uso de sesiones cuando lo deseemos es hacer uso de la función
sessionstart ( ) cuya sintaxis es la siguiente:
bool session_start()
Esta función crea una nueva sesión y genera el nuevo identificador, o retorna la sesión en caso de
que existiera, utilizando el identificador de sesión que se había propagado haciendo uso de la
URL o de cookies.
Si se está haciendo uso de sesiones basadas en cookies, la función session_start( ) debe ser
llamada al principio de nuestro script (antes de abrir cualquier etiqueta o de imprimir cual-
quier contenido). En caso contrario, se genera un error.
Como hemos dicho anteriormente, en el instante en que se crea una sesión, se genera un identifi-
cador único para ella. Haciendo uso de la función session_id ( ) , podemos recuperar o modificar
dicho valor. Su sintaxis es la siguiente:
Si llamarnos a la función sin hacer uso del parámetro id, obtendremos una cadena con el identifi-
cador de la sesión actual (debe ser llamada una vez que exista la sesión). Si, por el contrario,
hacemos uso del citado parámetro, estaremos reemplazando el identificativo de la sesión actual
por el valor dado al parámetro (debe ser llamada antes de crear la sesión).
También es posible identificar a las sesiones asignándoles un nombre específico. Para ello, utili-
zaremos la función session_name ( ) que tiene la siguiente sintaxis:
Si no hacemos uso del parámetro nombre, obtendremos el nombre de la sesión actual; si, por el
contrario, proporcionamos dicho parámero, la sesión actual pasará a tener por nombre el argu-
mento pasado.
siguiente ejemplo muestra la creación de una sesión y de una variable de sesión al igual que su
acceso, actualización y eliminación para poder obtener un contador de accesos:
<?php
session_start();
if (isset($_SESSION['contador'])) {
$_SESSION['contador']++;
}
else {
$_SESSION['contador'] = 0;
}
$nombre_anterior = session_name('SESION_CONTADOR');
?>
<HTML>
<HEAD>
<TITLE>Trabajando con Sesiones</TITLE>
</HEAD>
<BODY>
<CENTER>
<H2>Trabajando con Sesiones</H2>
<TABLE BORDER="1" CELLPADDING="2" CELLSPACING="4">
<TR ALIGN="center" BGCOLOR="yellow">
<TD COLSPAN="2"><B>Información de la Sesión</B></TD>
</TR>
<TR>
<TD BGCOLOR="yellow">ID</TD>
<TD><?php echo session_id() ?></TD>
</TR>
<TR>
<TD BGCOLOR="yellow">Número de accesos</TD>
<TD><?php echo $_SESSION['contador'] ?></TD>
</TR>
<TR>
<TD BGCOLOR="yellow">Nombre actual</TD>
<TD><?php echo session_name() ?></TD>
</TR>
<TR>
<TD BGCOLOR="yellow">Nombre anterior</TD>
<TD><?php echo $nombre_anterior ?></TD>
</TR>
</TABLE>
<BR><PRE>
<A HREF="sesiones1.php">Actualizar</A> | <A HREF="sesiones2.php">Resetear contador</A>
</PRE>
</CENTER>
</BODY>
</HTML>
Como podemos observar, para crear una nueva variable de sesión, sólo hay que definirla dentro
del array $_SESSION. En el código se pregunta si la variable de sesión tiene valor (si está defi-
nida) y, de este modo, saber si hay que crearla o actualizar su valor. El ejemplo, además, obtiene
el identificador de sesión y modifica el nombre asignado por defecto. La siguiente imagen mues-
tra el resultado después de haber realizado 10 accesos a la página que contiene el contador:
El segundo script de este ejemplo se encarga de borrar la variable de sesión creada en el script
anterior.
<?php
session_start();
unset($_SESSION['contador']);
?>
<HTML>
<HEAD>
<TITLE>Trabajando con Sesiones</TITLE>
</HEAD>
<BODY>
<CENTER>
<H2>Trabajando con Sesiones</H2><BR><BR>
<P>Variable <B>'contador'</B> actualizada<BR>
de la sesión <B><?php echo session_id() ?></B><BR>
con nombre <B><?php echo session_name() ?></B>
<BR><BR><A HREF="sesiones1.php">volver</A></P>
</CENTER>
</BODY>
</HTML>
Ficheros y directorios
26.1 INTRODUCCIÓN
Como es bien sabido, la información que se necesita guardar de manera permanente está almace-
nada en ficheros. Por esto, es bastante habitual que las aplicaciones, sean del tipo y del entorno
que sean, necesiten realizar operaciones con ficheros del sistema local. Por ejemplo, poner un
simple contador de visitas en una página nos obliga a guardar en un fichero el total de visitas
recibidas para que, cuando llegue la siguiente, abramos el fichero, leamos el número que con-
tiene y lo modifiquemos convenientemente.
Para poder implementar este tipo de tareas, PHP dispone de funciones predefinidas para la utili-
zación y manejo de ficheros. Gracias a estas funciones, podremos acceder a un fichero que poda-
mos haber creado previamente, podremos consultar los datos que contenga, añadir otros,
modificarlos, o bien, borrarlos.
PHP nos provee de funciones que nos permiten realizar operaciones típicas de ficheros: abrir,
cerrar, leer, escribir, recorrer...
Para poder abrir un fichero, disponemos de la función fopen ( ) . PHP nos permite abrir ficheros
locales o remotos. Que el fichero esté en el disco duro de nuestra máquina o en otra dependerá de
cómo esté formado el parámetro nombre: si éste comienza por http: // o ftp: //, indicará que es un
fichero remoto y que se accederá a él vía el protocolo correspondiente. En caso contrario, se tra-
26.2 FICHEROS Y DIRECTORIOS
tará de un fichero que PHP buscará en el sistema de ficheros del servidor, razón por la cual habrá
que tener atención a la hora de indicar el camino o ruta de acceso al archivo deseado.
El segundo parámetro (modoApertura) puede tener los siguientes valores expresados en la tabla
siguiente:
La función fopen ( ) devuelve un descriptor de fichero, esto es, el canal por el que vamos a poder
acceder a él; por tanto, los descriptores serán imprescindibles a la hora de realizar operaciones
sobre ficheros tales como lectura, escritura, cerrado, etc. De aquí deducimos que usaremos, tan-
tas variables que almacenen descriptores, como ficheros abiertos simultáneamente vayamos a
necesitar.
En el caso de que el fichero no se pudiera abrir por la causa que sea, fopen ( ) devolverá FALSE.
Característica por la cual la forma más habitual de abrir un fichero es:
<?php
if (! $descriptor = fopen ("un_fichero_cualquiera", "r")) {
echo "*** ERROR: el fichero no se puede abrir. <br>";
} else {
echo "podemos acceder al fichero a través de '\$descriptor'. <br>"); }
Con la función fclose ( ) cerramos el fichero que está referenciado por el descriptor que pasamos
como argumento. Por supuesto, este descriptor es el devuelto por la función fopen ( ) vista ante-
Dado que un fichero abierto consume recursos del sistema, es conveniente cerrar todo aquél que
se prevea que no se va a usar más. De todas formas, en el caso de que no se cierre expresamente
un fichero, PHP lo hará automáticamente al terminar de ejecutar el script.
En general, dado que son muy lentas todas las operaciones en las que está implicado un acceso al
sistema de ficheros (al disco duro, para ser más exactos), se recurre a la escritura mediante
buffers para hacerlas más eficaces. Esto quiere decir que la escritura no se hace efectiva en el
fichero hasta que no se llena esta memoria intermedia. Por defecto, el buffer de escritura de PHP
tiene un tamaño de 8 Kb, pero, si en algún momento necesitáramos cambiar esta cifra por otra,
podríamos hacerlo con la función set_file_buffer ( ) :
set_file_buffer (descript, buffer_tamaño);
• is_executable (fichero): Devuelve verdadero si el nombre del fichero pasado como argu-
mento tiene permisos de ejecución (Unix) o es un fichero ejecutable (extensión exe, com o
bat).
• is readable (fichero): Devuelve verdadero si el fichero tiene permiso de lectura. Si no tiene
dicho permiso o no existe, devuelve FALSE.
• is_writeable (fichero): Devuelve verdadero si el fichero tiene permiso de escritura. Si no
tiene dicho permiso o no existe, devuelve FALSE.
• filemtime (fichero): Devuelve el instante (timestamp) de la última modificación hecha
sobre el contenido del fichero.
• filesize (fichero): Devuelve un número entero que indica el tamaño en bytes del fichero
pasado como parámetro. En caso de error, devuelve FALSE.
Con los ficheros podemos realizar operaciones para simplificar nuestros programas cuando utili-
zamos ficheros. Veamos algunas de estas operaciones:
• copy (origen, destino): Copia un fichero destino. Si no ha habido ningún error, devuelve
TRUE.
• rename (nom_original, nom_final) : Cambia el nombre a un fichero o directorio.
• unlink (nom_fichero) : Borra un fichero.
• link (fich_original, fich_enlazado): Crea un enlace duro (válido sólo en Unix).
• tempnam (directorio, prefijo): Crea un fichero único (no existente) en el directorio que se
le indica como primer parámetro. Si el directorio no existiese o fuese la cadena vacía, el
fichero se creará en el directorio temporal del sistema. El nombre generado empezará por
lo que se pase como segundo parámetro. Devuelve el nombre del fichero creado. Es muy
útil cuando necesitamos crear ficheros auxiliares en entornos multiusuario.
• touch (fichero [, instante]) : Modifica las fechas de último acceso y modificación del
fichero. Por defecto, esto es, sin el segundo parámetro, toma la fecha actual. Si no existe el
fichero, lo crea.
Al igual que tenemos funciones específicas para ficheros, también tenemos a nuestra disposición
una serie de funciones predefinidas para el manejo y utilización de directorios. Con ellas podre-
mos crear, borrar, leer las entradas que tiene un directorio, averiguar en qué directorio nos encon-
trarnos, cambiarnos a otro, etc.
• opendir (nombre) : Abre el directorio pasado como parámetro. Devuelve un descriptor de
directorio.
Ejercicio: Realizar un navegador de archivos que nos permita movernos por la estructura de
directorios del disco duro del servidor.
Dado que la operación de crear un directorio es atómica en cualquier sistema operativo, pues así
se garantiza la consistencia de la estructura de árbol de un sistema de ficheros, podemos crear
una región crítica haciendo uso de las funciones de creación y borrado de directorios, esto es,
podemos garantizar el acceso ordenado de múltiples procesos a un recurso compartido.
Este mecanismo se basa en el uso de semáforos: para que un proceso pueda acceder a un recurso,
necesita previamente consultar si tiene permiso. Esta autorización se implementa de manera muy
sencilla: si existe un directorio (de nombre convenido previamente), significará que hay otro pro-
ceso haciendo uso del recurso; en caso contrario, creará el directorio y accederá a dicho recurso.
Una vez satisfechas las necesidades de uso del recurso, borrará el directorio.
Ejercicio: Realizar un programa de acceso a un formulario que garantice que sólo un usua-
rio se encuentra introduciendo datos.
En este apartado incluirnos, a modo de miscelánea, funciones que de alguna manera están rela-
cionadas con los ficheros:
• basename (ruta) : Ésta no es una operación de ficheros propiamente dicha, sino, más bien,
de cadenas de caracteres ya que tanto lo que pasarnos a la función, como lo que obtenemos
de ella, es un string: dada una cadena de caracteres que definen una ruta o posición de un
fichero en el disco duro (separados los directorios por el carácter " /" o "\"), basename ( )
nos devuelve los caracteres que están después del último carácter que usamos como sepa-
rador. Por ejemplo, si le aplicamos esta función a la cadena /hola/que/tal, obtendremos tal.
• dirname (ruta) : Hace el inverso de la función basename ( ) , es decir, devuelve la ruta de
directorios y subdirectorios donde está ubicado el fichero: los directorios por los que hay
que pasar para encontrarlo; aplicado a "/hola/que/tal", obtendremos "/hola/que".
• disk_free_space (dir) : Esta función toma una ruta a un directorio y devuelve el espacio
libre en octetos (bytes) disponibles en el sistema de ficheros que contiene al directorio.
• disk_total_space (dir) : Toma una ruta a un directorio y devuelve el tamaño del sistema de
ficheros donde está situado dicho directorio.
Por último, las operaciones en las que están involucrados ficheros que nos quedan por ver son
aquéllas en que el cliente le envía un fichero al servidor y a la inversa: el servidor le envía un
fichero al cliente.
El problema de subir ficheros al servidor se divide en dos escenarios: uno es la página HTML
donde el usuario indicará (a través de etiquetas) qué fichero de su disco local quiere subir; el otro
se encuentra en la parte programática: gracias a la página HTML (en realidad, gracias al proto-
colo HTTP), el fichero ya ha sido transferido al servidor y ahora lo que tenemos que hacer es
poder acceder a él para realizar las tareas que consideremos oportunas.
En la página HTML sólo necesitamos dos etiquetas: la etiqueta <input> (en realidad, tantas
como ficheros queramos subir), gracias a la cual el navegador mostrará una cajita, y un botón de
navegación (broivsing), para que el usuario seleccione el fichero deseado:
<input file='file' name=' nombre_fichero_a_subir'>
La segunda etiqueta necesaria es la que nos permite construir un formulario (<form>), pero con
una serie de cláusulas adicionales:
form action="subir_fich.php" method="post" enctype="multipart/form-data">
Es decir, tenemos que indicar que el método de transferencia de los datos del formulario es
mediante POST (viajan junto a la página), y que viajarán codificados como multipart/form-data.
Opcionalmente, se puede expresar el tamaño máximo que podrá tener un fichero para poder ser
enviado con un campo de datos oculto (tendríamos entonces tres etiquetas) al que hay que identi-
ficarlo como max_file_size (si no se indica, se tomará la directiva upload_max_filesize, comen-
tada más abajo). Por ejemplo, limitamos el tamaño máximo a 1.000 caracteres:
<input type='hidden' name='max_file_size' value='1000'>
Veamos un sencillo ejemplo de página HTML desde la que se podría enviar un mensaje junto con
un fichero adjunto:
<HTML>
<HEAD>
<TITLE> subir ficheros </TITLE>
</HEAD>
<BODY>
<h2>Componer Mensaje</h2>
<FORM method='post' action='subir_fich.php'
enctype='multipart/form-data'>
<INPUT type='hidden' name='max_file_size' value='250000'>
Para poder trabajar con los ficheros así transmitidos, PHP nos proporciona el array asociativo
$_FILES. Este array tiene dos dimensiones: en la primera columna se indican los ficheros que
han sido subidos usando como claves los identificadores que usamos en la etiqueta <input>,
mientras que las claves de la segunda columna se corresponderán con las características de cada
fichero:
También disponemos de un par de funciones que son muy útiles para trabajar con estos ficheros.
Una nos vale para saber si el fichero ha sido subido:
• is_uploaded_file($_FILES[' identif_fich']['tmp_name'1)
• move_uploaded_file(nom_fich_original, destino) nos sirve para renombrar o mover el
fichero temporal a otro que será permanente.
Veamos un ejemplo de cuál sería el programa que trataría los datos introducidos en la página
HTML anterior:
<?
foreach ($_FILES['f_adjunto'] as $clave => $valor)
echo "\$_FILES[$clave]: ($valor)<br>";
if (!is_uploaded_file($_FILES['f_adjunto']['tmp_name']))
{
$error=$_FILES['f_adjunto']['error'];
die("<h3>** ERROR: fichero no transferido: $error </h3>");
}
if ($_FILES['f_adjunto']['type'] != 'application/x-zip-compressed')
echo "<h3>** ERROR: el fichero enviado no está comprimido</h3>";
?>
Hemos visto que, por defecto, la salida generada por cualquiera de las funciones readfile ( ) ,
fpassthru ( ) , echo ( ) , print ( ) , etc., se envía directamente a la salida estándar, es decir, la recibe
directamente el cliente. Por ello, el resultado de estas funciones no podemos asignarlo a una
variable o pasarlo como parámetro a otra.
PHP nos ofrece toda una familia de funciones para poder controlar todo aquello que se dirige a la
salida estándar. En la práctica, lo que hacen es trabajar con el contenido de una serie de memorias
intermedias (buffers):
• ob_start ( ) : Activa el almacenamiento en memoria intermedia, por lo tanto, cualquier
texto enviado a la salida estándar no llegará al navegador del cliente.
• ob_end_flush ( ) : Envía el contenido del buffer a la salida estándar y luego lo vacía. Ade-
más, da por terminado el almacenamiento intermedio.
• ob_end_clean ( ) : Borra el contenido del buffer y da por terminado el buffering.
• ob_get_contents ( ) : Devuelve el contenido de la memoria intermedia.
Bases de datos
27.1 INTRODUCCIÓN
Puede parecer extraño decir que Internet no sería lo que es actualmente si no fuera por la existen-
cia de las bases de datos. De hecho, el propio PHP probablemene no seria tan popular o útil si no
fuera por su soporte integrado de numerosos tipos de bases de datos. (Como regla general, el
soporte de bases de datos por parte de PHP y su facilidad de uso son cosas que no encontraremos
utilizando scripts CGI.
Una base de datos es una colección de tablas (una tabla está a su vez compuesta por filas y
columnas) que almacenan información. Las bases de datos se utilizan por todo Internet. Los
sitios de comercio electrónico utilizan bases de datos para almacenar las especificaciones de los
productos (como su precio y color, por ejemplo), así como los datos de los clientes, mientras que
los sitios de contenido colocan artículos y noticias en la base de datos.
En cualquier sistema operativo, Oracle está considerado como el mejor DBMS, pero su precio lo
coloca fuera del alcance de la mayoría y se utiliza fundamentalmente para grandes aplicaciones
corporativas y con buena financiación. En el caso de Microsoft se suele recurrir a Access y SQL
Server; ambos sistemas muy útiles pero incompaibles con la plataforma cruzada.
Durante esta parte del curso usaremos MySQL como ejemplo de DBMS. Aunque MySQL, el
cual está disponible para la mayoría de las plataformas, no es tan potente como otros servidores
de bases de datos, tiene la suficiente velocidad y funcionalidad como para ser usado en muchísi-
27.2 BASES DE DATOS
mos proyectos (algunos de gran envergadura) y su precio (gratuito) lo convierten en una de las
opciones mas comunes para el desarrollo web.
Este tema se estudiará en su totalidad haciendo uso del libro de texto. Para ello es necesario cen-
trarse en los siguientes temas:
• Tema 9: Introducción a las bases de datos y SQL. En este tema se hace un rápido repaso al
diseño de bases de datos, configuración e instalación de MySQL y al propio lenguaje de
consultas SQL.
• Tema 10: Recuperar datos de MySQL mediante PHP. En este tema se estudian los meca-
nismos que proporciona PHP para acceder a los datos almacenados en una base de datos
MySQL.
• Tema 11: Utilizar PHP para manipular datos en MySQL. A lo largo del tema se estudia
comorealizar modificaciones en los datos a través de PHP.
En el curso virtual, se le indicarán diversos ejercicios para que practique los conocimientos
adquiridos.
PHP Avanzado
Una vez vistos los conceptos generales de programación con PHP es necesario abordar una serie
de tecnologías que corresponden a técnicas avanzadas de programación. Dichas técnicas de
programación son especialmente útiles cuando los proyectos de desarrollo involucran un
conjunto elevado de personas que tienen distintas responsabilidades. Habitualmente se emplean
tres tipos de perfiles en el desarrollo de aplicaciones web: analistas, programadores y diseñadores
multimedia. Los analistas se encargan de realizar el diseño lógico de la aplicación, indicando
cuales son las funcionalidades requeridas y dando unas estructuras a los programadores para que
puedan implementar las funcionalidades requeridas. Los programadores emplean las estructuras
(habitualmente compuestas por diagramas con una notación que deben comprender) para escribir
el código necesario que desarrolla las funciones descritas para la aplicación web. De otra parte,
los diseñadores multimedia (en otras referencias, se les denomina diseñadores Web) se encargan
de realizar el aspecto gráfico que la aplicación web mediante el uso de lenguajes como XHTML
o DHTML, más los recursos multimedia que consideren necesarios. Teniendo en cuenta lo
anterior, se puede concluir:
1 Debe existir una coordinación entre los distintos roles para asegurar la productividad del
equipo de desarrollo y facilitar la consecución de los objetivos temporales.
2 Cada rol debe desarrollar una serie de estructuras que debe enviar a los roles dependientes.
Esto es, el analista enviará un conjunto de diagramas de notación conocida a los programa-
dores que implementarán el código de la aplicación. A su vez los programadores deberán
enviar aquellos scripts PHP que deben ser modificados para adecuarlos al aspecto Web que
los diseñadores multimedia han realizado. Los diseñadores multimedia remitiran a los pro-
gramadores los scripts modificados para verificar que no se ha modificado la lógica de
programación.
Finalmente, en el último tema se realiza una introducción al empleo de XML como estándar de
comunicación de datos entre aplicaciones y como se puede un API específico de PHP usar para
generar y modificar documentos XML.
28.1.1 INTRODUCCIÓN
Para comenzar a hablar de programación orientada a objetos en PHP es necesario recordar cúales
son sus conceptos básicos. Estos conceptos varían dependiendo de las diferentes fuentes
consultadas, pero se pueden mencionar algunos que son básicos y necesarios para cualquier
lenguaje del cual pueda decirse que es orientado a objetos:
- Herencia.
- Polimorfismo.
<?php
class Something {
var $valor;
function setValor($v) {
$this->x=$v;
function getX() {
return $this->x;
?>
Las propiedades de los objetos son definidas en PHP utilizando la declaración “var” dentro de la
clase. Cuando se declara una propiedad la misma no tiene tipo, hasta que se le asigne algún valor
en particular, asumiendo el tipo del valor asignado. Una propiedad puede ser un entero, un
vector, un vector asociativo, e inclusive puede ser otro objeto. Los métodos son definidos como
funciones, también dentro de la clase. Para acceder a las propiedades de la instancia de esa clase
es necesario referirse a las propiedades con la sentencia $this->propiedad. En caso de no utilizar
el “$this->” la variable será local al método y una vez terminada la ejecución del mismo se
perderá su valor. Para crear una instancia de un objeto se debe ejecutar el operador “new”, que
devuelve en una variable un objeto de la clase que se le indica:
$obj->setX(5);
$entero=$obj->getX();
El método setX ejecutado en el objeto $obj hace que se asigne un 5 a la propiedad ”x” de dicha
instancia. Se puede notar en este punto que se podría haber inicializado la propiedad “x” con
cualquier tipo de variable, por ejemplo una cadena de texto (tipo string). Para asignarle el valor
entero 5 a la propiedad “x” del objeto $obj se podría haber puesto en el código directamente
“$obj->x=5;”, sin la necesidad de llamar a ningún método, pero el problema consistiría en que en
que se estaría violando la regla de encapsulamiento de los objetos. Una buena práctica de la
programación orientada a objetos consiste en acceder a las propiedades solamente mediante
métodos propios de la clase y nunca usar directamente el acceso a las variables.
Lamentablemente PHP en su versión 4.x no ofrece la posibilidad de declarar las propiedades
privadas, pero ha sido corregido en la versión 5. De esta manera se pueden usar modificadores de
acceso para catalogar las propiedades e implementar así la encapsulación de datos.
<?php
var $y;
function setY($v) {
$this->y=$v;
function getY() {
return $this->y;
?>
Los objetos de la clase “Another” poseen todas las propiedades y metodos de su clase padre
“Something”, más las propiedades y métodos propios. Ahora se pueden ejecutar por ejemplo los
siguientes comandos:
$obj2=new Another;
$obj2->setX(6);
$obj2->setY(7);
En PHP una clase de objetos no puede ser “hija” de más de un “padre”, lo que es conocido como
herencia múltiple. En PHP se pueden reescribir métodos de la clase padre en la clase hija (técnica
conocida como overriding). Para esto sólo hace falta volver a definir la función en el objeto hijo.
Por ejemplo si se desea redefinir el método getX para la clase “Another” simplemente se define
la función en la clase “Another”. Una vez hecho esto no es posible para los objetos de la clase
“Another” ejecutar el código del método getX de “Something”.
En caso de declararse una propiedad en la clase “hija” con el mismo nombre que en la clase
padre, la propiedad de la clase padre se encontraría “oculta”.
En las clases se pueden definir constructores. Los constructores son métodos que se ejecutan al
momento de instanciar la clase (cuando se ejecuta la sentencia new). La característica para que
un método sea el constructor de una clase (en las versiones PHP 4.x) es que debe tener el mismo
nombre que la clase.
<?php
class Something {
var $x;
function Something($y) {
$this->x=$y;
function setX($v) {
$this->x=$v;
function getX() {
return $this->x;
?>
$obj=new Something(6);
Automáticamente el constructor asigna el valor entero 6 a la propiedad “x”. Todos los métodos,
incluyendo los constructores, son funciones normales de PHP, por lo que se le pueden asignar
valores por defecto. Supongamos que tenemos el constructor definido de la siguiente manera:
function Something($x="3",$y="5")
Los argumentos por omisión son utilizados en C++ y son una vía para cuando no hay valores
poder pasar por parámetro las variables a las funciones. Cuando el parámetro no es encontrado
por la función que es invocada, toma el valor por omisión que le es especificada en su definición.
Otro mecanismo interesante de la POO consiste en la utilización de las interfaces. Son clases que
no son instanciables y están hechas para el único propósito de definir una especificación de
funciones para otras clases que implementarán dichas funciones. Los analistas usualmente
utilizan estas clases para forzar a los programadores a asegurarse que cada clase tiene una cierta
funcionalidad predefinida.
<?php
function niceDrawing($x) {
$x->draw();
$obj=new Circle(3,187);
$obj2=new Rectangle(4,5);
?>
Fundamentos de PHP 5
que se envió anteriormente. En el capítulo 12 se describe de manera detallada y con ejemplos los
elementos de la POO soportados en PHP5, mientras que en el capítulo 13 se describen los
principios del lenguaje unificado de modelado (UML) usado en la descripción de una aplicación
que usa la POO. Es muy importante la lectura de este capítulo porque permite tener una visión
global del modelo de desarrollo de la POO.
Serialización
PHP no soporta la persistencia de objetos. En la POO los objetos persistentes son objetos que
mantienen su estado y funcionalidad a través de múltiples invocaciones de la aplicación. Esto
puede resolverse salvando el objeto en un archivo o en una base de datos y restaurando los datos
cada vez que se ejecuta dicha aplicación. El mecanismo es conocido como serialización. PHP
proporcione un método de serialización que puede ser llamado por los objetos. El método de
serialización devuelve un string representando el objeto. La serialización guarda las propiedades
del objeto pero no sus métodos.
En PHP si se serializa un objeto sobre el string $s, se destruye el objeto, y entonces utilizando la
deserialización de objeto en $obj se puede mantener el acceso a las propiedades del objeto. Esto
no se recomienda por dos razones: la primera es porque no se garantiza que en futuras versiones
esto siga funcionando. La segunda es porque si se serializa un objeto, se guarda a disco el string
y se sale del script, al ejecutar en el futuro dicho script puede ser posible que los métodos del
objeto no sean los mismos, ya que en la serialización sólo se guardaron las propiedades.
Concluyendo, la serialización es útil en PHP para guardar las propiedades de un objeto (se puede
serializar un vector asociativo para salvarlos a disco por ejemplo).
<?php
$obj=new Classfoo();
$str=serialize($obj);
$obj2=unserialize($str)
?>
En este caso se dispone de las propiedades recuperadas pero no se pueden utilizar los métodos ya
que no existe información sobre ellos.
para algunos productos se reproducirá un sonido mientras que para otros productos se mostrará
una foto del mismo guardada en la base de datos. Se puede definir una clase Producto, con los
métodos que la clase debe tener (por ejemplo “display”), y entonces se definen clases para cada
tipo de producto como una extensión (extends) de la clase Producto, por ejemplo clase
ItemSonoro, ItemVisible, etc., redefiniendo los métodos que ya se definieron en Producto para
cada una de las clases hijas. Lo que resulta conveniente en este caso es nombrar las clases de
acuerdo con los tipos de “columna” que se guardan en la base de datos por cada tipo de producto
(id, tipo, precio, etc.).
De esta manera cuando se procese el script se puede pedir el tipo desde la base de datos e
instanciar un objeto de la clase del tipo de producto:
<?php
$obj->display();
?>
Esto propiedad de PHP permite llamar al método “display” por ejemplo del tipo de objeto que se
desea usar. Con esta técnica no es necesario modificar el script de proceso (el formulario) cuando
se agrega un nuevo tipo de objeto, solamente se debe añadir la nueva la clase. Esta es una
funcionalidad muy interesante (disponible sólo en lenguajes interpretados como PHP). Sólo se
debe cuidar la definición de los métodos que todos los objetos deben tener de acuerdo a los tipos
que se especificaron, generando las diferentes maneras para los diferentes tipos.
<?php
$obj_serializado=serialize($obj);
$vec=explode( ':',$obj_serializado);
?>
Teniendo en cuenta lo anterior, si especificamos una clase “Universal” y se fuerza a que todas las
clases sean extensión de ella (como hace Java, en donde todas las clases heredan directamente de
la clase Object) se puede definir un método “clone”:
<?php
class Universal {
function clone() {
$obj=serialize($this);
$vec=explode( ':',$obj);
$ret=new $name;
return $ret;
//Entonces:
$obj=new Something();
$other=$obj->clone();
?>
28.1.4 EJERCICIOS
1 Se desea definir una clase Forma con dos métodos dibujar() y borrar(), de la cual heredan
tres clases: Circulo, Cuadrado y Rectángulo. Para cada una de las clases se deben redefinir
los métodos dibujar() y borrar(), imprimiendo un mensaje en cada llamada a dichos méto-
dos (por ejemplo, echo ‘Dibujo un circulo’ y echo ‘Borro el círculo’). Desarrolle un script
php que demuestre el funcionamiento del polimorfismo mediante la generación aleatoria
de diez objetos de las clases Circulo, Rectángulo y Triángulo. Cada objeto instanciado de
las clases anteriores se tratará como un objeto de la clase Forma (a esto se le denomina
casting) y se realizarán sendas llamadas a los métodos dibujar() y borrar(). Explique qué
ocurre y porqué.
2 Cree una clase base (padre) con dos métodos, de tal forma que en la implementación del
primer método se llame al segundo. Cree una clase hija de la anterior y sobrescriba el seg-
undo método de forma que imprima un mensaje indicando el nombre de la clase hija.
Escriba un script php que cree un objeto de la clase hija, convierta dicho objeto (casting) a
un objeto de la clase padre, y realice una llamada al primer método usando los dos objetos
(padre e hijo). Ejecute el script y explique qué ocurre y porqué.
3 Defina una interface Conmutador con tres métodos: on(), off() y switch() y desarrolle dos
clases que implementen la interface. La primera es un conmutador de tipo semaforo que
está en verde cuando está encencido y rojo cuando está apagado. La segunda es un con-
mutador telefónico que permite enviar sonido cuando está encendido y finaliza la emisión
cuando se apaga. Escriba un script php (o varios, según necesite) que permita seleccionar
el tipo de conmutador (creando así un objeto del tipo apropiado) y una vez seleccionado se
pueda invocar a los métodos on(), off() y switch() apropiados, mostrándo en pantalla el
estado del objeto. Por ejemplo al invocar el método on() de un conmutador tipo semáforo
se debe mostrar en pantalla un mensaje indicando “Estoy en verde”.
4 Desarrolle una aplicación PHP que almacene los resultados del formulario/encuesta
desarrollado en Javascript en el módulo anterior en el servidor mediante el uso de la serial-
ización de objetos. Esto debe permitir al usuario almacenar de manera parcial o total los
resultados en una cadena de texto en el servidor, mediante un botón Guardar respuestas.
5 Realize el diseño de clases (mediante UML, vea el capítulo 13) de un “hipotético” sistema
de control de acceso y de autorización a los usuarios de una tienda virtual de compra on-
line. Se debe tener en cuenta que funcionalidades que pueden realizar los usuarios, depen-
diendo el pérfil, las controla el sistema de autorización mientras que el sistema de acceso
valida la información de conexión.
Las plantillas (del término ingles Template) consisten en una técnica que permite diseñar de
manera visual los documentos HTML que se enviarán desde servidor y que emplea la
información generada por los scripts para mostrar el contenido completo de la página HTML (el
documento diseñado más la información dinámica). Mediante el uso de plantillas se puede crear
rápidamente gran cantidad de documentos de un aspecto parecido, simultáneamente, separando
la lógica de programación (scripts y funciones php) del lado visual. Una plantilla individual
puede ser utilizada un número interminable de veces, incluso para la construcción de la siguiente
plantilla. Esta separación del desarrollo de los scripts php y la parte visual permite definir un
entorno de trabajo que sitúa a los editores web en la generación de los documentos HTML y a los
pogramadores en el desarrollo de las funcionalidades.
En Internet se pueden encontrar diferentes sistemas de plantillas que se pueden combinar con
PHP:
• PHPLib (http://phplib.sourceforge.net/)
• TemplatePower (http://templatepower.codocad.com/)
• TemplateLite (http://templatelite.sourceforge.net/)
• Smarty (http://smarty.php.net/)
Se podrían usar cualquiera de estos sistemas de plantillas, pero se va a emplear Smarty por ser el
más usado en los sistemas de desarrollo basados en PHP. El mecanismo de funcionamiento en
todos es muy parecido (salvo quizás la notación usada para pasar la información que necesita la
página HTML para ser generada), por lo que se recomienda al estudiante que una vez finalizado
el estudio del sistema Smarty, lo compare con el resto de las alternativas.
En principio no parace de mucha utilidad puesto que se podrían obtener resultados parecidos
mediante la función echo dentro del documento: <?echo $var;?>. Sin embargo, como se verá a
continuación, el uso de la notación anterior permite a los diseñadores de las páginas Web evitar el
aprendizaje de la sintáxis de PHP. Lo único que deben conocer es la información a incluir en el
documento y dónde ubicarla. Adicionalmente la lectura del documetno HTML es más sencilla y
comprensible. He aquí la primera ventaja de Smarty, no la última y la menos importante.
Existencia de Modificadores
Los modificadores funcionan directamente sobre las variables, modificando su apariencia o su
contenido. Se pueden desplegar cadenas con la ayuda de letras mayúsculas, sustituir en la cadena
la palabra indicada por otra expresión, o acortarla a una longitud concreta. De esta manera, el
programador debe proporcionar únicamente los datos señalados por el diseñador, y éste se
ocupará de su formato. De este modo, se focaliza el trabajo de desarrollo en la obtención de la
información necesaria de la base de datos, del archivo o de alguna función. Al mismo tiempo, el
diseñador recibe mejores y significativas posibilidades para el formato del documento, de las que
le ofrece HTML. Además de todo esto, no tendrá problemas con usar los modificadores, dado
que son más entendibles y secillos de usar, con respecto a las funciones correspondientes de PHP.
Funciones propias
Smarty añade un conjunto de funciones que le introducen elementos de programación. mediante
estas funciones se puede leer el contenido de los arrays, crear un contador que estará numerando
las cabeceras consecutivas en el texto o rápidamente crear una lista de campos opcionales en una
sola línea de código. Por ejemplo, se puede usar el siguiente código :
$lista_revistas = array ("1" => "Programación en PHP", "2" => "Revista AJAX");
Al generar la página se creará dentro del documento HTML el siguiente trozo de código:
Conviene mencionar que todo el código creado mediante las funciones construídas en Smarty se
genera en el estándar XHTML, o al menos eso es lo que indica la documentación. Si se analiza el
ejemplo anterior se aprecia que en el interior del tag <input/> se encuentra el atributo name. Las
especificaciones de XHTML indican claramente que ese atributo debería ser sustituído por id.
Otra de las posibilidades es la creación de instrucciones if. Se pueden emplear con el objetivo de
verificar si una variable determinada que se le enviará a la plantilla contiene un valor o no. Por
ejemplo:
{else}
¿Cual es tu nombre?
{/if}
Creación de Filtros
El uso comentarios en los scripts y páginas HTML permite documentar de manera detallada el
proceso de programación y desarrollo de las aplicaciones, pero desgraciadamente dichos
comentarios se hacen visibles a los usuarios. Para evitar esto se usa el concepto de filtro, de tal
forma que se limpian las plantillas de comentarios, antes de ser generadas las páginas Web. Los
filtros también permiten agregar nuevo contenido en los archivos generados, como podría ser el
logotipo de la empresa en la parte inferior de la plantilla.
Plugins
Smarty es un sistema abierto, fácil de extender o modificar. Los plugins permiten crear
modificadores, funciones y filtros. También se pueden utilizar plugins construidos y
proporcionados por otros. Ya que todo está en PHP, únicamente debemos cumplir con las
especificaciones que indican los requerimientos que se refieren a la construcción de plugins en
Smarty (http://smarty.php.net/manual/es/plugins.php).
Utilización de la caché
Cuando se crea una plantilla se genera un script php con la estructura del documento (es decir, se
convierte la plantilla Smarty a un script php) que es usada por el módulo php del servidor web
para generar la página HTML que servirá al cliente. De esta manera una vez generado el script,
todas las peticiones se resolverán con llamadas al script php generado a través de la plantilla. Si
existe un cambio en la plantilla, el sistema de manera automática vuelve a generar el script php.
El trabajo de Smarty puede acelerarse utilizando la caché (del término ingés Caching). Esta
operación consiste en almacenar el documento en formato HTML, que será enviado durante la
siguiente llamada al navegador del cliente, sin la necesidad de procesar nuevamente los scripts, o
realizar las consultas a la base de datos.
El empleo correcto de Smarty requiere la creación de cuatro carpetas. Sus nombres por defecto
son /templates, /templates_c, /configs y /cache (a los directorios les coresponden 4 variables
dentro del archivo Smarty.class.php: $template_dir, $compile_dir, $config_dir y $cache_dir).
Para configurar Smarty simplemente hay que incluir la clase Smarty.class.php, redefinir la clase
Smarty indicando los directorios que deben usarse y luego instanciar un objeto de la nueva clase,
como muestra el siguiente ejemplo (Smarty_config.class.php):
<?php
define('SMARTY_DIR',"smarty/");
require_once(SMARTY_DIR.'Smarty.class.php');
function Smarty_config() {
$this->teplate_dir = "templates/";
$this->compile_dir = "templates_c/";
$this->config_dir = "configs/";
$this->cache_dir = "cache/";
//$this->caching = false;
//$this->debugging = true;
//$this->debug_tpl = 'debug.tpl';
?>
Como se puede ver es necesario indicar los directorios para templates (smarty/templates),
templates compilados (smarty/templates_c), archivos de configuracion y cache. Obsérvese que
los directorios son relativos al directorio en donde esta Smarty (definido con SMARTY_DIR) y
no a la aplicacion. Además si se eliminan los comentarios finales tambien se indica si se desea
usar el sistema de cache o si se quiere disoponer una ventana emergente de depuración para las
plantillas. Una vez hecho esto el objeto "smarty" es el que se empleará para mostrar las plantillas.
Paso 1 En primer lugar se debe crear el template hola.tpl que se situará en el directorio de templates (por
ejemplo smarty/templates). Su contenido es muy simple:
Como se puede ver la plantilla es una mezcla de codigo HTML y directivas Smarty (entre llaves)
y que en este caso lo que hace es mostrar el contenido de la variable $nombre. Las variables
deben generarse y asignarse desde un script PHP.
Paso 2 Escriba un script php denominado hola.php que contenga el siguiente código:
<?php
require_once('Smarty_config.class.php');
$smarty-> assign('nombre','Rafa');
$smarty->display('hola.tpl');
?>
El script asigna a la variable de smarty 'nombre' la cadena de texto 'Rafa' y luego muestra el
template 'hola.tpl'. El resultado es un documento html que dice: Hola mundo, Mi nombre es Rafa.
Realmente este ejemplo es bastante simple pero permite ver la forma de emplear un objeto
smarty para recopilar la información que luego se empleará en la generación de la página HTML
correspondiente. A continuación se muestra un ejemplo más completo que usa varias de las
características del sistema de plantillas Smarty.
Para las necesidades de este ejemplo, se supone que se tiene una página sobre un conjunto
musical. Para que el trabajo resulte agradable, supongamos que es el grupo The Beatles. La parte
en la que mejor se pueden aplicar las plantillas es la discografía del conjunto. Cada disco debería
tener su propia página con el nombre del álbum, la descripción de las canciones, la fotografía de
la portada además de una breve descripción. Todos van a utilizar las plantillas preparadas , lo que
facilita añadir rápido los siguientes discos, y al mismo tiempo, las modificaciones posteriores de
cada una de las páginas.
Para eso se crea una plantilla de ejemplo, cuyo contenido se presenta en el Listado 1. Como se
puede ver ya a primera vista, es un documento común y corriente escrito en XHTML. Sin
embargo, es fácil encontrar el lugar donde aparecen las variables. En las plantillas de Smarty, el
nombre de las variables va precedido por el símbolo del dólar ($) y encerrado entre llaves.
Además, en ellas no se tienen puntos y comas, que son tan comunes en los scripts de PHP. El
archivo de la plantilla es un archivo de texto común, al cual se le asigna la extensión .tpl (del
inglés: template, es decir, plantilla). Por supuesto, nada impide darle la extensión que se desee.
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>{$albumName}</title>
</head>
<body>
<h3>{$albumName}</h3>
<table>
<tr>
</tr>
</table>
<p>{$albumSynopsis}</p>
</body>
</html>
El archivo debe almacenarse en el directorio /templates de la distribución Smarty. Una vez lista
la plantilla, se debe utilizar en el código de la aplicación. Para eso se debe crear un script PHP
cuyo contenido se muestra el Listado 2. En este script se definen los valores concretos de las
variables y la plantilla utilizada. Este archivo se coloca junto con otros documentos web.
<?
require ("Smarty.class.php");
$smarty->assign("albumCover", "grafika/sgtpep.jpg");
Sgt. Pepper's Lonely Hearts Club Band (Reprise);A Day In The Life");
$smarty->display("album.tpl");
?>
Una vez visto un ejemplo de script que usa Smarty es necesario comentar ciertos detalles sobre el
mecanismo de Smarty. En la primera etapa, tiene lugar la compilación de la plantilla. Pero esto
no tiene nada que ver con la compilación conocida de tales lenguajes como, por ejemplo, Java, o
la compilación de scripts PHP. Su propósito es la conversión de la plantilla a un documento php.
Esto significa que, por ejemplo, la notación {$var} será cambiada a:
<?php
echo $this->_tpl_vars['var'];
?>
El código PHP de title.php es muy simple de interpretar y leer. Para empezar, se debe cargar la
librería Smarty y crear un nuevo objeto tipo smarty. Luego se emplea el método assign para crear
las variables y asignarles valores concretos. Smarty maneja los mismos tipos de variables que
PHP, así que se pueden emplear números, cadenas, arrays, etc. Finalmente el método display se
encarga de que se cargue la plantilla dada y se despliege todo el documento. Desde luego, el
archivo title.php podría contener una secuencia de funciones complicadas que permitirían la
carga de datos desde una base de datos, archivos de texto, etc. Pero se puede suponer aquí por
simplicidad que ya se dispone de ella y se pueden asignarl a variables de una vez. En este
momento, se debe prestar atención a un punto importante. Todo lo que se colocará en la plantilla
entre llaves, será tratado como una posible variable o función. Así que, si se desea introducir una
llave en el texto, debemos utilizar {ldelim} para la llave izquierda y {rdelim} para la llave
derecha. Lo mismo se refiere a colocar en el documento estilos o scripts, por ejemplo:
<style>
p {ldelim}color: #000000;
font-size: 12px{rdelim}
</style>
Es fácil convencerse de que este método resulta complejo en el caso de una gran cantidad de
llaves por lo que se puede utilizar el tag {literal} disponible en Smarty. Todo lo que se encuentra
entre {literal} y {/literal} no será interpretado por el mecanismo Smarty. El ejemplo anterior del
código quedaría:
{literal}
<style>
p {color: #000000;
font-size: 12px}
</style>
{/literal}
De paso se debe mencionar que Smarty tiene su propio mecanismo de comentarios, que son
eliminados durante la compilación. Los comentarios en la plantilla se inician con {* y terminan
con *}. Volviendo a la plantilla de ejemplo, se ve claramente que se pueden mejorar en ella
muchas cosas. Se puede mejorar rápidamente con algo sencillo: los modificadores.
{$variable_name|modifier_name}
Algunos de los modificadores pueden tener parámetros que deben ser proporcionados al
llamarlos. Si existiera la necesidad de añadir un parámetro a un modificador, se puede hacer
mediante el siguiente esquema:
{$variable_name|modifier_name: parameter1:parameter2}
El parámetro puede ser una cadena o un valor numérico. En el primer caso, se deben colocar
entre comillas. ¿Qué modificadores serían de utilidad para el ejemplo? Nótese que no todos los
fragmentos del título del álbum empiezan con mayúsculas. Podría ser un dato erróneo en la base
de datos, pero eso es irrelevante para un diseñador. Este valor de la variable fue transferido a la
plantilla y se debe usar tal y como viene. Para eliminar este problema, se añade el modificador
capitalize a la variable $albumTitle. Este hará que cada palabra en la variable dada empiece con
mayúscula.
Otro punto que merece la pena subrayar, es el índice de canciones. Se ha supuesto que es
porporcionado en forma de una variable escalar, donde los títulos son separados por punto y
coma. Desde luego, sería más cómodo almacenarlos en un array, pero esto lo veremos más tarde.
Ahora debemos intentar formatear la lista que llega de esta forma. Para empezar, emplearemos el
modificador replace, que busca en la variable una cadena y la cambia por otra. En este caso, el
modificador que requiere dos parámetros. El primero de ellos es la cadena a buscar y el segundo
– la cadena a introducir. Se van a cambiar los puntos y comas en la variable $albumSongs por
tags <br/>. De este modo se obtendrá la lista de canciones, cuyos títulos serán colocados uno
debajo del otro.
El último punto será ajustar el párrafo con la descripción del disco. Para este propósito se debe
utilizar el modificador wordwrap, el cual ajusta la cadena a un ancho determinado. El
modificador posee tres parámetros. El primero de los parámetros indica el ancho al cual el texto
se debe ajustar (por defecto son 80 caracteres), el segundo, define el símbolo que servirá para
ajustar el texto (por defecto es \n), el tercer parámetro indica si el texto debe ser ajustado al final
de la palabra o si la palabra puede ser dividida en dos partes (la primera opción es la que está por
defecto).
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>{$albumName|capitalize}</title>
</head>
<body>
<h3>{$albumName|capitalize}</h3>
<table>
<tr>
</tr>
</table>
<p>{$albumSynopsis|wordwrap:100:"<br />"}</p>
</body>
</html>
include ("file.txt");
{include file="file.txt"}
Además, ciertas funciones tienen etiquetas de apertura y cierre, por ejemplo, {literal} presentada
anteriormente. Como ya se conoce la información básica sobre las funciones, se pueden aplicar
en la plantilla de ejemplo.
...
<table>
<tr>
{/foreach}</td>
</form>
</tr>
</table>
...
Si se analiza el código del Listado 4, se pueden ver claramente los efectos de las modificaciones
y el uso de las funciones utilizadas en la plantilla. Para empezar, se abre la función y se definen
sus parámetros. El primero de ellos (key) define una variable a la que se asignará la clave del
elemento actual del array, mientras que el segundo (item) es una variable a la que se asignará el
valor del elemento. El siguiente atributo (from) es el nombre del array que se usará en el
recorrido. El último (name) define el nombre asignado al bucle (no es imprescindible, pero puede
ser de utilidad para ser referenciado en otras funciones). En la siguiente parte del código, se
realiza la visualización de las variables, introduciendo simplemente sus nombres a la plantilla.
Conviene prestar atención a la primera variable – {$smarty.foreach.songs.iteration}. Es una
variable de entorno que permite obtener el número de iteración actual. Al final se cierran las
etiquetas de las funciones. De esta forma sencilla se obtuvo, al mismo tiempo, el índice
numerado de canciones junto con sus tiempos de duración – todo gracias a tres líneas de código.
Se pueden añadir elementos extras a la página de ejemplo, por ejemplo una calificación del
álbum. Para este propósito se necesita definir una forma para votar, además del script
correspondiente que contará los votos y almacenará los resultados. La forma más sencilla es
insertar una combo box en la página, que ocupa menos espacio que los campos de selección.
Supongase que a cada disco se le va a asignar el rango de calificaciones del 1 al 6. Para generar la
lista y el formulario, se podría escribir un script en PHP, pero Smarty es capaz de realizar esta
acción.
La lista completa será creada con la ayuda de la función llamada {html_options}. La función
tiene tres parámetros interesantes. El primero es values, al que hay que asignarle un array con
valores que serán las opciones de la lista. El segundo es el output, que también exige un array que
contenga elementos desplegados en la lista. El último atributo es name, que define el nombre de
la lista. Todo el código que crea el formulario se presenta en el Listado 4.
Solo falta una cosa para que la combo box pueda funcionar correctamente: el array con las
calificaciones (para definir los valores y nombres de las posiciones de la lista utilizaremos los
mismos datos). Se debe definir en el archivo title.php con la ayuda del método assign.
Variables de entorno
La variable {$smarty} es una variable reservada. Gracias a ella se dispone de acceso a mucha
información sobre los temas de Smarty, por ejemplo, el nombre de la plantilla procesada
actualmente, y no sólo eso. Con su ayuda se reciben diferentes variables de entorno. Si se quiere
desplegar el valor de la variable $id, que fue transferida por el navegador por medio del método
Una variables muy interesante: {$smarty.now}, en la que se almacena la fecha y el tiempo actual
del sistema en formato de tiempo Unix.
Archivos de configuración
Los archivos de configuración son ideales para definir variables que serán usadas en varias
plantillas. Por ejemplo, supongase que se quiere que en el título del navegador siempre aparezca
el texto “Super página sobre The Beatles”. Para este propósito se puede crear un archivo de
configuración llamado title.conf y se almacena en el directorio /configs (por defecto, Smarty
carga de ahí los archivos de configuración). Se añade una variable en él de la siguiente manera:
El nombre de la variable no inicia con el signo de dólar, y al final no hay un punto y coma. Todo
debe estar escrito en una sola línea. La forma de llamar una variable del archivo de
configuración, dentro de una plantilla, no es muy común. Para este propósito se sitúa su nombre
entre el símbolo hash (#), por ejemplo
<title>{#pageTitle#}</title>
Pero antes de insertar la variable dentro de la plantilla, se debe cargar en ella el archivo de
configuración, con la ayuda de la función {config_load}. La función tiene el atributo file, cuyo
valor es el nombre del archivo. Recordad que es suficiente dar sólo su nombre, para que Smarty
lo busque automáticamente dentro del directorio /configs.
Conviene mencionar que en los archivos de configuración se pueden emplear los comentarios
disponibles en PHP. El otro punto importante es la forma de almacenar las variables, las que
sobrepasen la longitud de una línea. En este caso, se deben encerrar entre un triplete de comillas,
por ejemplo:
Uso de filtros
En Smarty, los filtros están divididos en 3 grupos: Prefilters (cambian el contenido de la plantilla
antes de que haya sido compilada), Postfilters (modifican la plantilla después de la compilación)
y Output Filters (son ejecutados en el momento de la invocación de la llamada de la plantilla
existente, con la ayuda del metodo display). Los filtros se pueden colocar dentro de las plantillas
de dos formas: cargar un filtro ya creado o registrar uno nuevo en un archivo PHP. En primer
lugar se va a describir este segundo método.
Un filtro no es otra cosa que una función desarrollada en php que debe tener dos parámetros:
$tpl_source (en el caso de los filtros del tercer grupo es $tpl_output) y &$smarty. Como se
<?
require ("Smarty.class.php");
$smarty->assign("albumCover", "grafika/sgtpep.jpg");
$smarty->assign("albumSongs",array(
"Lucy In The Sky Of Diamonds" => "(3:28)", "Getting Better" => "(2:47)",
"Within You, Without You" => "(5:05)", "When I'm Sixty-Four" => "(2:37)",
"Lovely Rita" => "(2:42)", "Good Morning, Good Morning" => "(2:41)",
\n\n</body>\n</html>";
$smarty->register_postfilter("footer");
$smarty->display("album.tpl");
?>
La función footer() se emplea para de colocar un pie de página en la plantilla. En este caso es
solamente un enlace a la página principal y las etiquetas de cierre </body> y </html>. Desde
luego, el pie de página es colocado después del contenido de la plantilla. Luego de definir la
función, se debe registrar como filtro mediante el método register_postfilter.
Por supuesto, sería más efectivo almacenar el filtro en un archivo separado, y después, cargarlo
directamente en la plantilla.
$smarty->variable=value,
Para terminar, hay que recordar que la propia consola se basa en la plantilla debug.tpl que se
encuentra en la librería de archivos Smarty. Se puede modificar para que el aspecto de la consola
concuerde con las necesidades de los probadores de código. Por otro lado, si se quisiera pasar la
plantilla de la consola a otro lugar, se debería cambiar el valor de la variable $debug_tpl.
Modo seguro
Se puede ejecutar Smarty de modo seguro o, como lo define la documentación, con la variable
$security activada. Si se modifica su valor a true (verdadero), entonces Smarty activa el modo
seguro pero con algunas limitaciones relacionadas con su funcionamiento. No se puede utilizar el
código PHP directamente en las plantillas, los archivos externos podrán ser cargados solamente
desde ciertas localizaciones, además, en modificadores e instrucciones if podrán usarse las
funciones de PHP, únicamente si han sido definidas con anterioridad. Al modo seguro se ligan
dos variables más: la primera de ellas es $secure_dir, que representa el array que define el
conjunto de directorios seguros; la segunda es $security_settings, que define el conjunto de
funciones seguras de PHP.
Caché
Como se mencionó al principio del artículo, Smarty compila las plantillas y las almacena en
directorios separados con el fin de mejorar su funcionamiento. La segunda propiedad que acelera
el despliegue de las plantillas es el uso de la caché. Para activarlo, se puede abrir el archivo
title.php y añadir en él la siguiente línea
$smarty->caching=true;
¿Qué sucede en caso de que durante el lapso de tiempo definido por la variable, se realice un
cambio en la plantilla o en cualquier otro archivo que sea utilizado por el documento? Entonces
en el explorador todavía aparecerá el contenido del archivo almacenado en la caché. Para que los
cambios se reflejen enseguida se puede establecer el valor true a la variable $compile_check. En
ese caso, si Smarty descubre que la plantilla o cualquier otro archivo ha sido modificado, el
contenido de la memoria caché se crea de nuevo.
No es la solución ideal y por eso Smarty también ofrece la posibilidad de almacenar sólo una
parte de la página.
28.2.6 EJERCICIOS
Para la realización de los ejercicios es muy importante que lea la documentación disponible en
http://smarty.php.net/manual/es/
1.- Suponer que se dispone de una tienda virtual donde se venden una serie de productos que
tienen características comunes: identificador (no se mostrará) , nombre, descripción, lista de
características, imagen, unidades disponibles, días aproximados de envío del producto,
fechas inicial y final de disponibilidad. Diseñe una plantilla smarty capaz de mostrar todas
las propiedades del producto empleando las técnicas mostradas en la introducción teórica
(uso de modificadores y funciones). Suponga que el nombre y la descripción son cadenas de
texto, la lista de características un array, las unidades disponibles y los dias aproximados son
enteros y las fechas cadenas de texto con un representación de formato AÑO (4 digitos) -
2.- En una tienda virtual existen varios roles de usuarios que pueden realizar diferentes
acciones, tal y como se muestra en la Tabla 2.1. Diseñar las plantillas necesarias que depen-
diendo del tipo de rol, muestren en un menú ubicado en la parte superior las opciones dis-
ponibles para cada tipo usuario. Escriba un script php que permita seleccionar el tipo de rol
y a continuación muestre su plantilla correspondiente.
Función Administrador Comprador Vendedor Anónimo
Añadir categoría Sí No No No
Editar categoría Sí No No No
Eliminar categoría Sí No No No
Añadir Producto Sí No Sí No
Editar producto Sí No Sí No
Eliminar Producto Sí No Sí No
Añadir Producto Carrito No Sí No No
Ver Carrito No Sí No No
Eliminar Producto Carrito No Sí No No
Buscar Productos Catálogo Sí Sí Sí Sí
Listar Productos Catálogo Sí Sí Sí Sí
3.- Si se analiza la acción “Ver un producto” de una tienda virtual se puede concluir que depen-
diendo del tipo de rol es posible asociar otros tipos de acciones. Un administrador o el vend-
edor de dicho producto podrá también Editar o Eliminar el producto y Un comprador podrá
adicionalmente Añadir el producto al carrito. Crear las plantillas necesarias que, usando la
plantilla del primer ejercicio como base, añada las acciones correspondientes al rol (selec-
cionable mediante el script del ejercicio anterior, que se debe reutilizar). Se pueden ubicar
en la parte superior de lo que sería “la ficha” del producto.
4.- Generar una estructura HTML que tenga una cabecera, un menú izquierdo, el contenido
central y un pie de página mediante plantillas Smarty (emplee la técnica de filtros mostrada
en la parte teórica). La cabecera debería mostrar la hora y fecha actual (use la función
Smarty correspondiente) y permitir seleccionar el tipo de rol empleado en la tienda virtual,
el menú izquierdo una lista de 10 productos que al ser seleccionados hace que se muestre en
el contenido central la ficha del producto (generada en el ejercicio 3) y el pie de página debe
mostrar el nombre de los productos mostrados.
28.3 XML
La utilización de las etiquetas en XML implica que un documento XML tenga un aspecto similar
a un documento HTML. Sin embargo este último sólo se encarga de definir cómo se va a
presentar la información del documento, mientras que XML se centra en describir la estructura
de los datos. En sentido estricto, un documento XML es simplemente un documento de texto
plano al que se le añaden etiquetas, proporcionando estas etiquetas un mecanismo muy poderoso
para definir la semántica de cualquier documento.
El origen de XML se remonta a finales de los años sesenta, cuando un grupo de investigadores se
empezó a preguntar si podría ser interesante dar usos alternativos a los documentos electrónicos.
En particular, IBM pidió a Charles Goldfarb que construyese un sistema para almacenar, buscar,
gestionar y publicar documentos. El resultado de su trabajo fue el lenguaje SGML (Standard
Generalized Markup Language).
1.- Para intercambiar información los programas tienen que soportar un lenguaje común. Tiene
sentido que ese lenguaje común sea algún tipo de lenguaje de marcas.
2.- La estructura de un documento se puede ver como una jerarquía de elementos. Por ejemplo,
un correo electrónico tiene, en un primer nivel, un elemento "encabezado" y un elemento
"cuerpo". El encabezado puede contener, a su vez, elementos "destinatario", "asunto", etc.
Las marcas que delimitan estos elementos se denominan marcas estructurales generalizadas
(eStructural Generalized Markup).
3.- Los documentos tienen que seguir algún tipo de reglas, es decir, el lenguaje de marcas
debería ser especificado de algún modo formal que permitiese garantizar que el documento
cumple cierta estructura. Esto facilita al dispositivo visualizador la manipulación de los
datos y la realización de cálculos a partir de ellos.
1.- Permite al dispositivo visualizador hacer el trabajo de presentación de los datos en la pan-
talla.
4.- Fomenta la creación de vocabularios (marcas) específicos en diferentes dominios, como los
bancos, las telecomunicaciones, el transporte o la ingeniería de sistemas (por ejemplo
daqXML, AIML o VIML).
La característica principal del uso de documentos XML es la capacidad de definir los datos de
forma independiente a su presentación. En otros lenguajes de marcas, como por ejemplo HTML,
la propia definición de los datos en el documento lleva implícita la forma de presentar la
información. En el caso de XML es posible definir la estructura de los datos (normalmente
jerárquica) y posteriormente recurrir al modulo de transformación para obtener la presentación
adecuada al dispositivo donde se visualizará la información.
Los documentos XML están compuestos por caracteres del conjunto Unicode que se combinan
en cadenas de texto. La sintaxis de XML describe la forma de concatenar dichas cadenas de texto
para crear documentos XML bien formados. Las características sintácticas más significativas de
un documento XML son:
2.- Las etiquetas se delimitan con '<' y ‘>’ o por '&' (al igual que ocurre en HTML).
3.- Los blancos son el espacio (ASCII 32), el tabulador (ASCII 9), el retorno de carro (ASCII
13) y el carácter de línea nueva (ASCII 10).
4.- Los literales aparecen rodeados de comillas simples o dobles. Por ejemplo, si se desea que
un atributo tenga un valor determinado el literal que define ese valor se debería escribir
como nombre_atributo=”valor”.
5.- Los nombres que se pueden utilizar para designar elementos XML deben empezar por letra,
'.' o '_', e ir seguidos de letras, dígitos, '-', '_', '.' y ':'.
Los documentos XML están divididos en dos partes principales: una cabecera y una instancia de
documento. La cabecera está compuesta de una declaración XML y una declaración de tipo de
documento, siendo ambas opcionales. En el Listado 3.3 se presenta un ejemplo de documento
XML, donde la cabecera corresponde a las líneas 1 y 2. En la primera línea se indica la versión
de la especificación XML y en la segunda que la instancia del documento declarará los datos de
acuerdo al tipo de documento holamundo definido en el fichero holamundo.dtd.
1: <?xml version="1.0"?>
3: <holamundo>
4: <saludo>Hola mundo</saludo>
5: </holamundo>
Fundamentos de PHP 5
que se envió anteriormente. En el dicho capítulo se detallan los mecanismos que posee el
lenguaje PHP (tanto en sus versiones 4.x como las 5.x) para analizar documentos XML de
acuerdo a su definición de tipos (DTD o Schema) y generar nuevos documentos con ese formato.
Es especialmente interesante el estudio de las funciones del API de procesamiento XML de PHP
5.x ya que introducen mecanismos simples de realizar las tareas más habituales con documentos
PHP.
Ejercicios
1.- Crear un script PHP capaz de leer un documento XML proporcionado por el navegador cli-
ente (use un botón de carga de fichero para enviar el documento al servidor) e indique si el
documento esta bien formado o no. Como sugerencia, defina una clase AnalizadorPHP con
las propiedades y métodos que crea necesarios.
2.- Modificar el script anterior para que sea capaz de analizar documents XML que tengan aso-
ciados DTDs o Schemas e indiquen si se cumple la especificación de estructura correspondi-
ente. En caso de ser así debe mostrar los errores de análisis encontrados durante la operación
con el formato Linea X: Tipo de error. Como sugerencia, defina una clase hija de la anterior
y añada las propiedades y métodos necesarios.
3.- Genere un script que sea capaz de representar en un formato jerarquico de tipo árbol la
estructura de un documento XML. Puede usar la extensión PEAR que se analiza en el Capí-
tulo 14 del libro Fundamentos de PHP(del que ya dispone) y que proporciona una vista vis-
ual de un árbol de datos. Este ejercicio tiene por tanto dos objetivos: crear una
representación visual de un documento XML y enseñarle que es PEAR y cómo instalar
extensiones de PHP.
4.- Cree un script que permita modificar (añadir, cambiar o eliminar) nodos y atributos de un
documento XML. Use el código desarrollado en el ejercicio anterior para disponer de la
estructura del documento en un marco situado a la izquierda y las acciones a realizar sobre
el documento (añadir, cambiar o eliminar nodos y añadir, cambiar o eliminar atributos de un
nodo) en un marco situado a la derecha.
5.- Cree un editor de documentos XML mediante PHP empleando el código desarrollado en los
ejericios anteriores. Es decir, el editor podrá cargar documentos XML que se podrán modi-
ficar y almacenar posteriormente en el ordenador del cliente. Además deberá poder crear
documentos XML y validar la estructura del documento respecto de un DTD o Schema
externo.