Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Clase 1 Introducción a PHP
Escrito por Demian P. Alonso (demian@linuxadistancia.com)
Programa analítico de la materia
1. Introducción a PHP y los scripts. Variables. Tipos De Datos. Entrada/Salida Básica.
2. Control de flujo: if, for, while, foreach
3. Archivos. Descriptores de Archivos. Entrada/Salida en Archivos. Tuberías.
4. Expresiones Regulares
5. Funciones y Módulos
6. Manejo de archivos y directorios.
7. Biblioteca de funciones: manejo de cadenas; manejo de arreglos; manejo de fechas
8. Servicios de Internet: SMTP, POP y FTP
9. Referencias
10.Introducción al manejo de objetos. Conceptos básicos herencia, polimorfismo, redefinición
11.Excepciones: teoría y aplicación
12.Introducción a la programacion web. Introducción a HTML: HTML, HEAD, BODY. Formato
básico del texto. Creación de links y tablas.
13.Creación de Formularios en HTML. Utilización de Frames y listas en HTML
14.Creación de páginas web dinámicas. Utilización de valores pasados por formularios y por links
15.Manejo de Cookies y sesiones.
16.Introducción a las base de datos relacionales. El servidor MySQL. Lenguaje de Definición de
Datos
17.Lenguaje de Manipulación de Datos
18.Lenguaje de Administración de Seguridad. Utilidades Relacionadas.
19.Índices e Integridad Referencial.
20.Conectividad a base de datos: PHP y MySQL
Conceptos Teóricos Generales sobre Programación
Programa: Es un conjunto de acciones que realizan una tarea especifica. Para ello un programa toma
datos y los convierte en información (por ejemplo, listado de clientes, modificar un archivo, enviar un
dato a otra computadora, etc).
Esquematicamente:
Datos *----------* Información
------->| Programa |------------->
*----------*
Carrera Linux 2008 Programacion PHP 2
Lenguaje de programación: Es un conjunto de reglas sintácticas que nos otorgan una forma de
escribir nuestros programas.
Código fuente: Es un programa escrito en un lenguaje de programación dado.
Compilador: Es un programa que traduce un programa escrito en un lenguaje de programación a un
archivo ejecutable. Esto significa que convierte el texto escrito en un lenguaje de programación X, en
código de máquina para ser ejecutado cuando sea necesario. A este proceso se lo denomina como
compilación. Si se llegase a modificar el código fuente será necesario pasar de nuevo por el proceso de
compilación para que se vean reflejados dichos cambios. Ejemplos de lenguajes que son compilados
son: C, C++, Pascal, Clipper, etc.
Intérprete: Es un programa que se encarga de ejecutar un código fuente en un lenguaje dado. Un
interprete leerá el texto y lo ira ejecutando a medida que lo va leyendo, sin necesidad de generar un
ejecutable. En consecuencia, cuando se altera el código fuente del programa se verá automaticamente
reflejado la proxima vez que se ejecute. Ejemplos de lenguajes que son interpretados son: Perl, Python,
LISP, PHP, Bash, etc.
Variable: Es un espacio en la memoria de la computadora en donde se puede almacenar datos. Toda
variable tiene un nombre para poder usarla desde el programa.
Introducción al uso de PHP
Para crear un programa en PHP deberemos primero crear un archivo con su editor preferido (emacs, vi,
mcedit, kedit, etc).
Este archivo contendrá el có del programa. Sin embargo, la primer línea del mismo tendrá la siguiente
forma (DEBE SER LA PRIMERA DE TODAS):
#!/usr/bin/php
Esta línea le indica al shell en donde se encuentra el intérprete de PHP para ejecutar nuestro programa.
Si en su sistema PHP no se encuentra instalado en ese directorio, deberá cambiar dicha ruta por la
ubicación correcta.
Para saber si PHP esta instalado puede ejecutar desde el shell el siguiente comando:
$ which php
Si PHP esta instalado, entonces se mostrará la ruta al mismo (la cual es la correcta para utilizar).
Una vez escrito el programa, se deberá realizar un paso previo antes de poder ejecutarlo. Primero es
necesario asignarle permisos de ejecución. Para ello utilizaremos el comando chmod:
Donde nombre_archivo.php es el nombre del archivo que acabasen de crear con su programa.
Luego será posible ejecutar el programa simplemente ingresando desde el shell:
$ ./nombre_archivo.php
Si el programa esta bien escrito se ejecutará, en caso contrario PHP nos informará de los errores que
existiesen.
NOTA: Durante todas las clases se adoptará como regla que todos los comandos que se deban ejecutar
desde el shell estarán antepuestos por un símbolo de pesos ($) si se debe ejecutar dicho comando como
un usuario normal o un numeral (#) si se debe ejecutar como root. Dicho símbolo NO se debe escribir
ya que simplemente representa al prompt del shell (que deberín concordar con lo que ve en pantalla)
El lenguaje de programación PHP
PHP (PHP: Hypertext Preprocessor) es un lenguaje que nació en el mundo de las páginas web. Surgió
como una manera práctica de poder mezclar un lenguaje de programación con HTML (el lenguaje para
escribir páginas web).
Un programa en PHP, dentro de una página web, se puede pensar como un conjunto de secciones de
código PHP introducidas dentro de un archivo HTML. En el caso de un programa que interactue
completamente sobre el shell, podremos imaginarlo como un solo gran bloque de código PHP
embebido en nada de HTML.
Entonces, definiremos un bloque de PHP de la siguiente forma:
<?php
# Codigo en PHP
?>
En donde <?php abre el bloque de código y ?> cierra dicho bloque.
Variables en PHP
En PHP todas las variables comienzan con un signo de pesos ($). El interprete cuando encuentra un $
leerá los siguientes carácteres como el nombre de la variable. Los nombres de las variables en PHP
pueden contener cualquier caracter alfanumérico (letras y números) y el guión bajo (_). De todos ellos
queda restringido empezar el nombre de la variable con un número.
Si se hace referencia a una variable que no existe, esta pasara a existir (en el caso de una asignación) o
simplemente sera reemplazada en la expresión por un valor vacío (que generalmente no afecta en la
operación en cuestión).
Ejemplos de definición de variables:
$numero = 3;
$decimal = 8.3;
Carrera Linux 2008 Programacion PHP 4
Ejemplo de operaciones con variables
Existen otros tipos de variables que se utilizan de forma distinta. Entre ellos podemos encontrar los
arreglos. Un arreglo (también conocido como arreglo asociativo, diccionario o hash) es simplemente un
conjunto de elementos. Estos elementos pueden ser tanto variables comunes como otro arreglo. A su
vez, cada elemento esta asociado a una clave (que puede ser tanto numérica como alfabética). En
consecuencia, estos arreglos pueden ser utilizados como vectores en donde las claves se utilizaran como
índices numéricos. Para definir un arreglo usaremos la función array de alguna de las siguientes
formas:
La primer forma crea un arreglo en forma de "vector" en donde el elemento 1 tiene el índice 0, el
elemento 3 tiene el índice 1, el elemento 4 tiene el índice 2, el elemento "Hola" tiene el índice 3 y el
elemento 3.4 tiene el índice 5.
La segunda forma crea un arreglo de forma tal que la clave "Jose" tiene asociado el valor 2, la clave
"Pepe" el 35 y la clave 23 el 42.
Para acceder luego a uno de los valores del vector, solo hace falta conocer la clave que se quiere
acceder y escribirla entre corchetes luego del nombre de la variable. Por ejemplo:
mostrará por pantalla "Hola Mun 2". También se puede modificar (o agregar si no existe) una clave,
asignándole un valor a ella. Por ejemplo:
$arreglo["Yo"] = 24;
agregará una clave al arreglo mientras que
$arreglo["Pepe"] = 22;
modificará el contenido de la ya existente clave "Pepe".
Carrera Linux 2008 Programacion PHP 5
Operadores
Operador de asignación
El operador de asignación es el igual(=). Su misión es la de darle un valor a una variable. Por ejemplo:
$mi_nombre = "Pepe";
$mi_lista = array(1, 2, 3);
$un_numero = (3 + 5) * 4;
Es importante destacar que primero se evalua todo lo que se encuentre a la derecha del igual y luego se
los escribe en la variable especificada. No tendría sentido tratar de asignarlo al revez.
Operadores matemáticos
Estos operadores sirven para realizar operaciones matemáticas básicas. Por ejemplo para sumar dos
números se usa el más (+): 3 + 4
Los operadores básicos son:
Operación Operador
suma +
resta
multiplicación *
división /
módulo %
Operadores de cadenas
Existe un operador para manejar cadenas. Es el de concatenación (.). Este sirve para juntar dos
cadenas (que pueden estar en una variable) en una sola.
Por ejemplo, si se tiene una variable $nombre con el valor "Pepe", entonces "Hola " .
$nombre es lo mismo que "Hola Pepe".
Operadores de comparación
Estos operadores sirven para determinar si dos expresiones responden o no a un criterio (verdadero o
falso). Por ejemplo, para saber si una cadena (o número) es igual a otra se utiliza el operador == y este
dirá si ambas son iguales o no. Todos estos operadores son binarios, por lo tanto, se escriben de la
siguiente forma: expresion1 operador expresion2 y todo esto devolverá verdadero o falso.
Si se tiene una variable $sueldo con el valor 500 entonces $sueldo > 1000 será falso, mientras
que $sueldo <= 500 será verdadero. Estos operadores son:
Carrera Linux 2008 Programacion PHP 6
Operación Operador
Igualdad ==
Mayor que >
Menor que <
Mayor igual que >=
Menor igual que <=
Distinto !=
Operadores lógicos
Estos operadores son similares a los de comparación ya que determinan la veracidad o falsedad de una
o más condiciones. Los operadores mencionados anteriormente generaban condiciones (que $sueldo
> 500 por ejemplo) las cuales pueden ser concatendas para hacer condiciones mas complejas. Para
ello existen 3 operadores.
El primero es el operador and (y) el cual toma dos condiciones. Para que sea verdadera esta nueva
condición, las dos condiciones tomadas deben ser verdaderas. El siguiente cuadro resume todas las
posibilidades de valores que pueden tener dos condiciones:
El segundo operando es el or (o), el cual es similar al and solo que alcanza con que una sola sea
verdadera para que toda la condición sea verdadera. De forma análoga:
El último operando es el not (no) que es la negación. Simplemente cambia el valor de verdad que
tenga una condición.
condición = Valor
V F
F V
Carrera Linux 2008 Programacion PHP 7
Entrada y salida básica
Salida
Para mostrar cosas por la pantalla se utiliza la función echo. Esta recibe una lista con todas las cosas
que debe mostrar. Por ejemplo:
Nota: Cuando en una cadena se pone una barra invertida (\), PHP interpreta el próximo caracter en
forma especial. En el ejemplo anterior, el próximo caracter es la "n" y se interpreta el \n como si fuera
una nueva línea, por lo que los proximos echo imprimirán en la línea siguiente en vez de imprimir al
lado.
Los más comunes son:
Caracter Descripción
\n Nueva línea
\t Tabulación
\\ La barra invertida literalmente (se muestra UNA SOLA barra)
Entrada
Para leer datos del teclado se utiliza la entrada estándar. Para ello debemos leer desde el archivo del
teclado, el cual se llama STDIN. Para leer una línea desde el teclado llamaremos a la función
fgets(STDIN); la cual nos devolverá la próxima línea disponible o bloqueará el programa hasta
que se encuentre una disponible.
Para quitar el ENTER hay que utilizar el operador chop sobre lo leído. Por ejemplo:
$mi_entrada = fgets(STDIN);
$mi_entrada = chop($mi_entrada);
Entonces, si el usuario ingreso "Hola Mundo\n" (el \n se agrega siempre porque es el caracter que
ingresa el usuario para terminar) luego de las dos sentencias escritas, quedará en la variable
$mi_entrada el valor "Hola Mundo"
Ejercicios
1. ¿Que es una variable?
2. ¿Que tipos de datos hay en PHP?
3. ¿Para que sirven cada tipo de operador?
4. ¿Cual es la diferencia entre la funcion fgets y la funcion echo?
5. ¿Que ventajas tiene la programacion de scripts a programar sobre un lenguaje que se compile?
Carrera Linux 2008 Programacion PHP 8
Clase 2 Control del flujo de ejecución
Estructuras de control de flujo
Hasta este punto solo se podían ejecutar una sentencia debajo de la otra hasta que se completará el
programa. Sin embargo, existen algunas estructuras que permiten alterar este comportamiento y obtener
resultados más interesantes.
Estructura de bifurcación
La primera de las estructuras, el if, es la que me permite tomar una decisión sobre si ejecutar o no un
bloque de código dependiendo de una condición:
if(condición) {
sentencia1;
sentencia2;
sentencia3;
...
sentenciaN;
}
Si se cumple condición entonces se ejecutarán todas las sentencias que se encuentren entre las llaves
(que son obligatorias). En caso de que no se cumpla, entonces se seguiran ejecutando las sentencias que
se encuentren por debajo de la última llave del if.
Una condición puede solamente ser Verdadera, se cumple, o Falsa, no se cumple (Ver operadores de
comparación).
Sin embargo, también se puede obligar a ejecutar un bloque de código si no se cumple la condición:
if(condición) {
sentencia1;
sentencia2;
...
sentenciaN;
} else {
sentenciaN+1;
sentenciaN+2;
...
sentenciaM;
}
En este caso, si se cumple la condición se ejecutan las sentencias que van desde el 1 hasta N, y si no
se cumple, las que van desde N+1 hasta M. Para ello se utilizó la palabra else (sino) que nos permite
ejecutar algo si la condición es falsa. Siempre se ejecutará un bloque u otro pero nunca ambos.
Carrera Linux 2008 Programacion PHP 9
Cuando se anidan un if, o sea, poner muchos if uno dentro de otro, el código se hace bastante ilegible.
Para ello existe otra palabra reservada (o conjunción), elseif, que permite juntar un else con un if y
así dejar el código más ordenado:
if(condición) {
sentencia1;
sentencia2;
...
sentenciaN;
} elseif(condicion2) {
sentenciaN+1;
sentenciaN+2;
...
sentenciaM;
} else {
sentenciaM+1;
sentenciaM+2;
...
sentenciaJ;
}
En este caso, solo se ejecutará uno de los tres bloques de código (1 a N, N+1 a M o M+1 a J).
Ejemplos
Ejemplo 1: Leer una temperatura desde el usuario y decir "Hace Calor" si la temperatura es mayor que
30 o "Hace Frio" en otro caso.
Ejemplo 2: Leer una temperatura desde el usuario y decir "Hace Calor" si la temperatura es mayor que
30, si esta entre 20 y 30 mostrar "Esta perfecto" o "Hace Frio" en otro caso.
Estructura while
Esta estructura sirve para iterar sobre una porción de código mientras se cumpla una condición dada:
while(condición) {
sentencia1;
sentencia2;
...
sentenciaN;
}
Las sentencias 1 a la N se ejecutarán mientras condición tenga un valor verdadero. La condición se
controla cada vez que se termine de ejecutar la sentenciaN y allí determinará si debe iterar de nuevo o
no. Por lo tanto un ciclo while puede ejecutarse desde 0 (la condición nunca fue verdadera) hasta
infinito.
Ejemplos
Ejemplo 1: Mostrar la tabla de multiplicar del 7.
$x = 1;
while ($x <= 10) {
echo "$x por 7 = ", $x * 7, "\n";
$x = $x + 1;
}
Ejemplo 2: Leer varias líneas por teclado hasta que se ingrese una línea que contenga solamente un
punto (.). Cada línea leída se debe repetir en pantalla, pero enumerandolas desde 1 en adelante.
$ingreso = fgets(STDIN);
$ingreso = chop($ingreso);
$x = 1;
while($ingreso != '.') {
echo "$x. $ingreso\n";
$x = $x + 1;
$ingreso = fgets(STDIN);
$ingreso = chop($ingreso);
}
Estructura foreach
Esta estructura se utiliza para recorrer un arreglo.
Existen dos estilos de foreach. En el primero, se irán tomando de a uno los elementos del arreglo
Carrera Linux 2008 Programacion PHP 11
indicado, y se irán colocando en la variable indicada luego del as.
La sintaxis sería:
foreach($arreglo as $valor) {
sentencia1;
sentencia2;
...
sentenciaN;
}
Aquí se ejecutarán las sentencias 1 a la N tantas veces como elementos haya en el arreglo. Para cada
iteración existirá una variable llamada $valor que tendrá un valor de la lista.
La segunda forma nos permite no solo obtener el valor, sino también la clave asociada con dicho valor.
Para ello utilizaremos la sintaxis:
De esta forma para cada ciclo se dispondrá de una variable $clave que tiene la clave del elemento que
se este procesando. Además, en $valor estará el contenido del elemento actual. Por lo tanto, al saber
la clave, es posible modificar el arreglo original.
Ejemplos
Ejemplo 1: Mostrar todos los elementos de una lista.
Ejemplo 2: Desde una lista con números calcular la suma de todos ellos.
Ejercicios
1. ¿Cual es la diferencia entre un if y un while?
2. ¿Que es más práctico para recorrer una lista? ¿un while o un foreach?
3. Hacer un programa que dada una lista con numeros, los muestre y diga si cada número es PAR o
IMPAR.
NOTA: un número es PAR si al dividirlo por 2 el modulo da 0 ($numero % 2 == 0)
4. Hacer un programa que dada una lista con numeros, calcular la sumatoria y el promedio de
todos ellos.
5. Hacer un programa que muestre las tablas de multiplicar del 1 al 10 (usando solamente dos
ciclos while)
Clase 3 Archivos de datos
Introducción
Un archivo es simplemente un conjunto de bytes (o caracteres). Los archivos se dividen en dos
categorías: de texto y binarios. Si bien esta división es arbitraria ya que no hay diferencia real entre
ellos, diremos que los archivos de texto son aquellos que podemos leer y "entender" con cualquier
editor de texto (emacs, vi, mcedit, etc) y los archivos binarios son aquellos que presentan caracteres
"raros" cuando se los trata de leer.
Veremos aquí el uso de los archivos de texto.
Por lo general, cuando se lee un archivo se ven varias líneas de texto. Por ejemplo
Querido Mundo:
Hola Mundo, como has estado?
Es razonable pensar que existe alguna forma de expresar que "Hola Mundo" no se escriba al lado de
"Querido Mundo:". A pesar de que no se puede ver, hay un caracter entre estas dos cadenas. Este
caracter es el de nueva línea (el '\n'). Por defecto este es el caracter que le indica a PHP hasta donde
leer cuando se requiere una lectura.
Uso de Archivos
Apertura
Cuando se quiere utilizar un archivo (leer o escribir) primero es necesario decirle al Sistema Operativo
que nos lo "preste" para hacer lo que deseemos.
Para ello existe una función llamada fopen, que tiene la siguiente forma:
Donde $archivo es el nombre de la variable con la cual se hará referencia, dentro del script en PHP,
al archivo que haya sido abierto exitosamente. "nombre_del_archivo" es una cadena que tiene la
Carrera Linux 2008 Programacion PHP 13
ruta y el nombre del archivo.
NOTA: Una vez abierto el archivo se debe usar la variable $archivo para hacer referencia al archivo
dentro del script. nombre_del_archivo es solo una cadena y no se puede ni leer ni escribir desde
o hacia ella.
Como se mencionó antes, el archivo puede ser abierto para leer, escribir o tambien para agregar. Esto se
especifica dentro de la cadena "modo". Esta cadena podrá ser "r" para abrirlo para lectura, "w" para
escritura y "a" para agregar. Por ejemplo, para escribir en el archivo pepe.datos del directorio
actual, la cadena nombre_del_archivo es "./pepe.datos" y el modo "w". Cuando se abre un
archivo para escribir si no existe el archivo, entonces este es creado, y si existe todos los datos son
eliminados. Luego de abierto se comienza a escribir desde el inicio del archivo.
Si la intención no es la de borrar los datos, entonces se debe abrir para agregar. Cuando esto ocurre si el
archivo no existe se crea, y si existe entonces se comienza a escribir desde el fin de datos del archivo sin
borrar su contenido.
Algunos ejemplos de open son:
Puede ocurrir que no se pueda abrir el archivo por diversos motivos. Por ejemplo, si se abre el archivo
para lectura y el archivo no existe o no se tienen los permisos adecuados es un error. Para ello la
función open devuelve verdadero si se pudo abrir y falso en caso contrario.
Para controlar esto podríamos hacer:
Esto controlaría en el if si no se pudo abrir el archivo. En cuyo caso mostraría un mensaje informando
el motivo.
Clausura
Cuando se ha terminado de usar el archivo es necesario cerrarlo para asegurarse que todo haya quedado
guardado. Para ello existe la función close a la cual solo debe especificarsele el descriptor del
archivo. Por ejemplo:
close($archivo);
Carrera Linux 2008 Programacion PHP 14
Lectura
Para leer de un archivo se puede hacer de la misma forma en que se leía desde el teclado (en realidad el
teclado es un archivo). Esto se hace utilizando la misma función fgets. Por ejemplo,
$linea = fgets($archivo);
leerá una línea (hasta e incluyendo el '\n') hasta el delimitador (que por defecto es el '\n' que separa las
líneas). Con cada lectura se avanzará a la próxima línea y cuando no haya más líneas cada lectura
devolverá falso.
Para detectar que se hay llegado al final del archivo existe la función feof. Esta función devolverá
verdadero una vez que se haya leido el fin de archivo (una lectura despues del final del archivo) y falso
en otro caso. Para hacer un programa que muestre el contenido del archivo "mi_archivo.txt" una
solución sería:
Sabiendo que la función fgets devolverá falso una vez que tratemos de leer más alla del final, otra
solución sería:
Escritura
Para escribir en un archivo se utiliza la función fputs. Para ello se debe especificar como primer
parámetro el archivo a utilizar y luego lo que se quiera mostrar. Por ejemplo para guardar los números
del 1 al 10 en un archivo (numeros.txt):
NOTA: La función range nos devuelve una arreglo cuyos valores son los números que comprenden el
intervalo especificado con sus dos parámetros.
Carrera Linux 2008 Programacion PHP 15
Tuberías
Una tubería es ni más ni menos que un archivo. La diferencia esta que en vez de leer desde un archivo
de datos se leerá desde la salida de un comando, o en vez de describir en un archivo de datos, se
escribirá a la entrada de un comando.
Para crear una tubería utilizamos la función popen, que es análoga a open pero en vez de abrir un
archivo, ejecutará el programa especificado. Como diferencia tendremos solo dos modos "r" y "w" ya
que las tuberías son unidireccionales, solo podemos leer o escribir de ellas, pero no ambas cosas sobre
la misma tubería.
Para cerrar una tubería poseemos la función pclose que es igual a close pero cierra una tubería en
vez de un archivo.
Veamos un ejemplo:
Argumentos desde la línea de comandos
Es muy común que un script necesite el usuario le especifique sobre que archivos trabajar o que
modifique alguna conducta específica. Para ello se utilizan los parámetros que se le pasan a los
programas desde la línea de comandos. Por ejemplo el programa ls muestra todos los archivos de un
directorio. Pero si se quiere ver la información detallada de estos se le agrega un argumento ("-l")
para que lo haga.
En PHP todos estos argumentos son accedidos a través del arreglo argv. Este arreglo es creado
automaticamente por PHP y es automáticamente llenado con los argumentos. Para verificar esto se
muestra el programa args.php:
Si se ejecuta ahora:
Mostrará por pantalla:
Carrera Linux 2008 Programacion PHP 16
Ejercicios
1. ¿Que tiene de similar el teclado (STDIN), un archivo y una tuberia?
2. Hacer un programa que genere N numeros aleatorios y los guarde en un archivo uno por linea.
Tanto N como el nombre del archivo se deberan pasar desde la linea de comandos. Para los
numeros aleatorios mirar la ayuda para la funcion rand (buscar la funcion en el sitio de php:
www.php.net).
3. Hacer un programa que lea un archivo ingresado como un argumento desde la linea de
comandos (generado por el programa anterior) y que muestre solo aquellos numeros que sean
PAR.
4. Hacer un programa que lea todas las lineas de un archivo y las imprima nuevamente pero
anteponiendoles cuantas veces se repitieron dentro del mismo.
5. Hacer un programa que reciba tres nombres de archivos desde los argumentos. El programa
debe generar el tercer archivos en base a los dos primeros, intercalando las lineas de ambos.
Clase 4 Expresiones Regulares
Introducción a las expresiones regulares
Una expresión regular es una forma que nos provee PHP (entre otros lenguajes) de verificar, validar y
extraer datos. Esta herramienta se basa en que la entrada tiene un patrón. Esto significa que si bien no
son iguales todas las entradas, todas tienen la misma forma. Por ejemplo, un archivo de log
(/var/log/messages), un archivo de configuración (como /etc/inittab), o un archivo de datos (como /etc/
passwd) entre otros.
Patrones
Los patrones se especificará como una cadena de caracteres común. Estos patrones contaran con
caracteres literales (deben estar literalmente en la cadena que se busca) y otros caracteres especiales
que le dan flexibilidad y generalidad (por ejemplo, decir que debe haber uno o más dígitos).
Para aplicar este patrón sobre una cadena se utiliza la función ereg, en donde el primer parámetro será
el patrón y la segunda la cadena con la cual se quiere comparar. Ademas, ereg devolverá verdadero si la
cadena corresponde al patrón dado o falso en caso contrarior.
Carrera Linux 2008 Programacion PHP 17
Ejemplo:
En este ejemplo, aparecerá por pantalla la primera opción. Cuando se especifica un patrón que consta
solo de literales (ningun caracter especial), se fijará si ese patrón esta en alguna parte de la cadena sin
importar donde este.
El patrón tambien puede ser especificado o contener, variables comunes de tipo cadenas. Para poner el
patrón anterior en una variable el programa quedaría:
Caracteres especiales
Los caracteres especiales son: . * ? + [ ] ( ) { } ^ $ \
Si se quiere que alguno de estos caracteres deba aparecer en la cadena que se esta validando, entonces
se les debe anteponer una barra invertida (\) para que se los interprete como tal.
Límites
La primer restricción que pondremos sobre una expresión regular será los límites principio y fin. Para
ello existe el caracter ^ (principio) y el caracter $ (fin). El ^, si aparece, aparecerá como primer
caracter de la expresión, ya que el principio de la cadena solo puede ocurrir al principio. De forma
análoga será el $. Para saber si una oración termina en punto se podría pregunar:
if(ereg("\.$", $cadena)) {
print "Bien terminada\n";
} else {
print "Mal terminada\n";
}
Esta expresión consta de dos caracteres: el \. que representa un punto literal (este caracter debe estar
en $cadena y debe ser el último de todos) y el caracter $ que indica el fin de la cadena (dentro de cad
no puede haber más caracteres despues del .).
Carrera Linux 2008 Programacion PHP 18
Conjuntos
Hasta ahora solo se usaron caracteres literales, pero también pueden generalizarse. Esto significa que se
puede decir que en cierto punto puede ocurrir, por ejemplo, una letra mayuscula. Para ello se utilizan
los corchetes ( [ ] ). Dentro de los corchetes se pondran todos los caracteres que se permiten. Si se
buscan solo dígitos se usará [0123456789]. Si se quiere verificar que un valor ingresado se un
número de 3 dígitos se podría hacer:
$entrada = chop(fgets(STDIN));
if(ereg("^[0123456789][0123456789][0123456789]$", $entrada)) {
print "Tiene 3 digitos\n";
}
Como se puede apreciar esto es largo, confuso, y poco estetico. Para ello se permite la posibilidad de
definir un rango. Esto significa, que en vez de enumerar todas las posibilidades se puede decir desde un
caracter (0 por ejemplo) hasta cierto otro (9 por ejemplo). El rango se especifica poniendo entre estos
dos valores, un guión (-).
Considerando esto, el ejemplo anterior quedaría:
$entrada = chop(fgets(STDIN));
if(ereg("^[0-9][0-9][0-9]$", $entrada)) {
print "Tiene 3 digitos\n";
}
Si bien esto es mucho más claro, aun no es lo más óptimo. Para ello se definieron algunos rangos que se
usan muy comunmente. Estos rangos poseen un nombre, y se especifica el mismo entre los símbolos
[: y :]. Por ejemplo, el rango [0-9] esta representado por [:digit:] (equivalente a 0-9).
Considerando esto, se puede modificar lo anterior a:
$entrada = chop(fgets(STDIN));
if(ereg("^[[:digit:]][[:digit:]][[:digit:]]$", $entrada)) {
print "Tiene 3 digitos\n";
}
Así como se especifico en un conjunto cuales son los caracteres que se admiten, tambien puede ser
expresado de su forma contraria. Esto es, decir solamente cuales caracteres no se permiten, dejan que
califican en este rango a todos los demas caracteres. Para ello, luego del primer corchete, se debe poner
el acento circunflejo (^), que es el operador que me "niega" los demas caracteres. Por ejemplo si no se
quiere aceptar ningun número se pondría:
if(ereg("[^0-9]", $entrada) {
print "La cadena no tiene ningun numero\n";
}
Si bien esto es posible, es recomendable que siempre que se utilice un conjunto que se especifiquen los
caracteres que si pueden ir, en vez de especificarlo por negación. Esto nos da la seguridad que si la
Carrera Linux 2008 Programacion PHP 19
entrada es válida, entonces la solución esta entre lo que uno planeo. Si en cambio se nego los caracteres
que no se querian, si se olvido de poner alguno o si aparecieron otros caracteres que en el momento de
escribir el programa no existieran, podrian causar efectos raros en nuestro programa.
Entre los conjuntos ya definidos se encuentran:
[:alnum:] [0-9A-Za-z]
[:alpha:] [A-Za-z]
[:digit:] [0-9]
[:blank:] [ \t\n\r]
Repeticiones
Cuando se utiliza expresiones regulares, por lo general, ciertos caracteres se repiten varias veces. Por
ejemplo, si se esta leyendo un archivo que tiene nombres de usuarios, seguidos por un espacio y
seguido por su directorio actual, ocurrirá que los nombres tienen más que un solo caracter (muchos
[:alnum:]). En este ejemplo, tampoco se sabe hasta cuantos caracteres pueda tener el nombre o el
directorio, por lo que no se podría expresar todas las posibilidades. Aquí es donde entran las
repeticiones.
Cero o una repetición
Si se quiere poner algo como opcional, querra decir que cierto caracter puede o no estar. Para ello existe
el caracter especial ?. Este operador permite que el caracter anterior este o no. Por ejemplo, si se esta
leyendo líneas como las descriptas anteriormente, entradas posibles serían:
root /root
usuario /home/usuario/
Como se puede apreciar, los directorios no tienen la misma forma, ya que uno termina con / y el otro
no. Entonces esta barra (/) es opcional. En nuestra expresión regular aparecerá un /?. El ? permitirá
que ese caracter este o no este. Gracias a esto ambas entradas son válidas.
una o más repeticiones
Si consideramos el ejemplo anterior, para validar el nombre del usuario haria falta poder expresar que
debe haber por lo menos un caracter, y que luego pueden sucederlo varias mas. Para ello existe el
operador más (+). Este operador permite que el caracter o expresión que lo precede se repita 1 o más
veces. Dentro de la expresión regular, para validar al nombre, aparecerá al principio ^[[:alnum:]]+
donde el ^ representa el inicio de la cadena, [[:alnum:]] es cualquier caracter alfanumérico y el +
hace que se pueda repetir el [[:alnum:]] una o más veces.
Carrera Linux 2008 Programacion PHP 20
cero o más repeticiones
Si existe la posibilidad de que todo un campo pueda estar vacío, entonces en vez de necesitar que algo
se repita una o más veces, se necesitará que se repita ninguna o más veces. El "ninguna" es el que le da
la categoria de opcional. Por ejemplo, el archivo de usuarios (/etc/passwd) tiene algunos campos que
son opcionales (como el campo GECOS contiene información superflua, como el nombre real del
usuario). El operador que me permite hacer esto es el asterisco (*). De esta forma, en la expresión
regular aparecerá un [[:alnum:]]* donde [[:alnum:]] es un caracter que, por el asterisco, se
podrá repetir cero o más veces.
Rango de repeticiones
Las repeticiones anteriores eran indefenidas, esto es, no tenían un limite establecido. Puede ocurrir que
se necesite que un caracter este un número específico de veces o que este dentro de un rango. Si se
quiere validar un número de 3 dígitos, haría falta que el set [[:digit:]] se repita tres veces
([[:digit:]][[:digit:]][[:digit:]]). También puede especificarse una sola vez que
caracter se quiere que se repita y decir cuantas veces se debe repetir. Para indicar las repeticiones estas
se deben especificar entre llaves ( {} ). Para el caso anterior sería [[:digit:]]{3}. Que pasaría si
el número de 3 dígitos puede tener valores que solo sean de dos dígitos (ya que el 099 sería lo mismo
que poner 99). Para ello se puede decir que haya entre 1 y 3 dígitos. De esta forma estarian
contempladas todas las posibilidades. Para especificar un rango también se usan las llaves y entre ellas
se pondra el limite inferior seguido de una coma y seguido del limite superior. En nuestro ejemplo sería
[[:digit:]]{1,3}.
La repetición puede imitarse poniendo tantas veces como se necesite el caracter, pero el rango de
repeticiones no puede ser imitado de esta forma, por lo que lo hace necesario conocerlo.
También es posible no especificar uno de los limites. PHP interpretará que llendo para el limite que no
se especifico, puede tomar cualquier valor. Entonces, si se escribe [[:digit:]]{,3} (no se
especifico el limite inferior), podrá haber entre 0 y 3 dígitos. Y [[:digit:]]{2,} (no se especifico
el limite superior) significa que puede haber 2 o más dígitos.
Recuperar partes de la cadena
Cuando se aplica una expresión regular a una cadena se fija si esta cadena concuerda con el patrón
especificado. Si hay un patrón, entonces debe haber información útil mezclada con alguna forma de
expresar toda esta información para que se entendible por algo o alguien. Las expresiones regulares en
PHP nos permiten recuperar esta información útil desde la cadena. Para lograr este comportamiento las
partes de la expresión regular que se quieran obtener como variables se deben especificar entre
paréntesis.
Desde PHP sera necesario agregar un parámetro más a la llamada a ereg. Este será el nombre de un
arreglo que podemos usar. Luego de la llamada, quedará a partir de la posición 1 el primer juego de
paréntesis, en la posición 2 el segundo y asi sucesivamente.
Veamos un ejemplo práctico: El archivo /var/log/messages es un archivo de log que registra todas las
Carrera Linux 2008 Programacion PHP 21
acciones realizadas por los programas. Una entrada de este archivo en mi máquina es:
El formato de una entrada es (en este orden):
El comienzo de la cadena
3 letras que identifican el mes
1 o mas espacios
El dia en que se registro la operacion (pueden ser 1 o dos digitos)
La hora en que se registro la operacion separando las horas,
minutos y segundos con un :
El nombre del host
Una cantidad de caracteres hasta el un (puede haber espacios) : que
representan el programa (o proceso) que genero ese registro
1 :
Una cantidad indefinida de caracteres que muestran un mensaje que
informa el problema o exito detectado (incluido el \n).
Fin de la cadena.
El objetivo de este programa será mostrar por pantalla solo aquellas entradas que pertenezcan a un mes
y día especifico. La salida deberá indicar la hora y el mensaje de cada entrada.
El programa:
$patron = "^$mes".
"[[:blank:]]+".
"$dia".
"[[:blank:]]+".
"([[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2})".
"[[:blank:]]+".
"[[:alnum:]]+".
"[[:blank:]]+".
"[][[:alnum:].]+".
":".
"(.+)$";
while($linea = chop(fgets($log))) {
if(ereg($patron", $linea, $reg) {
Carrera Linux 2008 Programacion PHP 22
Lo único complejo de este programa es el patrón utilizado en el if. Veamosla por partes.
Al principio esta el ^ que indica que lo que sigue debe estar al principio de la cadena. En este caso se
utiliza la variables mes que posee el mes, que el usuario ingreso por teclado, que se quiere buscar (el
mes se escribe en ingles las primeras 3 letras).
Seguido del mes se especifica que puede haber 1 o más espacios ([[:blank:]]+). Luego aparece el
día que se quiere buscar, que se encuentra en la variable día (que ingreso el usuario).
Hasta aqui hace que la expresión concuerde con la fecha que el usuario quiere buscar. Esta es la unica
parte que cambia entre distintas ejecuciones del programa.
Luego aparece nuevamente los espacios ([[:blank:]]+). Según el formato del archivo de log, lo
siguiente es la hora con el formato dos dígitos dos puntos dos dígitos dos puntos dos dígitos
([[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2}). Como esto es parte de lo que nos
interesa mostrar lo escribimos dentro de paréntesis. De esta forma si la cadena concuerda con la
expresión regular, quedará guardado en la variable $reg[1] (por ser el primer grupo de paréntesis) la
hora.
Despues de la hora hay espacios ([[:blank:]]+), el nombre del host ([[:alnum:]]+) y más
espacios ([[:blank:]]+).
Luego viene el nombre del programa. Aquí pueden aparecer caracteres como los corchetes ( [] ), el
punto, el espacio o cualquier caracter alfanumérico. Para se hace un conjunto que contenga a todos
ellos (los corchetes por ser los que delimitan los conjuntos se deben escribir al comienzo), este conjunto
se escribe como [][[:alnum:].]. Y como todo eso se puede repetir 1 o más veces se le pone luego
un más (+).
Luego viene el dos puntos (:) literal, y luego puede haber cualquier cosa hasta el fin de la cadena.
Existe un caracter especial que concuerda con cualquier caracter. Este caracter es el punto (.).
Especialmente útil en esta ocasión, el punto seguido del más concuerda con cualquier cosa que haya
luego del punto. Como todo esto representa al mensaje que se esta buscando y es parte de lo que nos
interesa obtener el .+ se encierra entre paréntesis. De esta forma quedará en la variable $reg[2] la
cadena con el mensaje de log.
Finalmente se encuentra el fin de cadena que es donde termina la expresión regular.
Dentro del if solo se imprime la fecha (que estaba en $reg[1]) y luego el mensaje (que estaba en
$reg[2]).
Un ejemplo de la salida reducida es (si se ingreso como mes May y como día 6):
Partiendo y juntando cadenas
Si se posee una cadena, como una entrada del archivo /etc/passwd, que tiene campos separados por
delimitadores (en ese ejemplo el :), se puede separar esta cadena por campos para poder utilizar
aquellos que nos sean de interes. Para ello existe una función que despedaza una cadena en una lista,
donde cada elemento de la lista es un campo. Esta función se llama explode y lleva dos parámetros.
El primero es una cadena que específica el delimitador que se quiere usar y el segundo parámetro es la
cadena que se quiere romper. explode devolverá luego una lista con todos los campos.
Para el ejemplo del /etc/passwd:
$entrada = "root:x:0:0::/root:/bin/bash";
$campos = explode(":", $entrada);
Esto dejará en $nueva_salida la cadena "root#x#0#0##/root#/bin/bash".
Ejercicios
1. ¿Que es un patron y para que puede ser usado?
2. Hacer un programa que permita ingresar numeros (positivos y negativos) por teclado y los
valide. Para ello se debera usar una expresion regular. Se considerara un numero solo aquellas
entradas que posean digitos unicamente (sin espacios). Aquellas entradas que no sean numericas
deberan ser impresas en la salida de error estandar (STDERR).
3. Se posee un archivo con palabras (una por linea) que representa todas las palabras que hay en un
diccionario de español (dict.txt). Se pide hace un programa que le pida al usuario una
terminacion y que busque en dicho diccionario todas aquellas palabras que tengan esa
terminacion. Tanto la terminacion como el archivo de palabras se debera poder pasar como un
argumento desde la linea de comandos
4. El comando who -u muestra a los usuarios que estan conectados, en que terminal, en que
Carrera Linux 2008 Programacion PHP 24
fecha y hora, y cuanto tiempo estuvieron inactivos. Considerando que la ultima columna
muestra cuanto tiempo estuvieron inactivos (los que estan activos tiene un .), se pide hacer un
programa que muestre cual es el usuario que mas tiempo sin hacer nada.
5. El archivo /proc/meminfo posee informacion sobre la memoria. De este archivo se pide extraer
el valor asociado a MemFree y a MemTotal (Memoria libre y Memoria total
respectivamente). Luego el programa debera informar que porcentaje de memoria esta libre en
ese momento.
5 Funciones y módulos
Funciones
Una función es una agrupacion de sentencias, decisiones, y ciclos que realizan una tarea común. Estos
nos trae varios beneficios:
1. Reutilización: Una función puede ser usada varias veces sin necesidad de reescribirla cada vez
que haya que usarla.
2. Abstracción: Cuando una función esta hecha, ya no importa como es que lo hace sino que es lo
que hace. De esta forma nos permite concentrarnos en el problema más grande, dejando de lado
los detalles de la implementación.
3. Menos errores: Al separar el programa en partes más pequeñas es más fácil ubicar y corregir
los errores. Además, una función bien hecha ya no posee errores, y cuando se reutilize habra
menos errores en el campo general.
Una función puede depender de algunos parámetros de entrada. Si por ejemplo tenemos una función
que calcula el factorial de un número, será necesario pasarle a la función sobre que número se quiere
trabajar. La cantidad de argumentos puede ir desde cero hasta los que se quiera.
Tambien una función puede devolver un valor. En el ejemplo anterior, será necesario que la función
devuelva el factorial calculado.
En PHP para definir una función utilizaremos la palabra reserva function seguida del nombre de la
función, su argumentos y el bloque de código correspondiente.
En general sería:
Los argumentos se definen como variables normales, y pueden tomar cualquier valor, desde una cadena
hasta un array.
Para devolver un valor se llama a la funcion return seguida del valor a devolver.
Cuando se define una función, el código que de la misma no se ejecuta. Solo se ejecutará si se llama a
la función (como cuando se hacia con rand). Para llamar a una función pondremos el nombre de ella y
seguido y entre paréntesis sus argumentos (si no hay argumentos se escribira solamente los paréntesis).
Carrera Linux 2008 Programacion PHP 25
Veamos un ejemplo: La definición del a función será:
function factorial($numero) {
$fact = 1;
while($numero > 0) {
$fact = $fact * $numero;
$numero = $numero - 1;
}
return $fact;
}
Luego en alguna parte del código veremos un llamada del estilo:
$x = factorial(4);
En este caso, $x tendrá el valor 24 (4!).
Aclaración: Las variables que se definen dentro de una función, existen solamente dentro de la misma
y no afectará a variables que tengan el mismo nombre y se encuentren afuera de la función.
Ejemplo integrador
Para ejemplificar el pasaje y devolución de valores haremos dos funciones: una que nos diga si un valor
está o no dentro de un arreglo. Y otra que nos diga cual es el mayor valor dentro de un arreglo.
El código del primer ejemplo será:
Esta función tomará dos parámetros: el elemento a buscar y un arreglo en donde hacerlo. Luego
devolverá verdadero si lo encuentra o falso si no lo encuentra. Para ello, irá recorriendo el arreglo y
preguntando cada elemento contra el valor a buscar. Si lo encuentra, entonces devuelve verdadero y la
función termina (no se siguen consultando los demas valores).
Si se termino de recorrer el arreglo, entonces no se ha encontrado el elemento y se devolverá falso.
Si ejecutamos:
se mostrará por pantalla el mensaje del echo.
Carrera Linux 2008 Programacion PHP 26
El código de la segunda función es:
function buscarMayor($arreglo) {
$indiceMayor = $0;
$valorMayor = $arreglo[0];
foreach($arreglo as $indice => $valor) {
if($valor > $valorMayor) {
$indiceMayor = $indice;
$valorMayor = $valor;
}
}
return array("INDICE" => $indiceMayor, "VALOR" => $valorMayor);
}
En este caso se le pasará a la función un arreglo y esta nos devolverá otro arreglo con dos datos: el
índice del mayor elemento, y el valor del mismo.
Para buscar al mayor iremos guardando en una variable el mayor valor encontrado al momento de
recorrer el arreglo (comenzando con que el primero es el mayor). Entonces si encontramos que un valor
del arreglo ($valor) es más grande que el que teniamos guardado ($valorMayor), lo
reemplazamos por el nuevo (al igual que al índice).
Al terminar el ciclo, en $valorMayor quedará el valor más grande y en $indiceMayor su índice.
Una llamada a esta función podría ser:
Valores por defecto
Cuando se le pasan argumentos una función se le deben pasar la misma cantidad de argumentos con la
que fue definida.
Sin embargo, es posible darle valores por defecto. Si a un parámetro se le da un valor por defecto,
entonces no es obligatorio especificarlo, y en el caso de no hacerlo, se usará el valor que tenga por
defecto.
Ejemplo:
factorial();
Carrera Linux 2008 Programacion PHP 27
En esta caso al darle como valor por defecto 26, se puede llamar a la función sin parámetros. Por lo
tanto, al llamarla de este modo, se calcularía el factorial de 26.
Como última aclaración diremos que los parámetros que tengan valores por defecto serán los que
aparezcan últimos en el momento en que se define la función.
Recursividad
El concepto de recursividad es simplemente hacer que una función se llame a si misma. Esto es útil
cuando se necesita hacer un proceso que requiere hacer subprocesos que sean iguales a él. Por ejemplo,
el recorrer toda una jerarquía de directorios. Recorrer un subdirectorio es lo mismo que recorrer el
directorio actual, y así sucesivamente. El clásico ejemplo es el de calcular el factorial. El factorial de un
número n, es igual al producto de si mismo por todos los demas que lo preceden hasta el 0 (o sea, el
número multiplicado por el factorial del anterior). Y además, el factorial de 0 es 1.
Una función que calcule el factorial de un número n sería:
function factorial($n) {
if($n == 0) {
return 0;
}
return $n * factorial($n - 1);
}
Módulos
Una vez que tengamos muchas funciones, vamos a necesitar utilizarla desde otros scripts. Sería muy
incomodo tener que estar abriendo el archivo que tiene la función, copiarla y pegarla en el nuevo.
Además si se modifica en algun lado la función habría que buscar todos los archivos que la tengan
definida y modificarlos también.
Lo mejor es tener todas las funciones que se puedan utilizar por varias páginas en archivos separados, y
"traer" estos archivos a nuestro PHP. Esto se logra con la construcción require_once. Si por
ejemplo tenemos un archivo utils.php que tiene definida todas las funciones generales, podemos
traer todas estas funciones a nuestro archivo actual de la siguiente forma:
require_once("utils.php");
Con solo agregar esta línea al principio del programa tendremos disponibles todas las funciones que se
encuentre allí.
Existe otra construcción que es muy útil llamada include. include se diferencia de require_once en que
include trae todo el archivo y lo reemplaza en donde se encuentre la llamada. Por lo tanto escribir:
include("error.php");
sería idéntico a copiar y pegar todo el contenido de error.php en donde se encuentra el include.
Carrera Linux 2008 Programacion PHP 28
Esta construcción será más útil cuando se vea la programación web ya que servirá para redireccionar a
otra página haciendo un include de la misma.
Otra diferencia entre require_once e include es que la primera se ejecuta siempre,
independientemente de donde se haya escrito y la segunda se ejecuta solo si la ejecución pasa por allí.
Ejercicios
1. Enuncie cuales son las ventajas de utilizar funciones
2. Hacer una funcion (elegir_opciones) que se le pasen varias cadenas (cada una de ellas es
una opcion) dentro de un arreglo. Esta funcion debe mostrarle al usuario todas las opciones
disponibles y luego debe permitirle elegir una de ellas. Si el usuario ingresa algo que no esta
contemplado en esas opciones debe pedirle que ingrese una opcion nuevamente (tambien le
muestra las opciones nuevamente. Por ejemplo, la llamada:
elegir_opciones (array("agregar", "borrar", "consultar", "salir"));
debe producir una salida similar a esta:
agregar
borrar
consultar
salir
Ingrese su opcion:
Si el usuario no ingresa ninguna de esas cuatros palabras la salida debe repetirse y tambien la
entrada.
3. Realizar una subrutina que devuelva una lista con todos los usuarios cuyo UID sea menor que
500 (privilegios de administrador. Luego realizar otra funcion que tomando esta lista como
parametros, lea desde otro archivo varios nombres de usuarios y devuelva una lista con aquellos
que no se encuentren alli.
4. Realizar una subrutina que se le pase por parametro el nombre de un servicio (ejemplo, "ftp",
"http", etc) y devuelva el puerto al que esta asociado. Para ello, debera obtener la informacion
desde el archivo /etc/services.
Se debe investigar como es el formato del archivo /etc/services y se debe crear la expresion
regular (una sola) que lo represente.
5. Hacer una subrutina que implemente lo inverso de la anterior. Debe obtener por parametro un
puerto y luego debe devolver una cadena con el servicio asociado.
Clase 6 Manejo de archivos y directorios
Introducción
Existen algunas funciones para trabajar sobre archivos y directorios en el sistema. Estas funciones no
Carrera Linux 2008 Programacion PHP 29
requieren de comandos externos sino que se comunican directamente con el Sistema Operativo para que
las haga.
Directorio Actual
La función getcwd devuelve una cadena con el directorio actual. Esta función no lleva parametros.
Ejemplo:
mostrará por pantalla un mensaje informando el directorio actual.
Cambio de directorio
La función chdir cambia el directorio actual al que se le especifique por parámetro.
Por ejemplo:
chdir("/usr/bin");
cambiará el directorio actual a /usr/bin.
Creación de un directorio
La función mkdir crea un directorio. Esta función lleva como primer parámetro el directorio que se
quiere crear y como segundo parámetro (opcional) los permisos que se quieren otorgarle (NOTA: para
escribir un valor en octal para usarlo de la misma forma en que se usa el chmod, el número debe
empezar con 0).
Por ejemplo:
mkdir("/home/pepe");
le crea el directorio personal al usuario pepe.
mkdir("/home/pepe", 0700);
le crea el directorio personal al usuario pepe con los permisos 700.
Eliminación de un directorio
Para eliminar un directorio se utiliza la función rmdir. Para poder llevar a cabo esta acción el diretorio
debe estar vacío. Esta función solo lleva un parámetro que indique el directorio que se desea eliminar.
Por ejemplo:
rmdir("/home/pepe");
Carrera Linux 2008 Programacion PHP 30
Le quita el directorio personal al usuario pepe.
Copiado de un archivo
La función copy sirve para hacer una copiar de un archivo. Esta función lleva de parámetros el nombre
del archivo que se quiere copiar y el nombre del nuevo archivo. Si el nombre del nuevo archivo ya
existe, entonces se perderán los datos del mismo.
Por ejemplo:
copy("backup.tgz", "backup-2003-04-22.tgz");
Renombrar un archivo
La función rename sirve para cambiarle el nombre a un archivo. Esta función lleva de parámetros el
nombre del viejo archivo y el nombre del nuevo archivo. Si el nombre del nuevo archivo ya existe,
entonces se perderán los datos del mismo.
Por ejemplo:
rename("backup.tgz", "backup-2003-04-22.tgz");
Eliminación de archivos
Para llevar a cabo esta tarea existe la función unlink. Esta función lleva como parámetro el archivo
que se quiere eliminar.
Por ejemplo:
unlink("backup.tgz");
Cambio de permisos
Es posible modificarle los permisos a un archivo de forma similar a utilizar el comando chmod. Para
ello existe una función del mismo nombre, la cual lleva como parámetros el nombre del archivo y los
nuevos permisos (los permisos igual que con mkdir).
Ejemplo:
chmod("/home/mi_dir/solo_yo_lo_leo", 0700);
le da los permisos 0700 a al archivo "solo_yo_lo_leo".
Cambio de dueño
Es posible modificar el dueño a un archivo de forma similar a utilizar el comando chown. Para ello
Carrera Linux 2008 Programacion PHP 31
existe una función del mismo nombre, la cual lleva como parámetros el nombre del archivo y el nombre
del nuevo dueño.
Solo el superusuario puede cambiar los dueños de todos los archivos.
Ejemplo:
chown("/home/mi_dir/solo_yo_lo_leo", "demian");
le otorga el archivo "solo_yo_lo_leo" al usuario "demian".
Cambio de grupo
Es posible modificar el grupo a un archivo de forma similar a utilizar el comando chgrp. Para ello
existe una función del mismo nombre, la cual lleva como parámetros el nombre del archivo y el nombre
del nuevo grupo.
Solo el superusuario puede cambiar los grupos de todos los archivos.
Ejemplo:
chgrp("/home/mi_dir/solo_yo_lo_leo", "nobody");
le otorga el archivo "solo_yo_lo_leo" al grupo "nobody".
Separar directorio/archivo de una ruta completa
Si se posee la ruta completa a un archivo existen dos funciones para obtener estos datos por separados.
La primera es dirname la cual devuelve el directorio y la segunda es basename la cual devuelve el
nombre del archivo.
Ejemplo:
$archivo = "/etc/X11/XF86Config";
echo "Archivo: ", basename($archivo), "\n";
echo "Directorio: ", dirname($archivo), "\n";
Esto generará las siguientes líneas:
Archivo: XF86Config
Directorio: /etc/X11
Carrera Linux 2008 Programacion PHP 32
Información sobre archivos
is_writeable
Esta función toma como parámetro el nombre de un archivo y devuelve verdadero si el archivo tiene
permiso de escritura.
is_readable
Esta función toma como parámetro el nombre de un archivo y devuelve verdadero si el archivo tiene
permiso de lectura.
is_executable
Esta función toma como parámetro el nombre de un archivo y devuelve verdadero si el archivo tiene
permiso de ejecución.
is_dir
Esta función toma como parámetro el nombre de un archivo y devuelve verdadero si el archivo es un
directorio.
is_file
Esta función toma como parámetro el nombre de un archivo y devuelve verdadero si el archivo es un
archivo normal.
is_link
Esta función toma como parámetro el nombre de un archivo y devuelve verdadero si el archivo es un
link.
file_exists
Esta función toma como parámetro el nombre de un archivo y devuelve verdadero si el archivo existe.
filesize
Esta función toma como parámetro el nombre de un archivo y devuelve el tamaño (en bytes) del archivo
especificado.
Carrera Linux 2008 Programacion PHP 33
fileowner
Esta función toma como parámetro el nombre de un archivo y devuelve dueño (UID) del archivo.
filegroup
Esta función toma como parámetro el nombre de un archivo y devuelve grupo (GID) del archivo.
fileatime
Esta función toma como parámetro el nombre de un archivo y devuelve la fecha (en formato timestamp)
del último acceso a ese archivo.
filemtime
Esta función toma como parámetro el nombre de un archivo y devuelve la fecha (en formato timestamp)
de la última modificación a ese archivo.
filectime
Esta función toma como parámetro el nombre de un archivo y devuelve la fecha (en formato timestamp)
del último cambio al inodo correspondiente al archivo.
stat
Esta función toma como parámetro el nombre de un archivo y devuelve un arreglo con toda la
información obtenida por las funciones anteriores.
Listado de Archivos y Directorios
Existe dos formas para obtener todos los archivos y subdirectorios que existan dentro de un directorio.
Glob
La primer opción es la función glob. Esta función tiene como argumento el directorio y los archivos
que se quieren listar. En esta función se especifican de la misma forma que hace el shell. Esto significa
que el caracter * y el ? no seran interpretados literalmente sino que el * concordará con cualquier tipo
y cantidad caracteres y el ? concordará con un solo caracter cualquiera.
glob me devolverá una lista donde cada elemento es el nombre de uno de los archivos encontrados.
glob omite por defecto todos los archivos y directorios que comienzen con un punto (.).
Por ejemplo, para obtener todos los archivos jpg de mi directorio imágenes:
$archivos = glob("./imagenes/*jpg");
foreach($archivos as $archivo) {
echo "$archivo\n";
Carrera Linux 2008 Programacion PHP 34
opendir, readdir, closedir
La segunda opción es similar al uso de archivos. Esta consta en abrir el directorio, leer de el todos los
archivos y subdirectorios y luego cerrarlo. Para la primera operación se utiliza la función opendir
que es análoga a fopen. Esta función devuelve un descriptor de directorio (nombre de la variable con
la cual se va a hacer referencia el directorio en mi programa en PHP) y luego una cadena con el
directorio que se quiere ver.
Luego la función readdir va devolviendo por cada llamada un archivo. Por defecto, la función
readdir no ignora (como lo hacia glob) el directorio . (directorio actual) y el .. (directorio padre).
Como parámetro para readdir se debe utilizar un descriptor abierto con la función opendir.
Una vez leídos todos los archivos se cierra el directorio con closedir.
Ejemplo:
$dir_h = opendir("/etc");
while($archivo = readdir($dir_h)) {
echo "$archivo\n";
}
closedir($dir_h);
Argumentos desde la línea de comandos
Cuando ejecutamos nuestros scripts es posible recuperar los argumentos pasados al mismo desde la
línea de comandos. Para ello, existe un arreglo llamado argv, el cual se crea y lo completa
automaticamente por PHP. Este arreglo contendrá en la posición 0 el nombre del script y en las
posiciones siguientes tendrá todos los argumentos que restan.
Por ejemplo, si ejecutamos nuestro scripts de la siguiente forma:
El vector argv tendrá:
0 ./mi_programa
1 -v
2 -f
3 datos.txt
4 Hola Mundo
De esta forma es posible recuperar todos los argumentes.
También existe una variable llamada argc la cual contiene la cantidad de elementos que hay en el
arreglo argv (en este caso 5).
Carrera Linux 2008 Programacion PHP 35
getopt
Si estamos interesados en que nuestro comando tome argumentos del estilo seguido de una letra (o
seguido de una letra y un valor asociado a esa opción), disponemos de una función que interpreta al
arreglo argv de manera de facilitarnos el reconocimiento de este formato.
A esta función se le debe proveer una cadena la cual consistirá de las letras que deseemos que se
reconozcan como opciones válidas. Aquellas que posean un valor asociado se le debes poner un :
despues de la letra.
Luego, esta función devolverá un arregla en donde las claves serán las opciones ingresadas, y como
valor tendrá falso en el primer caso y el argumento asociado en el segundo.
Por ejemplo:
$ops = getopt("xhf:");
if(isset($ops["x"])) {
echo "Esta activada la opcion X\n";
}
if(isset($ops["h"])) {
echo "Esta activada la opcion H\n";
}
if(isset($ops["f"])) {
echo "Esta activada la opcion F\n";
}
En este ejemplo solo se aceptan las opciones h, x, y f (esta posee un valor asociado). Si ejecutamos el
script: ./mi_prog -x -f hola mostrará por pantalla:
Vale destacar que al poner falso en las variables que estan activadas (el valor asociado es falso, pero la
entrada en el arreglo esta definida) se debe utilizar la función isset para determinar si esa posición
esta o no elegida.
Ejercicios
1. ¿Cual es la diferencia entre opendir/readir/closedir y glob?
2. Hacer un programa que liste todos los archivos de un directorio (especificado como un
argumento desde el shell) ordenados alfabeticamente. El programa debera mostrar todos los
archivos del directorio especificado y tambien todos aquellos que existan dentro de algun
subdirectorio del mismo.
3. Hacer un programa que haga una copia de un directorio (especficado como un argumento desde
el shell) a otro directorio (tambien especficado como un argumento desde el shell). Luego de la
operacion ambos directorios deberian ser identicos.
NOTA: se deberan copiar todos los archivos del directorio como asi todos los existentes en
subdirectorios del mismo.
4. Hacer un programa que nos indique cuanto (por parametro se debe especificar si verlo en bytes,
Carrera Linux 2008 Programacion PHP 36
kilobytes, megabytes, gigabytes, etc) espacio se esta utilizando para cada usuario en el sistema.
5. Hacer un programa que guarde en un archivo de texto plano todas las entradas de un directorio
dado (junto con el tamaño del archivo). Luego se debera generar otro programa que compare el
contenido de ese archivo con el estado actual en el disco.
El programa debera alertar tanto en el caso que se encuentre una entrada que esta en el archivo y
no este en el disco, como asi tambien entradas que esten en el disco pero no esten en nuestro
archivo de texto. Tambien se debera alertar si el tamaño ha variado.
Clase 7 Biblioteca estándar de funciones
Manejo de cadenas
addslashes
Esta función sirve para escapar las comillas dentro de una cadena. Esto será especialmente útil cuando
se utilicen consultas dentro de una base de datos.
Si poseemos la cadena "Hola O'Reilly", si la pasamos por addslashes obtendremos otra cadena
que tendrá la forma "Hola O\'Reilly".
Ejemplo:
chop rtrim
Elimina los espacios en blanco del final de una cadena.
Ejemplo:
$linea = fgets(STDIN);
$lineaLimpia = chop($linea); #Elimino el \n y todos los blancos que haya ingresado
el usuario
str_replace
Esta función nos permite hacer reemplazo dentro de una cadena. Teniendo una cadena de origen,
podemos reemplazarla parte de la misma por una cadena a voluntad.
Su prototipo es:
Por ejemplo:
$cadena = "aaaBBBccc";
$cadenaNueva = str_replace("BBB", "bbb", $cadena);
echo "$cadenaNueva\n"; # Mostrara aaabbbccc
strlen
Esta función nos devuelve la cantidad de caracteres que posee una cadena.
Ejemplo:
strtoupper strtolower
Estas funciones sirven para transformar toda una cadena a mayúsculas o a minúsculas, respectivamente.
Por ejemplo:
ucfirst
Esta función pone en mayúscula el primer caracter de una cadena.
Por ejemplo:
ucwords
Esta función pone en mayúscula el primer caracter de cada palabra dentro de una cadena.
Por ejemplo:
wordwrap
Esta función corta a una cadena en caracteres de como maximo un tamaño, especificados por
Carrera Linux 2008 Programacion PHP 38
parámetro, agregando un separador entre las palabras que excedan ese límite.
Por ejemplo:
y en $nuevaCadena quedará:
Este es un mensaje\n
de prueba, para\n
cortarlo y ver que\n
queda.\n
Manejo de arreglos
array_merge
Esta función fusiona muchos arreglos pasados como argumentos en un único arreglo. Si los arreglos a
fusionar tienen claves repetidas, entonces se tomará el valor de la última aparición. Si son númericas se
agregarán todos al final.
Por ejemplo:
array_pop
Devuelve el último elemento de un arreglo, y lo elimina del mismo. Si el arreglo esta vacío, devolverá
vacío.
Ejemplo:
array_push
Agrega un elemento al final del arreglo.
Ejemplo:
NOTA: Usar array_push es lo mismo que utilizar los corchetes vacíos ([]) de la siguiente forma:
$arreglo[] = 29;
array_shift
Devuelve el primer elemento de un arreglo, y lo elimina del mismo, reduciendo la cantidad de
elementos en uno. Si el arreglo esta vacío, se devuelve vacío.
Ejemplo:
array_unshift
Esta función agrega un elemento al principio del arreglo, desplazando a los demás elementos.
Ejemplo:
count
Devuelve la cantidad de elementos de un arreglo.
Ejemplo:
in_array
Esta función nos permite buscar un elemento dentro de un arreglo. Si lo encuentra nos dirá verdadero,
Carrera Linux 2008 Programacion PHP 40
sino falso.
Toma dos parámetros, el primero es el elemento a buscar, y el segundo el arreglo.
Ejemplo:
array_search
Esta función nos permite buscar un elemento dentro de un arreglo. Si lo encuentra nos devolverá la
clave asociada al mismo o falso si no lo encuentra.
Toma dos parámetros, el primero es el elemento a buscar, y el segundo el arreglo.
Ejemplo:
sort
Ordena todos los elementos de un arreglo de menor a mayor. Además asignará indices nuevos a cada
valor, por lo que cualquier índice o clave existente se perderá.
Ejemplo:
asort
Ordena todos los elementos de un arreglo de menor a mayor, manteniendo la relación entre las claves y
sus valores.
Ejemplo:
$arreglo = array("pepe" => 26, "anibal" => 23, "emilio" => 30);
asort($arreglo);
# quedara ("anibal" => 23, "pepe" => 26, "emilio" => 30)
Carrera Linux 2008 Programacion PHP 41
ksort
Ordena los elementos de un arreglo, de menor a mayor, según las claves.
Ejemplo:
$arreglo = array("pepe" => 26, "anibal" => 23, "emilio" => 30);
ksort($arreglo);
# quedara ("anibal" => 23, "emilio" => 30, "pepe" => 26)
rsort
Análoga a sort, pero ordenandor de mayor a menor.
arsort
Análoga a asort, pero ordenando de mayor a menor.
krsort
Análoga a ksort, pero ordenando de mayor a menor.
Manejo de fecha
time
Esta devuelva la fecha/hora actual con el formato timestamp de UNIX. Este formato se cuenta como la
cantidad de segundos desde el Epoch de UNIX (1 de Enero de 1970 a las 00:00:00).
Ejemplo:
$timestampActual = time();
date
Esta función sirve para darle formato a una fecha en formato timestamp. Posee dos argumentos, el
primero es el formato y el segundo la fecha en cuestión (si solo se usa un parámetro se tomará por
defecto la fecha actual).
La cadena del formato es una cadena normal, en donde algunos caracteres serán reemplazados por el
campo de la fecha correspondiente. Entre los más comunes encontramos:
Caracter Descripción
d Día. 0031
m Mes. 0012
Carrera Linux 2008 Programacion PHP 42
Y Año 4 dígitos. AAAA
y Año 2 dígitos. AA
H Hora. 0023
i Minutos. 0059
s Segundos. 0059
Ejemplo:
# Dia actual
$dia = date("d");
checkdate
Controla si una fecha es válida (Año bisiesto, días incorrectos, etc). Posee 3 parámetros: mes, dia y año.
Ejemplo:
Ejercicios
1. Hacer un programa que lea desde STDIN tantas lineas como haya. Luego las debera mostrar por
pantalla ordenadas de menor a mayor por el largo de las mismas.
2. Se pide cargar dos arreglos con numeros (leidos desde dos archivos de texto). Luego se debe
ordenar ambos arreglos por separado. Finalmente se debe mostrar por la salida estandar los
numeros de ambos arreglos ordenados en su totalidad, aplicando la siguiente idea: Se debe ir
leyendo simultaneamente de cada arreglo un elemento, comparandolos y mostrando el menor,
para luego leer el proximo desde el arreglo que se acaba de mostrar. Al final, se debe tener toda
una salida ordenada.
Carrera Linux 2008 Programacion PHP 43
3. Dado un directorio cualquiera, se pide hacer un script que nos permita ver todos los archivos
que correspondan a un mes pedido por parametro.
4. Mostrar todos los archivos de un directorio (y de sus subdirectorios) ordenados por su fecha de
ultimo acceso.
5. Se pide hacer un script que filtre palabras en un archivo de texto (origen).
Este programa requiere que le pasen un archivo de texto por parametro. Tambien se posee otro
archivo con palabras a filtrar (una por linea). Se tiene que generar un archivo nuevo con el
contenido del archivo de origen pero reemplazando las palabras que aparezcan en el archivo de
filtros por asteriscos (*). Se debe poner tantos asteriscos como letras tenga la palabra.
Clase 8 Servicios de Internet
Simple Mail Transfer Protocol (SMTP)
Uno de los servicios más comúnes en internet es el correo electrónico. Más precisamente, para enviar
correo se utiliza el protocolo SMTP (Simple Mail Transfer Protocol). Para hacer uso de este protocolo,
PHP posee una función llamada mail. Esta función no implementa este protocolo, sino que hará falta
tener instalado sendmail en la máquina donde se ejecute el script.
Esta función tiene 3 parámetros obligatorios: el/los destinatarios, el asunto y el mensaje.
Veamos el ejemplo más simple:
$destinatario = "alguien@algunlugar.com";
$asunto = "El coso tiene algo";
$mensaje = "Cuidado con los mensajes que divagan";
El formato del destinatario puede incluir más de una dirección (según el RFC 2822). Algunos formatos
posibles, según el sitio de PHP, son:
• usuario@example.com
• usuario@example.com, otrousuario@example.com
• Usuario <usuario@example.com>
• Usuario <usuario@example.com>, Otro Usuario <otrousuario@example.com>
El campo asunto no debería tener ningún salto de línea (\n) ya que esto podría hacer que el correo no
pueda ser enviado satisfactoriamente.
El campo mensaje si puede contener saltos de línea. También se recomienda que si existe alguna línea
que contenga más de 70 caracteres, esta se cortada en dos. Para esto viene útil la función wordwrap.
Entonces, si queremos estar seguros que el mensaje quede entre los límites definidos podemos hacer:
También es posible agregar otras cabeceras más especificas del protocolo SMTP. Para ello, se le puede
pasar, opcionalmente, un cuarto parámetro con una cadena que contenga cabeceras SMTP para enviar
tal cual se pasa.
Si por ejemplo, queremos configurar la dirección de respuesta (el From) podemos agregar la cabecera:
Entre otras cabeceras comúnes encontramos ReplyTo (la dirección a quien deben responder), CC
(copia del email), BCC (copia oculta del email) y ContentType (para setear que tipo de email es: texto,
html, etc). Las cabeceras deben ser separadas por \r\n.
Podríamos tener entonces una cabecera como la siguiente:
Post Office Protocol (POP)
Para descargar y consultar el correo electrónico se utiliza el protocolo POP3 (Post Office Protocol).
Este nos permitirá consultar los correos, descargarlos, y obtener información sobre ellos.
Conexión al servidor
Para conectarnos al servidor utilizaremos la función imap_open. Ella nos permite conectar a distintos
servicios, pero por ahora utilizaremos solo lo necesario para POP3.
La función requiere 3 parámetros: el servidor con el formato {servidor/pop3:110}INBOX, el
usuario y la contraseña.
Si se logra conectar al servidor, nos devolverá un objeto desde el cual podremos consultar la casilla, en
caso contrario devolverá falso.
Ejemplo:
$pop = imap_open("{pop.servidor.com/pop3:110}INBOX","usuario","password");
if(!$pop) {
die("Error: " .imap_last_error());
}
Cantidad de mensajes
La cantidad de mensajes que hay en la casilla puede obtener mediante la función imap_num_msg.
Esta función nos devolverá un número con dicha cantidad.
Carrera Linux 2008 Programacion PHP 45
En código:
$cantidadMensajes = imap_num_msg($pop);
Recuperando mensajes
Para recuperar los en utilizaremos la función imap_fetch_overview la cual nos dará un arreglo
con un objeto con toda la información generica para cada uno de los mensajes elegidos.
De parámetros deberémos especificarle el recursos POP y la sequencia de mensajes. La secuencia
puede ser tanto un único número de mensaje (se devuelve ese solo), una lista de números separados por
comas (se devolverá cada uno de los elegidos) o dos números separados por un dos puntos (:) (lo cual
nos traerá todo el rango, 1:3 trae 1, 2 y 3).
Entre los campos para cada mensajes nos encontramos con:
Campo Descripción
subject Título del mensaje
from Quien envio el mensaje
to Destinatario
date Fecha de envío
message_id ID del mensaje
in_reply_to Es una respuesta al ID del mensaje que tiene
size Tamaño del mensaje, en bytes
uid Identificador del mensaje
msgno Número del mensaje
En nuestro ejemplo, traeremos todos los mensajes utilizando la cantidad (1:cantidad):
$cantidadMensajes = imap_num_msg($pop);
if($cantidadMensajes > 0) {
$encabezados = imap_fetch_overview($pop, "1:$cantidadMensajes");
foreach($encabezados as $encabezadoMensaje) {
echo "$encabezadoMensaje[from]\t$encabezadoMensaje[subject]\n";
}
}
Para recuperar el cuerpo del mensaje poseemos la función imap_body. Esta función recibe dos
parámetros, el recurso POP y el número de mensaje. Luego obtendremos una cadena con todo el
cuerpo. Debemos aclarar que cada línea estará separada por un \r\n.
Para recuperar el cuerpo del mensaje 2 solo debemos hacer:
Eliminación de mensajes
Para eliminar los mensajes del servidor se requieren dos pasos. Primero se deben marcar los mensajes
que se quiere eliminar. Luego se debe dar la orden de eliminarlos.
Para el primero de los pasos se posee la función imap_delete. Como es de esperarse esta función
requiere el recurso POP y el número de mensaje a eliminar.
Para el segundo paso se posee la función imap_expunge. Para esta, solo se necesita el recursos POP.
Cabe destacar que solo hará falta hacer una única llamada a esta función, mientras que se harán varias a
imap_delete.
Por ejemplo:
imap_delete($pop, 1);
imap_delete($pop, 2);
imap_delete($pop, 3);
imap_expunge($pop); // Los mensajes 1, 2 y 3 fueron eliminados por completo
File Transfer Protocol (FTP)
Este servicio es muy utilizado para transferir archivos. El FTP (File Transfer Protocol) es, en
definitiva, ni más ni menos que un simple servidor de archivos.
Conexión al servidor
Conectarse a un servidor de FTP requiere de dos pasos: la conexión y la autentificación.
Para realizar el primer paso utilizaremos la función ftp_connect. Esta función requiere de un
parámetro básico que es la dirección del servidor.
Luego si todo a funcionado bien nos devolverá un recurso desde el cual acceder al FTP, en caso
contrario nos devolverá falso.
Para hacer el segundo paso utilizaremos la función ftp_login. Esta función requiere de 3
parámetros: el recurso que nos permite comunicarnos con el FTP (el obtenido por ftp_connect), el
nombre de usuario y la contraseña.
Esta función devolverá verdadero o falso según haya o no podido autentificarse contra el servidor.
Por último, una vez terminada de usar la conexión, podemos cerrarla utilizando la función
ftp_close y pasándole el recurso FTP como parámetro.
En código:
$servidor_ftp = "ftp.miservidor.com";
$usuario_ftp = "nombre_usuario";
$password_ftp = "secreta";
$ftp = ftp_connect($servidor_ftp);
if(! $ftp ) {
Carrera Linux 2008 Programacion PHP 47
// El programa...
ftp_close($id_con);
Subir archivos
Para subir archivos al servidor poseemos la función ftp_put. Esta función precisa del recurso FTP,
una cadena que apunte al archivo local y otra al archivo remoto. Vale destacar que ambas rutas al
archivo pueden ser tanto absolutas como relativas (como en el shell). El servidor FTP también posee un
directorio actual para cada usuario conectado.
Si todo a funcionado correctamente ftp_put devolverá verdadero, sino devolverá falso. Veamos un
ejemplo (considerar que la conexión ya esta hecha y se posee el recurso FTP en la variable $ftp):
$archivo_local = "datos.txt";
$archivo_remoto = "./datos/usuario_datos.txt";
if (! ftp_put($ftp, $archivo_remoto, $archivo_local)) {
echo "Error al tratar de subir el archivo $archivo_local\n";
}
// Si no hubo errores el archivo datos.txt estará en el servidor como
./datos/usuario_datos.txt
Descargando archivos
Para traer un archivo desde el servidor a nuestra máquina, debemos usar la función ftp_get. Esta es
similar a ftp_put pero hará lo inverso y tendrá, por lo tanto, lo mismo parámetros pero invertidos el
archivo local con el archivo remoto.
$archivo_remoto = "libreria_quemefalta_lap-1.43.546376.rpm";
$archivo_local = "lib.rpm";
Eliminando y renombrando una archivo remoto
Para eliminar un archivo que es encuentre en el FTP debemos usar la función ftp_delete.
Sencillamente habrá que pasar el recurso FTP y la ruta al archivo a borrar.
Si todo funciona bien nos devolverá verdadero o falso en caso contrario.
Ejemplo:
$archivoBorrar = "datos_temp.txt";
$ok = ftp_delete($ftp, $archivoBorrar);
if($ok) {
echo "Se ha borrado exitosamente el archivo $archivoBorrar\n";
} else {
echo "Ha ocurrido un error al tratar de borrar el archivo
$archivoBorrar\n";
}
Para renombrar tenemos la función ftp_rename la cual necesita del recurso FTP, el nombre de
archivo viejo y el nuevo.
Si todo funciona bien nos devolverá verdadero o falso en caso contrario.
Ejemplo:
$archivoViejo = "datos_temp.txt";
$archivoNuevo = "datos_hoy.txt";
$ok = ftp_rename($ftp, $archivoViejo, $archivoNuevo);
if($ok) {
echo "Se ha renombrado exitosamente el archivo $archivoViejo\n";
} else {
echo "No se ha podido renombrar el archivo $archivoViejo a
$archivoNuevo\n";
}
Manejo de directorios
Al igual que en la máquina local, poseemos comandos para crear y borrar directorios como así también
para cambiar el directorio actual, y recuperar el mismo. Respectivamente tenemos:
el recurso FTP como parámetro. actual.
Recuperando los archivos de un directorio
Para recuperar los nombres de los archivos desde un FTP poseemos dos funciones: ftp_nlist y
ftp_rawlist.
La primer alternativa es usar ftp_nlist. Esta función requiere del recurso FTP y del directorio del
cual se quieren recuperar las entradas.
Nos devolverá una arreglo con cada una de las entradas encontradas (incluyendo el directorio . y el
directorio ..).
Ejemplo:
$dirActual = ftp_passwd($ftp);
$entradas = ftp_nlist($ftp, $dirActual);
foreach($entradas as $entrada) {
echo "$entrada\n";
}
La segunda alternativa será utilizando ftp_rawlist. ftp_rawlist funciona igual que
ftp_nlist, pero nos devolverá una salida más detallada, para la cual deberemos crear una expresión
regular para recuperar las partes de interes.
En código:
$dirActual = ftp_passwd($ftp);
$entradas = ftp_rawlist($ftp, $dirActual);
foreach($entradas as $entrada) {
echo "$entrada\n";
}
Ejercicios
1. Hacer un programa que acepte por parametro una direccion de email de destinatario, un email
de origen, un asunto y el nombre de un archivo de texto. Luego el programa debera enviar un
email al destinatario con los datos suministrados.
2. Modificar el ejercicio anterior para que levante el servidor y demas datos configurables desde
un archivo de texto que posea la forma:
opcion=valor
donde opcion sera uno de los aspectos configurable (como Servidor) y valor sea el valor
correspondiente.
3. Hacer un programa que elimine todos los emails desde un POP3 cuyos Remitentes se
encuentren en una lista negra.
La lista negra consistira en un archivo de texto el cual contiene un email debajo de otro.
Carrera Linux 2008 Programacion PHP 50
4. Modificar el ejercicios anterior para que la lista negra este dividida en dos partes. La primer
servira para especificar servidores prohibidos. De este modo con indicar spammer.com todo
email que venga desde alli (jose@spammer.com, pepe@spammer.com) debera ser eliminado.
La segunda parte servira para poner direcciones especificas (como funcionaba antes).
El formato del archivo se deja a criterio libre.
5. Hacer un programa que descargue todo los archivos desde un ftp dado y un directorio dado del
mismo (ambos pasados por parametros). El programa debera descargar todos los archivos del
directorio como asi tambien los de todos los sudirectorios que puedan existir y debera quedar
localmente una copia fiel del directorio remoto.
Clase 9 Referencias
Introducción
Hasta este momento, siempre que hemos programado, hemos estado utilizando variables. Estas variables siempre poseían un único contenido (un número, una cadena, un arreglo, etc) y ese mismo contenido
siempre tenía un mismo nombre (el de la variable). Esto no necesariamente es siempre asi ya que PHP nos permite darle distintos nombres a un contenido a través de las referencias.
Una referencia me permitirá acceder un contenido definido anteriormente por otra variable. Lo que hará realmente es darle otro nombre al mismo contenido.
Para crear una referencia hay que utilizar el operador & de la siguiente forma:
$var = 486;
$ref = &$var;
De esta forma hemos creado una variable normal llamada $var que tiene el valor 486. Luego hemos creado una referencia (llamda $ref) que hace referencia (valga la redundancia) al mismo 486.
Si ejecutamos:
ambos mostrarán 486. Como la variable $ref y $var hacen referencia al mismo contenido, si modificamos una de ella, la otra se verá inevitablemente alterada.
Si por ejemplo:
$ref = $ref + 1;
entonces:
ambos muestran el valor 487. Esto se deba a que un mismo contenido (originalmente 486) puede tener distintos nombres al mismo tiempo. Una vez creada la referencia es indistinto si usamos $var o $ref
ya que ambos son nombres del mismo contenido.
Referencias y Funciones
Cuando trabajamos en PHP las referencias nos serán especialmente útiles cuando trabajemos con funciones.
Para ejemplificar esto veamos la siguiente función:
function incrementar($var) {
$var++;
echo "[incrementar] var = $var\n";
}
$contador = 1;
echo "[antes] contador = $contador\n";
incrementar($contador);
echo "[despues] contador = $contador\n";
Si corremos este programa veremos la salida:
[antes] contador = 1
[incrementar] var = 2
[despues] contador = 1
La cual funcionaría como habría de esperarse. Sin embargo, nuestro objetivo al crear la función incrementar es que la variable que se paso por parámetro quede con el valor incrementado en 1.
Aquí es donde entran en juego las referencias. Veamos una versión modificada de la función anterior:
Carrera Linux 2008 Programacion PHP 51
function incrementar(&$var) {
$var++;
echo "[incrementar] var = $var\n";
}
Le hemos agregado un & en la declaración de la función. Esto le indica a PHP que ese parámetro se pasará por referencia. Al pasar los parámetros comunmente (como ya hemos visto) estos son pasados por
valor. Esto quiere decir que la variable (en este caso $var) contendrá una copia de la variable pasada por parámetro (en este caso $contador). Esto no siempre es deseable. Si quiciesemos modificar dicha
variable deberiamos utilizar una referencia. Como hemos visto al principio al utilizar una referencia, ambas variable apuntan al mismo contenido por lo que modificando una se modifica la otra.
Con esta versión modificada ahora obtendremos los resultados deseados:
[antes] contador = 1
[incrementar] var = 2
[despues] contador = 2
Una ventaja de pasar los parámetros por referencias (ademas de poder modificarlos) es que no es necesario crear una copia de los mismo. Si lo que se intenta pasar es muy grande (digamos un arreglo con
muchas entradas que son arreglos que a su vez tienen muchas entradas y etc), al crear una copia estaríamos desperdiciando espacio y tiempo. En cambio, al pasarlo por referencia solo hay que agregar un
nuevo nombre para el contenido ya existente.
Eliminando referencias y variables
PHP nos permite volver a dejar una variable que ya hemos utilizado en estado de indefinida (como si nunca la hubiesemos usado). Para ello existe la función unset. A esta función solo hay que darle
como parámetro la variable a utilizar.
Por ejemplo:
$x = 3;
unset($x);
echo "x = $x\n";
mostrará "x =" ya que la variable x esta vacía. Como x era el único nombre que tenia el contenido
asociado (Que tenia valor 3), al eliminarse x se perderá ese valor (ya no hay nadie quien haga referencia
a el). En cambio, si disponemos de una referencia, al aplicar unset solamente borraremos ese nombre
asociado a ese contenido. Las demas referencias a ese nombre no se perderán, por lo tanto, el contenido
seguirá existiendo.
Ejemplo:
$x = 3;
$ref = &$x;
unset($x);
echo "x = $x\n";
echo "ref = $ref\n";
mostrará:
x =
ref = 3
también funcionará al reves:
$x = 3;
$ref = &$x;
unset($ref);
echo "x = $x\n";
echo "ref = $ref\n";
Carrera Linux 2008 Programacion PHP 52
lo cual mostrará:
x = 3
ref =
Ejercicios
1. ¿Que son las referencias y cuales son sus aplicaciones practicas?
2. Se posee una variable a la cual se le crea una referencia. Si la variable es eliminada pero la
referencia no, ¿se perderá el contenido?
3. Una vez creada una referencia, ¿en que se diferencia la variable que tiene la referencia de la
original?
4. Realizar el juego tateti para dos jugadores. Para representar el tablero se deberá usar una
matriz.
Clase 10 Manejo de objetos
Introducción a la programación orientada a objetos
Hasta el momento hemos estado programando dentro de lo que se llama el paradigma de
programación estructurado. En este esquema, siempre partiamos desde el problema más grande y lo
ibamos partiendo en pedazos más chicos para su resolución.
En el paradigma de objetos, la historia es un poco al reves, partiendo desde lo específico (un objeto)
hasta lo general.
Un objeto esta compuesto por su estado (los atributos) y sus responsabilidades (los métodos). Los
atributos son el conjunto de valores que guarda cada objeto. Los métodos son los servicios que presta
ese objeto (por ejemplo, si se posee un objeto que representa a un Cliente, entonces se podría tener un
método Cobrar el cual permita al sistema registrar un cobro del cliente).
Los objetos existen dentro de un ambiente. Luego se podrán comunicar con otros objetos mediante el
paso de mensajes (invocaciones a métodos). Un mensaje es un pedido de un objeto (emisor) a otro
(receptor) un servicio, que este será ejecutado en el receptor por un método.
Dentro de este paradigma también existe algo llamado Clases. Las Clases son "los moldes" de los
objetos. O sea, para crear un objeto, debo tener una clase que lo defina. En realidad, un objeto será una
instancia de una clase. Podríamos pensarlo como que el objeto es la clase en ejecución.
Clases y objetos
El primer paso para crear un objeto, como hemos mencionado, es tener una clase de donde sacarlo. La
sintaxis para crear una clase cualquiera es la siguiente:
Carrera Linux 2008 Programacion PHP 53
class NombreClase {
// Definicion de atributos
// Definicion de metodos
Para definir un atributo usaremos un de las siguientes 3 palabras reservadas: public, private,
protected.
Antes de explicarlas veremos como se escribe:
public $nombre;
private $apellido;
protected $edad;
Atributos
Si definimos un atributo como public, entonces este podrá ser accedido (tanto para leerlo como para
modificarlo) desde afuera del objeto. O sea, cualquier objeto puede tener acceso a este atributo.
Esto es, por lo general, malo. Es de muy mala práctica y trae muchos problemas que un objeto pueda
modificar el estado de otro. Cada objeto es responsable por mantener su estado. Además, de esta forma,
si solo el objeto mismo es quien se ocupa de manejar su estado, solo habría que cambiar en ese objeto
en caso de necesitar hacer una modificación.
Si definimos un atributo como private, solo puede ser accedido por el objeto mismo. Ningún otro
objeto bajo ninguna circustancia podrá modificar dicho atributo.
Finalmente, si lo definimos como protected, solo lo podrán acceder el objeto mismo u objetos que
hereden de esa clase (ver Herencia).
Esto quiere decir que una subclase podrá usar los atributos definidos en la clase madre (los distintos
objetos, instancias, de esta clase no podrán acceder a los atributos de otros objetos).
Dentro de los métodos si queremos acceder a un atributo, entonces deberemos hacerlo escribiendo
$this-> seguido del nombre dado al atributo ( sin el $).
Métodos
Para definir un método utilizaremos la estructura function. Esta es idéntica que las funciones
definidas por el usuario explicadas en clases anteriores salvo que estarán dentro de una clase. Por lo
tanto, PHP las interpretará como métodos de dicha clase.
Los métodos también poseen una visibilidad como los atributos (public, private o protected)
y cumplirán las mismas condiciones pero sobre el método. Si no se especifica ninguna de las 3 se toma
por defecto que el método es public.
Darémos un ejemplo de una clase sencilla para mostrar todo lo explicado:
Carrera Linux 2008 Programacion PHP 54
class Persona {
private $nombre;
private $apellido;
private $edad;
private $pais;
Instanciación
Una vez definida la clase, podemos crear objetos a partir de ella. Este proceso se llama instanciación.
Para ello utilizaremos el operador new seguido del nombre de la clase y los paréntesis.
Luego, para acceder a un método, (o sea, enviarle un mensaje al mismo), escribiremos el la variable del
objeto seguida por un ->, el nombre del método y sus parámetros.
Carrera Linux 2008 Programacion PHP 55
Considerando la clase Persona, podríamos escribir:
Herencia
El concepto de herencia significa poder definir una clase tomando como en base a otra. La primera
será la clase hija mientras que la segunda será la clase padre. Al heredar desde una clase, la nueva clase
poseerá automáticamente todos los atributos y métodos de la clase padre, pero podremos agregarle
nuevos atributos y métodos (y/o modificarlos).
Las clases hijas se escriben al igual que cualquier otra clase (son clases despues de todo) con la
excepción que hay que agregarle de que clase estan heredando. Para ello, luego del nombre de la clase
hija, se debe agregar la palabra reserva extends seguida del nombre de la clase padre.
Veamos un ejemplo:
Aquí hemos definido una clase Empleado que extiende (hereda) de Persona. Esta relación también
se le dice "es un" (Empleado es una Persona).
Si creamos un objeto de esta clase, podremos llamar tanto al método setSueldo y getSueldo,
como a todos los métodos definidos para la clase Persona.
Redefinición
Como habiamos mencionados anteriormente, cuando creamos una clase hija, esta hereda todo el
comportamiento y los atributos del padre. Sin embargo, no siempre queremos que todo lo heredado
Carrera Linux 2008 Programacion PHP 56
funcione igual. Tenemos la posibilidad de redefinir los métodos que nos sean necesarios.
Expandiendo el ejemplo anterior, definiremos subclases de Empleado: Vendedor, Gerente.
El código de las clases es el siguiente:
En este ejemplo vemos que al crear las nuevas clases hijas, hemos redefinido el método getSueldo y
getTrabajo. Ahora los nuevos métodos trabajaran diferente al original, pero, visto desde afuera, no
habrá diferencia entre pedirle el sueldo a un objeto del tipo Empleado, que al del tipo Gerente.
Veamos todo esto en acción:
Polimorfismo
El último concepto que nos queda es el de polimorfismo. Se dice que dos objetos son polimórficos
cuando son intercambiables. Esto quiere decir que podemos poner cualquiera de los dos y el programa
funcionará con ambos. Para ello ambos objetos deben tener, por lo menos, un método que tenga igual
nombre e igual cantidad y tipo de argumentos.
Para ejemplificar esto, haremos una clase Empresa:
class Empresa {
private $personal;
private $costoFijo;
Aquí se puede apreciar el polimorfismo, por ejemplo, en el método calcularTotalSueldos. Allí
Carrera Linux 2008 Programacion PHP 59
cuando se recorre el arreglo se llama al método getSueldo de cada uno de los empleados. Cuando se
ejecuta este método no se sabe que hay en el arreglo personal. Puede haber tanto objetos de tipo
Empleado, como de tipo Gerente, como de tipo Vendedor, o una mezcla de ambos. Cualquiera
sea el caso, se le pedirá al objeto que ejecute el método getSueldo sin saber ni como lo hace, ni de
que tipo es el objeto, ni de donde saca la información.
También se ve lo mismo en el método listadoEmpleados el cual generá el mismo formato de
listado que el expuesto en el ejemplo anterior.
Veamos un ejemplo del uso de esta nueva clase, considerando creados los objetos de empleados:
$empresa->agregarEmpleado($empleado1);
$empresa->agregarEmpleado($empleado2);
$empresa->agregarEmpleado($vendedor1);
$empresa->agregarEmpleado($vendedor2);
$empresa->agregarEmpleado($gerente);
$empresa->setCostoFijo(7000);
$empresa->listadoEmpleados();
Constructores y destructores
Un constructor es un método que se ejecuta automaticamente al momento de instanciar una clase. De
esta forma, disponemos de una herramienta para inicializar el estado de nuestro objeto a nuestra
voluntad.
En PHP, y a partir de las versiones 5.X, el método constructor tiene por nombre __construct.
El constructor puede o no tener parámetros. Si los tiene, entonces será necesario pasarselos al momento
de instanciar la clase. Los parámetros al constructor se escribiran entre los corchetes en el momento de
hacer el new sobre la clase.
Por ejemplo, podríamos modificar la clase Empleado para que quede así:
public __construct() {
$sueldo = 0;
}
De esta manero nos aseguraríamos que siempre se posee un valor cargado en el atributo sueldo, ya
que si lo llegáramos a utilizar sin haberle cargado un valor (en nuestro ejemplo, sin haber llamado a
setSueldo), nos tirará un error.
El destructor es un método que se ejecuta cuando todas las referencias al objeto se hayan perdido. Esto
ocurrirá cuando finalice el script o cuando forzadamente se eliminen las referencias.
El nombre del método, análogamente al constructor, deberá llamarse __destruct y no podrá recibir
ningún parámetro.
Ejercicios
1. Definir los 3 conceptos basicos del paradigma de objetos.
2. Definir objeto. ¿Cual es la diferencia entre Clase y Objeto?
3. Definir el concepto de herencia. De un ejemplo en donde seria util.
4. Definir el concepto de redefinicion. De un ejemplo en donde seria util.
5. Definir el concepto de polimorfismo. De un ejemplo en donde seria util.
Clase 11 Excepciones
Introducción
Las excepciones son un método para el manejo de errores. Básicamente son un canal separado para
enviar errores. De esta forma nos permite eliminar de nuestro código los métodos más antiguos como
devolver el error como valor de retorno de una función, una variable global, usar ifs, etc.
Para ello se utilizará una nueva estructura: try/catch. Esta estructura esta compuesta por un bloque
de código, try, el cual podrá o no arrojar una excepción, y un bloque de código, catch, que se
ejecutará cuando se arroje efectivamente la excepción. En caso contrario, el bloque del catch NO se
ejecutará.
Conceptualmente, el sistema de excepciones funciona de la siguiente manera. En algún punto donde se
detecte una condición de error, se lanzará una excepción. En este momento, PHP dejará de ejecutar el
script, e irá hacia atras sus pasos en la línea de llamadas hasta encontrar un bloque try/catch que
capture la excepción. Cuando lo encuentre, reanudará la ejecución en el bloque de código del catch.
De no existir un bloque catch que atrape la excepción, PHP terminará la ejecución del script y
mostrará un error fatal.
Carrera Linux 2008 Programacion PHP 61
Manejo básico
Para demostrar lo expuesto, haremos un pequeño ejemplo. Crearemos dos clases. La primera será
ControladorTransferencia. Esta clase llevará un contando de cuantos bytes se han
transmitidos y cual es el máximo admisible. Luego tendremos la clase Usuario que representará a un
usuario logueado. Este tendrá un método descargar, para poder bajar un archivo y dentro de él se le
pedirá al controlador de transferencia que estipule si puede o no bajar el archivo pedido. En caso de no
poder, el controlador tirará una excepción.
Veamos el código:
class ControladorTransferencia {
private $maximoBajada;
private $bytesTransferidos;
function __construct($maximoBajada) {
$this->maximoBajada = $maximoBajada;
$this->bytesTransferidos = 0;
}
class Usuario {
private $username;
private $controladorTransferencia;
function __construct($nombre) {
$this->controladorTransferencia =
new ControladorTransferencia(100 * 1024 *
1024); // 100Mb
$this->username = $nombre;
}
En el método transferir de ControladorTransferencia se puede ver donde se tira la excepción. La
estructura para tirar una excepción es throw seguida de un objeto Exception.
Aquí se puede ver que, en definitiva, a nivel código, una excepción es ni más ni menos que un objeto.
Usamos la más básica de todas que es Exception pero luego veremos otras posibilidades. Es
Carrera Linux 2008 Programacion PHP 62
importante destacar que se debe hacer un new de la clase ya que sino estaríamos tratando de arrojar la
clase misma ocurriendo un error de ejecución.
También podemos configurarle un mensaje de error para esa excepción en particular, suministrándole al
constructor de la excepción una cadena arbitraria.
Veamos estas clases en uso:
try {
$usuario->descargar("misteriuos_data.tgz");
} catch (Exception $e) {
echo "Excepcion atrapada\n";
echo "Archivo: ", $e->getFile(), "\n",
"Linea: ", $e->getLine(), "\n",
"Mensaje: ", $e->getMessage(), "\n";
Aquí aparece por primera vez el bloque try/catch. Como se ve en el bloque try hemos puesto
todas las sentencias que puedan tirar una excepción (es este caso es una sola pero podrían ser más).
Luego viene un bloque catch, el cual tiene como "argumento" una excepción que se guarda en la
variable $e. Esto lo hace automáticamente PHP y, a fines prácticos, nosotros solo usaremos esa varible
dentro del bloque. La excepción nos da mucha información sobre el error. En particular, un objeto
Exception tiene varios métodos interesantes. A saber:
Método Descripción
getFile Nos devuelve el nombre del archivo .php desde el cual se arrojo la excepción
Nos devuelve el número de línea desde donde se arrojo la excepción (donde
getLine
esta el throw).
Nos devuelve una cadena con el mensaje de error (el que configuramos
getMessage
cuando creamos el objeto Exception)
Nos devuelve una cadena con todas las llamadas que se hicieron desde el nivel
getTraceAsString más alto hasta el método que tiro la excepción. De esta forma podemos ir
siguiendo el camino que llevo el programa y encontrar el error lógico.
Excepciones definidas por el usuario
Hasta aquí solo hemos utilizado la excepción Exception, pero PHP también nos permite crear
nuestras propias excepciones. Esto servira para darle un significado mayor a la excepción. Al recibir
una excepción diferente podemos saber más precisamente el error y podremos diferenciarlas de otras
excepciones (ver el apartado siguiente Manejo de multiples excepciones).
También nos permite agregarle funcionalidades extra al objeto de excepción, agregándole también
información extra particular para ese caso.
Carrera Linux 2008 Programacion PHP 63
Para crear una nueva excepción solamente hay que crear una clase que herede de la clase Exception.
Esto solo basta para crear la nueva excepción. De todos modos, como mencionanmos antes, podemos
agregarle más atributos y métodos.
En nuestro ejemplo, crearemos una excepción nueva para representar el limite excedido y guardaremos
en ella los valores (máximo, actual y lo pedido) para luego dar más información cuando falle.
El código de la nueva clase y la modificación en la clase ControladorTransferencia para que
emplee esta nueva excepción:
class ControladorTransferencia {
private $maximoBajada;
private $bytesTransferidos;
function __construct($maximoBajada) {
$this->maximoBajada = $maximoBajada;
$this->bytesTransferidos = 0;
}
Veamos ahora como atrapar esta nueva excepción:
try {
$usuario->descargar("users.php");
} catch (limiteExcedidoException $e) {
echo "Excepcion atrapada\n";
echo "Archivo: ", $e->getFile(), "\n",
"Linea: ", $e->getLine(), "\n",
"Mensaje: ", $e->getMessage(), "\n";
Para atrapar una excepción en particular cambiaremos el tipo Exception por el de nuestra excepción en el bloque catch. De esta forma, y para este ejemplo, la variable $e tendrá nuevos métodos que no
poseen las excepciones comunes (getMaximo, getActual y getPedido). Por lo tanto, además de la información estándar hemos agregado información extra relacionada con los tamaños requeridos.
Manejo de multiples excepciones
Puede ocurrir, y es muy común, que para un bloque try se puedan disparar varias excepciones diferentes. Puede ser necesario tratar de forma distinta cada excepción. Por lo tanto podemos definir tantos
bloques catch como excepciones tengamos.
Cada bloque catch deberá definir a cada tipo de excepción. El primer bloque catch deberá tener la excepción más específica y el útlimo la más general (Exception). Si los escribimos al reves,
Exception concordará con cualquier excepción tiremos y se utlizará ese sin revisar los demás.
Modificaremos la clase Usuario para que arroje otra excepción:
class Usuario {
private $username;
private $controladorTransferencia;
function __construct($nombre) {
$this->controladorTransferencia =
new ControladorTransferencia(1024); //*1024);//*100);
$this->username = $nombre;
}
Luego agregaremos el manejo para ambas excepciones (limiteExcedidoException y Exception):
try {
$usuario->descargar("users.php");
} catch (limiteExcedidoException $e) {
echo "Excepcion atrapada\n";
echo "Archivo: ", $e->getFile(), "\n",
"Linea: ", $e->getLine(), "\n",
"Mensaje: ", $e->getMessage(), "\n";
Como se ve aquí primero se captura la excepcion limiteExcedidoException y luego Exception. PHP se encargará automáticamente de ejecutar el primer bloque catch que concuerde con la
excepción tirada y nos asegurará que no se ejecuta ningún otro bloque catch.
Ejercicios
1. ¿Que es un excepcion y para que sirve?
2. ¿Cuantos bloques catch puede haber en una construccion try/catch? ¿porque?
3. ¿Que información me provee una excepcion?
4. ¿Como se extiende una excepcion? ¿Que funcion cumple?
Carrera Linux 2008 Programacion PHP 65
Clase 12 Introducción a la programación web
Conceptos Generales sobre Programación Web
La programación web consiste basicamente, en generar páginas HTML dinamicamente. Esto quiere
decir que cada vez que se quiera ver una página, esta deberá crearse en el momento y para quien la
pida.
Cuando se accede a una página hay tres atores en escena: El cliente (un navegador), El servidor web y
PHP (en este caso).
Los pasos son los siguientes:
1. El cliente pide ver una página .php
2. El servidor web reconoce que no es un HTML estático
3. Se ejecuta el interprete de PHP y ejecuta la página .php
4. La salida generada (todo lo que el script envíe a la salida está) por este programa se envia al
cliente para que la visualice
Para comunicarse entre el cliente y el servidor se utiliza el protocolo HTTP. Este protocolo sirve para
mucho más que devolver páginas HTML pero por el momento solo usaremos esta característica.
En el paso 3 es donde ocurre la magia. Cuando se ejecuta la página se utiliza todo un lenguaje de
programacion (PHP) para crearla. Esto implica que se usarán variables, decisiones, operaciones, ciclos,
etc. En un programa, las variables mantienen el "estado", es decir, los valores procesados. Estos valores
se pierden completamente cuando se termina de ejecutar la página.
Estructura básica de un HTML
Todo HTML debe tener por lo menos estos tres tags que definen la estructura básica: HTML, HEAD,
BODY.
El tag HTML sirve para encerrar todo el archivo de html.
Sería:
<HTML>
</HTML>
Entre medio de estos dos tags se escribirá todo el contenido de HTML que se quiera que muestre el
archivo.
El tag HEAD sirve para determinar algunos parámetros generales del HTML que se este editando. Se
puede setear el título de la página (el que normalmente el navegador utiliza como título de la ventana) o
algunas reglas generales del manejo de fuentes, o metadata. Este tag sería el primero que se debe
encontrar luego del <HTML>.
Para establecer el título se utiliza el tag TITLE.
Carrera Linux 2008 Programacion PHP 66
Quedaría algo asi:
<HTML>
<HEAD>
<TITLE> El título </TITLE>
</HEAD>
</HTML>
El tag BODY es el que delimita el cuerpo del HTML. Dentro de este tag se escribirá todo lo que se
quiera que se vea en la pantalla cuando se intente ver el archivo.
La estructura básica quedaría finalmente:
<HTML>
<HEAD>
<TITLE> El título </TITLE>
</HEAD>
<BODY>
Hola Mundo
</BODY>
</HTML>
En este ejemplo, se mostraría por pantalla el texto "Hola Mundo".
NOTA: Los ejemplos de HTML que apareceran de aquí en adelante, son fragmentos de lenguaje que se
escribe dentro del tag BODY a no ser que se indique lo contrario.
Primero que nada veamos que pasaría si escribimos esto:
Hola a todos,
queria informarles que esto sale mal
La salida sería:
Hola a todos, queria informarles que esto sale mal
Lo cual no es lo que se esperaba. Esto se debe a que cuando se interpreta el HTML, a no ser que se
encuentre un tag, los caracteres que se encuentran se muestran directamente y se ignoran todos los
espacios. Para poder lograr que se baje de línea hay que poner un tag que lo haga. Dicho tag es el tag
BR. Este tag no tiene fin, simplemente cuando se lo encuentra el navegador bajará de linea. Sería:
Holas a todos,<BR>
queria informarles que esto casi sale bien
La salida sería ahora:
Holas a todos,
queria informarles que esto casi sale bien
Carrera Linux 2008 Programacion PHP 67
Si bien mejor que antes no lo suficientemente bien. Para poner espacios se puede alinearlo todo usando
tablas o poner los espacios. Para poner espacios se debe como escapar el espacio, lo cual se logra
escribiendo
También pueden especificarse párrafos. La ventaja de esto es que dentro de un párrafo se puede
configurar la justificación del texto (izquierda: left, centrado: center, derecha: right). El tag que
hace esto es el tag P. La opción para la justificación es align. Cuando se escribe un tag P, el navegador
comenzará el párrafo comenzando inmediatamente desde la línea próxima. Si no se especifica el fin del
tag (el </P>) se cerrará automaticamente cuando se termine el archivo.
Veamos un ejemplo:
Entonces el dijo:<P ALIGN=CENTER>"No olvidar.<BR>Lo que ves ya se ha visto ya."
La salida será:
Entonces el dijo:
"No olvidar.
Lo que ves ya se ha visto ya."
El tag P dejo una línea en blanco y comenzo el nuevo párrafo. Si bien el HTML escrito es correcto, y a
pesar de que los "ENTER" se ignoren a la hora de mostrarlos por pantalla, es buena costumbre bajar
una línea luego de escribir un <P> o un <BR>.
Dandole estilo al texto
Es posible darle estilos al texto. Que pasaría si en el ejemplo anterior, quicieramos que la parte entre
comillas aparezca en itálicas (cursiva). Para ello existen el tag I. Quedaría algo así:
Entonces el dijo:
<P ALIGN=CENTER>
"<I>No olvidar.<BR>
Ahora el navegador lo mostrar en letra cursiva (también queda más claro el haberlo organizado
diferente, ¿no?).
En el siguiente cuadro se listan todos los tags similares que dan otros efectos:
TAG EFECTO
<B>...</B> Negrita
<I>...</I> Itálica (Cursiva)
Carrera Linux 2008 Programacion PHP 68
<U>...</U> Subrayado
<SUB>...</SUB> Subindice
<SUP>...</SUP> Supraindice
También existe un tag para setear un texto como título. Para ello esta el tag H seguido de un número
entre 1 y 6. Esto le dará el tamaño al título siendo el 1 el más grande y el 6 el más pequeño. Este tag
también tiene la opción ALIGN para setear la justificación.
Por ejemplo:
<H1 ALIGN=CENTER>Profecias</H1>
Pondrá un título bien grande y centrado que dira "Profecias" en nuestro HTML.
Creando Links
Un link es una enlace entre dos páginas. De esta forma cuando el usuario aprete sobre el link, se lo
llevará automaticamente a ese documento. La idea básica es que un link vincule o enlace información
relacionada de forma tal que quien navege la página pueda ir descubriendo toda la información que
busca.
Para crear un link se utiliza el tag A. Este tag tiene la opcion HREF la cual me permite especificar a que
documento hace referencia. Por ejemplo:
Grandes obras:
<A HREF=la_biblia_segun_vox_dei.html>La Biblia segun Vox Dei</A>
<A HREF=the_lamb.html>The Lamb Lies Down On Brodway, Genesis</A>
Aquí se crearan dos links. El primero llevará al archivo la_biblia_segun_vox_dei.html. Sin embargo el
usuario vera en la pantalla lo que se encuentre dentro del tag A, en este caso, La Biblia segun Vox Dei.
Lo mismo ocurrirá con el segundo link.
El tag A tiene otras cuantas opciones. Veremos, sin embargo, una sola más, la opcion TARGET. Esta
opción nos permite especificar a donde queremos que se habra el link. Puede llevar el nombre de un
frame para que lo abra allí, o podra llevar un nombre que no este usado en ningún lado y abrirá al link
en una nueva ventana, como un popup. Por lo general se le da el nombre _web para este tipo de target.
Por ejemplo:
En este ejemplo, cuando se aprete sobre el link (creyendo ganar mucho dinero) aparecerá un popup con
propaganda.
Carrera Linux 2008 Programacion PHP 69
Tablas
Las tablas son una de las herramientas más útiles del HTML y se usaran hasta el cansancio. Una tabla
es simplemente un area del html que esta dividida en celdas, y en donde cada celda puede contener
cualquier cosa de HTML.
Las tablas las utilizaremos para organizar visualmente el HTML como también para crear cuadros.
Estas consisten en filas y columnas (aunque no necesariamente coincidan en cantidad).
El tag para crear tablas se llama TABLE. Este tag tiene varias opciones, entre ellas encontramos:
ALIGN: Determina la alineación de toda la tabla en el HTML (al igual que con el tag P)
BORDER: Determina el ancho del borde que tendrán las celdas. Si es 0 no tendra ningún border. Por
defecto el valor es 1.
WIDTH: Determina el ancho de la tabla. Se puede especificar en pixeles (poniendole un valor) o en
porcentaje (poniendo un % luego del valor). Por ejemplo WIDTH=100 le dara un tamaño de 100
pixeles mientras que WIDTH=100% usará todo el ancho de la ventana.
BGCOLOR: Determina el color de fondo que tendra la tabla. Los colores se escriben como una
combinación de Rojo, Verde y Azul (RGB). Cada color puede variar entre 0 y 255 (o en hexadecimal
entre 0 y FF). Se debe escribir un numeral (#) y luego los tres valores de los colores (en hexadecimal).
Por ejemplo, para obtener el color azul sería #0000FF
Para crear una fila se utilza el tag TR. Este tag tiene una opción ALIGN para alinear el texto dentro de
esa fila, y una opción BGCOLOR para darle un color de fondo a la fila unicamente. Dentro de este tag se
deberá especificar cada celda que habra en esa fila.
Para crear una celda se utiliza el tag TD (también tiene las opciones ALIGN y BGCOLOR que se
comportan igual que las de TR pero a nivel celda). Veamos un ejemplo completo de una tabla:
<TABLE BORDER=1>
<TR>
<TD>Celda 1</TD>
<TD>Celda 2</TD>
</TR>
<TR>
<TD>Celda 3</TD>
<TD>Celda 4</TD>
</TR>
<TR>
<TD>Celda 5</TD>
<TR>
</TABLE>
La salida será:
Celda 1 Celda 2
Celda 3 Celda 4
Celda 5
Carrera Linux 2008 Programacion PHP 70
Como vemos no hemos especificado la última columna por lo cual quedará vacía. Como cantidad de
columnas se tomará la fila que tenga más celda y aquellas filas que no lleguen a esa cantidad quedarán
vacías.
Es posible juntar las ultimas dos celdas para que quede prolijo, para ello en la última celda deberiamos
indicarle que debe utilizar dos columnas de ancho. Para ello esta la opción COLSPAN. Si le damos el
valor dos se tomará las dos columnas. Quedaría así:
<TABLE BORDER=1>
<TR>
<TD>Celda 1</TD>
<TD>Celda 2</TD>
</TR>
<TR>
<TD>Celda 3</TD>
<TD>Celda 4</TD>
</TR>
<TR>
<TD COLSPAN=2>Celda 5</TD>
<TR>
</TABLE>
Y ahora la salida sería correcta:
Celda 1 Celda 2
Celda 3 Celda 4
Celda 5
También puede hacerse esto a nivel filas (juntar dos filas en una columna) si utilizamos la opción
ROWSPAN en vez de COLSPAN.
Ejercicios
1. ¿Que es un pagina web dinamica? ¿A donde debe enviarse la salida de la misma y que funcion
conocida de PHP utilizaria para ello?
2. ¿En que se basa los archivos HTML? ¿Como esta conformado un tag?
3. ¿De que sirve poder crear tablas en HTML? ¿Como se determina la cantidad de filas y
columnas de una tabla?
4. ¿Que hacen los navegadores con un conjunto consecutivo de caracteres blancos (espacios,
ENTER, tabulaciones, etc)? ¿Que utilidad le encuentra a dicho hecho?
5. Se necesita crear una serie de scripts que informen sobre algunos aspectos del estado actual del
sistema.
Estos scripts debe generar:
a. Un html que se basara en informacion que encuentre en el archivo /etc/lilo.conf. De
dicho archivo debera extraer el campo message y todos los campos label. Luego debera
mostrar el campo message y luego en una tabla centrada todos los labels que encontro.
b. Un html que se basara en la informacion que encuentre en el archivo /etc/inittab. Este
Carrera Linux 2008 Programacion PHP 71
HTML debe mostrar una tabla con dos entradas (dos columnas) en donde la primera sera
la accion y la segunda el comando. Desde el archivo /etc/inittab se debe extrar el campo
accion y comando de todos aquellos que pertenezcan a los runlevels 3, 4 o 5.
NOTA: Cada entrada del archivo inittab tiene el formato:
id:runlevel1,runlevel2,...,runlevelN:accion:comando
Para mas informacion ver el manual inittab(5)
c. Aqui se deberan genera un HTML (usuarios.html) con un listado de todos los usuarios.
Cada usuario sera un link a otra pagina (llamada usuario_nombre.html, por ejemplo,
para root sera usuario_root.html) que tendra la informacion del usuario. Toda la
informacion de los usuarios se encuentra en /etc/passwd y la de los grupos en /etc/group)
En particular cada pagina del usuario tendra la siguiente forma:
Primero en titulo 1 y centrado (h1) estara el nombre del usuario. Luego vendra una tabla
que tendra en la primer fila, dos columnas: una que dira el UID y otra el GID. En la
segunda fila dira el directorio personal y el shell. En la tercer fila debera informa la
informacion extra que haya (este fila debe ocupar dos columnas).
Luego se debera mostrar otra tabla que liste todos los grupos a los cual pertenece dicho
usuario. Cada entrada de este grupo sera un link a la informacion del grupo (ver mas
adelante).
d. Tambien se debe generar un archivo, grupos.html, el cual contendra un listado de todos
los grupos existentes (segun el archivo /etc/group). Cada entrada sera un link a la
informacion del grupo (similar a los usuarios). De cada grupo se debe poner un titulo
centrado H1 con el nombre del grupo y luego una tabla de una sola columna que liste, en
cada fila, a todos los usuarios de ese grupo. Cada usuario sera un link a la informacion
del mismo.
Es necesario crear tambien un html, menu.html, para acceder a cada uno de estos cuatro
puntos. Tambien, cada html debe tener un link, abajo a la derecha, que diga "Volver" el
cual me permitira volver a la pagina anterior (al menu.html, salvo cuando se trata de la
informacion de un usuario o grupo, en donde llevar al listado correspondiente).
NOTA: Por simplicidad se sugiere hacer dos scripts separados para el punto a y b, y uno
solo para el punto c y d.
Carrera Linux 2008 Programacion PHP 72
Clase 13 HiperText Markup Language(HTML)
Parte 2
Listas
En HTML una lista es simplemente la enumeración o denotación de varios elementos. Estos elementos
serán en definitiva, texto. Las listas servirán entonces para darle formato a la salida.
Una lista puede ser ordenada o desordenada. Aquellas que son ordenadas llevarán algún tipo de
numeración, las otras llevarán simplemente alguna viñeta.
Listas desordenadas
Las listas desordenadas quedan definidas por el tag <ul> ... </ul> (Unordered List). Dentro de
este tag se especificarán todos los elementos de la lista. Cada elemento de la lista se definirá en el tag
<li>...</li>.
Ejemplo:
<ul>
<li><A HREF=http://www.atptennis.com>Tenis</A></li>
<li><A HREF=http://www.freeprogrammingresources.com>Free Books</A></li>
De esta forma el HTML exibirá algo así:
• Tenis
• Free Books
• Las noticias
Lo que es posible configurar de las listas desordenadas es que dibujo utilizar como viñeta. Entre los
posibles estan un circulo, un cuadrado o un disco (por defecto). Para ello habrá que agregarle la opción
TYPE al tag UL. Los valores de esa opción son CIRCLE, SQUARE y DISC respectivamente. El fin del
tag LI (</LI>) puede ser, y normalmente lo es, omitido ya que es claro para el navegador que en
donde encuentre otro tag <LI> significa que comienza otro elemento.
Lista Ordenadas
Las listas ordenadas se diferencia de las anteriores en que cada elemento de la lista posee una posición
(numérica o alfabética) , o sea, identificarían como una secuencia de pasos. El tag que se utiliza para
estas listas es el tag <ol>...</ol> y para los elementos el tag <li> (mismo caso que con las listas
desordenadas). El tag ol también posee un parámetro TYPE que permite determinar el tipo de
numeración. Entre los posibles existen:
Carrera Linux 2008 Programacion PHP 73
A Alfabética Mayúscula A,B,C,D...
a Alfabética Minúscula a,b,c,d...
I Números Romanos Mayúscula I,II,III,IV...
i Números Romanos Minúsculas i,ii,iii,iv...
Frames
Hasta el momento todas las páginas que generamos ocupaban toda la ventana. Si se desea dividir la
venta en partes de forma que podamos cargar varias páginas distintas dentro de la misma ventana, será
necesario utilizar frames. Un frame es simplemente un "porción" de una ventana. Para utilizar frames
es necesario crear un HTML que contenga solamente la definición de los frames y luego otro html por
cada frame que se utilice.
Para crear un frame se utiliza el tag <FRAMESET>...</FRAMESET>. Es tag REEMPLAZA al tag
BODY, por lo tanto, el tag BODY no estará presente. Un FRAMESET me permite dividir la ventana en
filas o en columnas. Si luego se quiere dividir más la página se pueden anidar FRAMESETs. Este tag
llevará un parámetro COLS(columnas) o un ROWS(filas), pero no ambos. Cada uno de ellos dividirá a la
ventana en filas o en columnas. Las divisiones se pueden especificar en pixeles (ej. ROWS=100,300)
o en porcentajes (ej. ROWS=40%,60%). Al igual que con las tablas se puede utilizar un asterisco (*)
para aquellos valores que no deseemos especificar y que quedarán librados al tamaño disponible (ej.
COLS=50,*).
El tag FRAME es el que se utiliza para especificar que páginas cargar en cada frameset. Este tag tiene
tres opciones básicas:
• SRC: especifica que página se va a cargar
• NAME: es el nombre que tendrá el frame. Esto es utilizado por los links que quieran desplegar
el contenido de una página en un frame distinto al que se encuentran.
• SCROLLING: puede ser YES (siempre existirán las barras de desplazamiento), NO (nunca
existirán las barras de desplazamiento, aun si el contenido no entra en la ventana), o nada
(aparecerán las barras solo si son necesarias).
Veamos como sería el HTML principal de una página de noticias que este dividida en tres columnas, en
donde la primera tendrá un conjunto de opciones del sitio (ocupará el 15% de la ventana), la columna
de la derecha tendrá los encabezados de noticias de otros sitios (ocupará un 15% de la ventana), y la
columna central tendrá las noticias del sitio (ocupará lo que quede de la ventana).
El HTML sería:
<HTML>
<HEAD>
Carrera Linux 2008 Programacion PHP 74
<TITLE>Muchos Frames</TITLE>
</HEAD>
<FRAMESET COLS=15%,*,15%>
<FRAME SRC=opciones.html SCROLLING=NO>
Formularios
El HTML no solamente proporciona utilidades para darle formato a la salida sino que nos provee de
algunos elementos para poder interactuar de forma más avanzada con el usuario. Estos componentes
son la base para poder crear CGIs. Los formularios nos permitirán poner botones, cajas de texto, etc, en
nuestras páginas para que el usuario pueda proveer información más completa y poder hacer verdaderas
páginas dinámicas.
Si bien esto es parte de la programación de CGIs (discutida en la próxima clase) diremos que todo lo
que se encuentre en un formulario y tenga asignado un nombre, podrá ser recuperado por el programa
que lo reciba. Cada formulario tendrá también, un programa asociado para procesarlo. Dentro de una
misma página se pueden tener varios formularios (aunque no se pueden anidar) y los componentes que
esten en un formulario no se verán en los demás.
Un formulario queda definido por los tags <FORM> y </FORM>. El tag FORM no tiene una
representación gráfica, sino que simplemente agrupa a todos los componentes que luego agreguemos
en el.
Entre las opciones que tiene FORM podemos encontrar:
• ACTION: aquí se especifica a que programa (scripts) se debe llamar cuando se sube el
formulario (por ejemplo, ACTION=http://www.misitio.com/cgi-
bin/vender.pl)
• METHOD: Determina con que método se subiran los datos del formulario. El método puede
ser GET o POST.
Si el método es GET los valores viajarán a través de la URL (será visible al usuario) y tiene la
desventaja de que el tamaño de la URL es limitado y pueden llegar a perderse parte de los datos
si estos son muy grandes.
Si es POST los valores se pasaron por otra conexión al servidor. La ventaja del POST es que no
se esta limitado con el tamaño, y la desventaja es que se "más lento" (se hace otra conexión).
• NAME: Nombre que tiene el formulario.
Ejemplo:
</FORM>
Carrera Linux 2008 Programacion PHP 75
El tag INPUT
El tag INPUT es el utilizado para ingresar datos. Este tag permite crear cajas de texto, cajas de
contraseña, botones, checkbox, opciones, botones de imágenes y campos escondidos.
Todas estas posibilidades tiene algo en común: todas tienen un nombre que las identifica y tienen un
valor asociado. Estas opciones serán NAME y VALUE respectivamente.
El tag INPUT tendrá también una opción, TYPE, que determinará de cual de todos los componentes
queremos usar.
Si TYPE=TEXT entonces se creará una caja de texto. Si la opción VALUE esta especificada, dicho valor
será el que contenga la caja por defecto. El tipo TEXT tiene dos opciones más: SIZE que determina el
ancho de la caja de texto (cuantos caracteres se verán) y MAXLENGTH que determina cuantos caracteres
admitirá como máximo.
Si TYPE=PASSWORD sera similar a TEXT pero cuando se escribe dentro de esa caja de texto los
caracteres aparecerán como asteriscos (*).
Si TYPE=SUBMIT entonces se creará un botón que permite subir el formulario para ser procesado. El
valor que tenga la opción VALUE será el texto que aparecerá dibujado sobre el botón.
Si TYPE=IMAGE entonces se creará un botón que funciona igual que SUBMIT pero con la diferencia
que este será una imágen. Para ello, se posee una opción extra, SRC, que determinará desde donde se
obtendrá (la URL) la imágen que se desea mostrar.
Si TYPE=HIDDEN entonces se creará un campo escondido. Este tipo de campo es especialmente útil
para programar CGIs, en particular para pasar valores entre distintos formularios.
Si TYPE=CHECKBOX entonces se crearán las clásicas casillas para seleccionar. En este caso el valor
que tenga la opción VALUE será la que se muestre al lado del rectángulo de selección. Si se desea que
por defecto la opción aparezca marcada se debe agregar la opción CHECKED.
Si TYPE=RADIO entonces se crearán la selección de opciones unitaria. Es decir, el navegador agrupará
a todos aquellos componentes de tipo RADIO que tenga el mismo nombre, y solo permitirá que se elija
uno y solo uno de ellos. Al igual que con los CHECKBOX el valor que tenga la opción VALUE será el
texto que se muestre al lado del circulo de selección. Si se desea que por defecto la opción aparezca
marcada se debe agregar la opción CHECKED.
El tag TEXTAREA
Este tag permite crear cuadros de texto bidimensionales. A diferencia de los INPUT TYPE=TEXT los
TEXTAREA permiten ingresar varias líneas de texto. Cada línea estará delimitada por un \r\n (para
cuando se procesa el formulario). Este tag tiene, por supuesto, la opción NAME para ser identificado
luego desde el CGI. También posee la opciones COLS que determina la cantidad de columnas que
ocupará el cuadro, y ROWS que determina la cantidad de filas que ocupará el cuadro (visualmente).
Este tag, y también a diferencia del tag INPUT, tiene un tag que lo cierra (</TEXTAREA>
obviamente). Todo lo que se encuentre dentro de estos dos tags se tomará como valor por defecto. Se
debe aclarar que solo se permite texto plano dentro de estos dos tags, ya que lo que se escriba como
Carrera Linux 2008 Programacion PHP 76
HTML será ignorado y pasado directamente al cuadro de texto.
El tag SELECT
Este tag se utiliza para crear tanto listas como combobox (listas desplegables). SELECT creará un
cuadro con todas las opciones que se le otorguen y permitirá elegir una o más de ellas. Las opciones se
determinan mediante el tag <OPTION>...</OPTION>. Lo que se encuentre dentro de estos tags
será lo que vera el usuario por pantalla (y por defecto el valor que se obtendrá cuando se sube el
formulario). Si se desea dar otro valor a cada opción se puede utilizar la opción VALUE dentro del tag
OPTION y asignarle el valor que se desee.
También existe la opción SELECTED para que por defecto, esa opción aparezca seleccionada.
El tag SELECT también tiene algunas opciones. Primero tiene la opción NAME al igual que todos los
demás componentes. Posee tambien la opción MULTIPLE la cual le dice al navegador se debe o no
permitir que se elijan más de una opción. También posee la opción SIZE que determina la cantidad de
elementos que se veran al mismo tiempo en pantalla. Si la cantidad de elementos es mayor que la
especificada en SIZE, entonces aparecerá una barra de desplazamiento para poder moverse y elegir
cualquier elemento.
Si no se especifico la opción MULTIPLE y SIZE=1 entonces la lista se convierte en una lista
desplegable.
Ejercicios
1. ¿Cual es la diferencia entre los metodos GET y POST?
2. ¿Que formas de entrada tiene el usuario mediante el tag INPUT?
3. ¿Cual es la diferencia entre el tag OL y UL?
4. ¿Para que sirven los frames?
5. ¿Como armaria una pagina que este dividida en 5 partes, de modo que queden 3 paginas en la
primer fila y 2 en la segunda?
Clase 14 Programación web
Un programa en PHP, dentro de una página web, se puede pensar como un conjunto de secciones de
código PHP introducidas dentro de un archivo HTML.
Entonces, definiremos un bloque de PHP, como lo hemos hecho al inicio, de la siguiente forma:
<?php
# Codigo en PHP
?>
En donde <?php abre el bloque de código y ?> cierra dicho bloque. Todo lo que se encuentre dentro
de este bloque de código se ejecutará como código PHP y la salida (o sea, todo lo que se escriba en la
salida estándar) resultante irá al navegador. Para que nuestro programa genere HTML se utilizará la
función echo.
Carrera Linux 2008 Programacion PHP 77
Por ejemplo, si creamos el archivo hola.php:
<HTML>
<HEAD>
<TITLE>Saludos!</TITLE>
</HEAD>
<BODY>
<?php
echo "Hola Mundo";
?>
</BODY>
</HTML>
Generaremos una página web en PHP que escribe Hola Mundo.
Veamos un ejemplo un poco más complejo:
<HTML>
<HEAD>
<TITLE>Ejemplo</TITLE>
</HEAD>
<BODY>
<?php
?>
</BODY>
</HTML>
Cuando ejecutemos esta página, por primera vez, las variables $x y $s no existirán. Cuando empieza el
ciclo while ambas variables se irán incrementando hasta llegar a $x=9 y $s=55. Esta información se
verá en el navegador:
La suma de antes era:
1 dot
2 dot
3 dot
4 dot
5 dot
6 dot
7 dot
8 dot
9 dot
10 dot
La suma es: 55
Carrera Linux 2008 Programacion PHP 78
Como se podra apreciar, el primer echo no muestra ningún valor para $s, que es lo que intuitivamente
uno supondría ya que es la primera vez que se ejecuta. Sin embargo, cuando volvemos a ejecutar la
página, volverá a producir la misma salida. Esto se debe al hecho que no se comparten estados
(variables) entre dos ejecuciones distintas. Cuando se ejecuta por segunda vez, todas las variables que
se utilizaron antes, no existen hasta que se hayan utilizado.
Esto no quiere decir que es imposible comunicarse entre dos páginas ya que esto es posible utilizando
HTML (links y formularios) o mediante el protocolo HTTP (cookies).
Paso de información entre páginas
Como hemos dicho anteriormente dos ejecuciones de una misma página no comparten sus variables.
Sin embargo, si es posible pasar información entre dos páginas cualquiera (o la misma para el caso que
sea). Cuando se trabaja sobre la Web existen dos métodos: GET (links) y POST (formularios).
Cuando se utilizan links es posible pasar información mediante la URL que llevan. Un link común
sería:
Este link, simplemente apunta al index.html. Ahora, supongamos que poseemos un link que nos lleva a
los proximos 200 resultados (a partir del resultado 400) de una búsqueda:
En esta oportunidad era necesario pasarle a nuestro CGI cierta información para que funcionase como
uno esperaría. Cuando se ejecute no será igual el resultado si se empieza a mostrar desde el resultado
100 que desde el resultado 5000. El script procesará la búsqueda de igual forma en ambos casos pero
mostrará cosas distintas.
Para pasar datos por la URL es necesario separar el archivo de los parámetros usando el signo ?. Luego
cada uno de los parametros tendrá un nombre (fijo para poder encontrarlo despues) y un valor asociado
(que es lo que personaliza la ejecución). Los distintos parámetros se separan luego por ampersands (&).
Desde PHP para obtener estos valores existe el arreglo $_GET. En este arreglo, las claves son los
nombres de los parametros. $_GET es una variable como las demas que se utilizan en PHP. Esto quiere
decir, que cuando se termino la ejecución del CGI, todo su contenido también se pierde junto con todas
las variables. Este arreglo lo cargará PHP automáticamente con la ejecución de cada CGI. Si en una
ejecución dada no se paso ningún parámetro por la URL, entonces $_GET estará completamente vacío.
Si se paso una opción, entonces $_GET tendrá una única entrada.
Veamos esquematicamente como sería el ejemplo anterior:
<?php
# Si hay algo para buscar
if(isset($_GET["criterio"])) {
if(!isset($_GET["desde"])) {
$desde = 0;
} else {
$desde = $_GET["desde"];
}
Se puede observar que el link de la próxima página irá aumentando su campo desde a medida que se
van pasando las páginas, ya que siempre se le pasa el valor que tenia ($desde) más un incremento
($cantidad). Los otros dos campos permanencen fijos (cantidad y criterio).
Formularios
Cuando se necesita que el usuario interactue de manera más contundente (lease, tipee algo
basicamente) debemos recurrir a los formularios.
Un formulario, como lo visto en la guia de HTML, es un conjunto de controles que permiten al usuario
ingresar datos, seleccionar desde un combo, elegir un checkbox, etc. Sin embargo los formularios
tienen otra propiedad: pueden ser enviados. Esto quiere decir que toda la información ingresada podrá
ser utilizada luego (De ser enviada) por un CGI.
La forma en que se pasan los datos es similar a la de los links. En el caso de los formularios cada uno
de los componentes tendrá un nombre (Fijo) que tendrá un valor asociado (lo que ingreso el usuario).
Luego todo este conjunto de claves,valores estarán disponibles desde el arreglo $_POST.
La forma de utilizar $_POST es totalmente igual a la de usar $_GET. La diferencia reside en el origen
de los datos (unos vienen por la URL, generados por nuestro programa y los segundos son lo que
ingreso el usuario).
Veamos un ejemplo de un programa que nos dice si un número ingresado es o no es par:
<HTML>
<HEAD>
<TITLE>Par o no par, esa es la cuestion</TITLE>
Carrera Linux 2008 Programacion PHP 80
</HEAD>
<BODY>
<FORM METHOD=POST>
Numero:<INPUT TYPE=TEXT NAME=nro VALUE=<?php echo $_POST[nro]; ?>
SIZE=5>
<INPUT TYPE=SUBMIT VALUE=Controlar>
<P>
<?php
# No se ingreso nada
if(!isset($_POST["nro"])) {
echo "No se ha ingresado ningun valor todavia";
Recordemos que al igual que $_GET, $_POST será eliminado cuando se termine de ejecutar el
programa y será cargado nuevamente cuando se vuelva a correr el programa. Esta claro que $_POST
será cargado solamente con los valores ingresados en el momento en que se envio el formulario.
El programa es bastante lineal, y su única función es informar sobre los tres posibles estados: No se
ingreso nada, o es la primera vez que se ejecuta ($_POST["nro"] no contiene ningún valor); Se
ingreso un numero que es par (entonces $_POST["nro"] contiene un número par); o se ingreso un
número impar (entonces $_POST["nro"] contiene un número impar).
Diferencias entre el método GET y el método POST
Si bien ambos métodos se utilizan básicamente igual poseen algunas diferencias entre ellos.
Una de ellas ya la mencionames, y es el origen desde donde vienen los datos. En el método GET
vendran junto con la URL, en cambio, en el metodo POST viene por otra conexión.
Antes de continuar aclararemos que las diferencias técnicas mencionadas aquí no afectan a la forma de
programar, sino que se deben utilizar para entender el proceso y saber cuando conviene enviar datos por
GET y cuando por POST.
Los datos del GET, al ir a traves de la URL, viajan al servidor Web junto con el pedido de la página. El
servidor interpretará la URL, la dividirá y se la enviará a nuestro programa. En cambio, cunado los
datos son enviados usando el metodo POST, se generan dos conexiones. La primera sera la común en la
que se pide la página necesaria. A esta, le sigue otra conexión por la cual se enviarán los datos del
POST. Luego, el servidor se encargará de juntar los datos del POST para enviárselos a nuestro
programa.
El método POST nos permitirá pasar una mayor tamaño de datos. El método GET, al estar limitado por
la URL, no aceptará aproximadamente más de 512bytes. En cambio el tamaño de un POST es del orden
Carrera Linux 2008 Programacion PHP 81
de los megas.
Ejercicios
1. ¿Como es el ciclo para interactuar con un usuario mediante formularios? ¿Como se recuperan
desde una pagina web los valores ingresados por el ususario?
2. Hacer una pagina que liste todos los usuarios del sistema (usando de base el archivo
/etc/passwd). Cada usuario debe ser un link a otra pagina, la cual debera mostrar toda la
informacion disponible del mismo (usando de base el mismo archivo).
Ambos listados deberan estar dentro de tablas HTML.
3. Hacer una pagina que permita al usuario ingresar un numero. Luego la pagina ira indicando si el
numero es menor, mayor o igual a uno elegido al azar. Dicho numero al azar debera ser el
mismo durante todo el juego (se debera ir pasando entre las diferentes paginas en un tag INPUT
del tipo HIDDEN).
4. Modificar el programa anterior para que el juego se reinicie solo cuando el usuario halla
adivinado el numero. Tambien se debe agregar un boton para reiniciar el juego manualmente.
Agregar tambien un contador para que indique en cuantos intentos se adivino el numero.
5. Se requiere crear un Message Board (libro de visitas) para un sitio web. Un message board (de
aqui en adelante MB) consiste simplemente en permitir al usuario dejar mensajes en el sitio y
que todos puedan ver estos mensajes (los mensajes no tienen relacion entre ellos).
Por restriccion del sitio no todos los usuarios pueden escribir en el MB. Solo aquellos que esten
registrados lo podran hacer.
Se debera crea una serie de scripts para agregar usuarios (y ver su informacion), ingresar
mensajes, y ver los mensajes ingresados. Para registrar a un usuario se le debe pedir cierta
informacion:
* nickname: alias con el que se vera al usuario
* nombre y apellido: reales del usuario
* email: direccion de correo electronico
* contraseña: su contraseña
Una vez dado de alta al usuario este podra ingresar mensajes. Cuando se ingresa un mensaje se
debe permitir ingresar el usuario, la contraseña y el mensaje propiamente dicho.
Los usuario seran listados dentro de una lista desplegable (o sea SELECT no multiple con
SIZE=1), y la contraseña en una caja de contraseñas (PASSWORD). El mensaje, por tener un
tamaño considerablemente largo, debe ser ingresado mediante un TEXTAREA. Tambien sera
registrada la fecha y hora en que se realizo la transaccion.
El usuario solo podra agregar el mensaje si la contraseña ingresada es correcta.
Los mensajes se listaran uno debajo del otro con el siguiente formato:
Fecha y hora
Nick_del_usuario (email) escribio:
Mensaje
Carrera Linux 2008 Programacion PHP 82
Donde "Fecha y hora" es la fecha y hora en que se genero el mensaje, "Nick_del_usuario" es un
link a al informacion del usuario, "email" es un link al email (o sea, un
mailto:usuario@serv.com) y "Mensaje" es el mensaje ingresado por el usuario. Cabe destacar
que el Mensaje debe estar separado por lineas de la misma forma en que la ingreso el usuario.
Como el sitio sera muy visitado se pide que se muestren de a 5 mensajes por vez ordenados del
mas reciente al mas antiguo. Se debe proveer entonces, en la parte inferior de la pagina, links
para ir hacia atras y hacia adelante.
Clase 15 Cookies y Manejo de Sesiones
Las cookies son una forma de pasar información entre el servidor y el cliente de forma tal que no se
pierda entre distintos pedidos de páginas. Esto se utiliza ya que cada vez que el cliente pide una página
se crea una conexión nueva independiente de las páginas que ya ha pedido, por lo que nos permite ir
pasando información entre formularios. Las cookies tienen la ventaja que se envian una sola vez y esta
se sigue reenviando a todas las páginas que se visiten posteriormente sin necesidad de agregar código
extra (a no ser que se desee modificar el valor de la misma).
Las cookies deben ser enviadas junto con la cabecera HTTP de respuesta que genera el servidor cuando
un cliente pide una página. Por eso las cookies deben ser enviadas antes de que haya cualquier tipo de
salida en HTML (antes del tag <HTML> y antes de que haya un solo espacio en blanco).
Para enviar una cookie disponemos de la funcion setcookie:
Las únicas opciones que son obligatorias son $nombre y $valor. $nombre debe ser único ya que
no pueden existir dos cookies con el mismo nombre.
La opción $expira determina el tiempo que durará (en segundos) la cookie. Luego de que pase ese
tiempo se deberá generar una nueva cookie. Para darle un tiempo útilizaremos la función time() que
nos devuelve la cantidad de segundos a la fecha de hoy y a eso le sumaremos el tiempo que deseemos
que dure. Por ejemplo, time() + 3600 hará que la cookie expire dentro de una hora.
La opción $dominio especifica un dominio al cual unicamente le será válido al navegador devolver la
cookie. Si se especifico el dominio www.misitio.com solo será enviada la cookie si la página pedida
pertenece a ese dominio (sino todos los sitios podrian ver información confidencial).
La opción $path es similar a domain. Solo enviará la cookie si la página pedida pertenece a ese
directorio (o subdirectorio).
Finalmente si la opción $seguro esta activada solo se enviará la cookie si el servidor y el cliente
soportan el uso de encriptación (SSL Secure Socket Layer).
Para recuperar el valor de una cookie existe un arreglo llamado _COOKIE. Este arreglo posee una
entrada para cada cookie que se halla enviado, en donde la clave será el nombre de la cookie y el valor
será el valor que tenga la cookie.
El siguiente ejemplo consta de 4 archivos:
Carrera Linux 2008 Programacion PHP 83
Archivo: menues.php
<?php
$menues = array("Configurar" => "configurar.php", "Principal" => "principal.php",
"No Principal" => "no_principal.php");
Archivo: configurar.php
<?php
require_once("menues.php");
$colores = array("Roj izo" => "#FF9999", "Verd oso" => "#99FF99", "Azul ado" =>
"#9999FF");
if(isset($_COOKIE["color"])) {
$color_elegido = $_COOKIE["color"];
}
if(isset($_POST["actualizar"])) {
setcookie("color", $_POST["color"]);
$color_elegido = $_POST["color"];
}
?>
Carrera Linux 2008 Programacion PHP 84
<HTML>
<HEAD>
<TITLE>Configuracion de color</TITLE>
</HEAD>
<BODY BGCOLOR=<?php echo $color_elegido;?>>
<?php
mostrar_menu("Configurar", $menues);
?>
<FORM METHOD=POST>
Eliga un color:
<?php
crear_lista("color", $colores, $color_elegido);
?>
<br>
<INPUT TYPE=SUBMIT NAME=actualizar VALUE=Actualizar>
</FORM>
</BODY>
</HTML>
Archivo: principal.php
<?php
require_once("menues.php");
$colores = array("Roj izo" => "#FF9999", "Verd oso" => "#99FF99", "Azul ado" =>
"#9999FF");
if(isset($_COOKIE["color"])) {
$color_elegido = $_COOKIE["color"];
}
if(isset($_POST["actualizar"])) {
setcookie("color", $_POST["color"]);
$color_elegido = $_POST["color"];
}
?>
<HTML>
<HEAD>
<TITLE>Configuracion de color</TITLE>
</HEAD>
<BODY BGCOLOR=<?php echo $color_elegido;?>>
<?php
mostrar_menu("Configurar", $menues);
?>
<FORM METHOD=POST>
Eliga un color:
<?php
crear_lista("color", $colores, $color_elegido);
?>
<br>
<INPUT TYPE=SUBMIT NAME=actualizar VALUE=Actualizar>
</FORM>
</BODY>
Carrera Linux 2008 Programacion PHP 85
</HTML>
Archivo: no_principal.php
<?php
require_once("menues.php");
$color_elegido = $_COOKIE["color"];
?>
<HTML>
<HEAD>
<TITLE>Pagina Principal</TITLE>
</HEAD>
<BODY BGCOLOR=<?php echo $color_elegido;?>>
<?php
mostrar_menu("Principal", $menues);
?>
<H1 align=center>¡ESTA ES LA PAGINA PRINCIPAL!</H1>
La moraleja del dia es:<br><br>
<i>El problema no es que los programas tenga errores,
sino que los errores tenga programas.
</i>
</BODY>
</HTML>
La idea de este ejemplo es mostrar que las cookies se siguen enviando solas sin necesidad de agregar
nada. Para ello disponemos de 3 páginas: configurar.php, principal.php y no_principal.php.
En la primera de ellas configuraremos que color de fondo queremos ver. Luego si pasamos a cualquiera
de las otras dos veremos que estan del color que seteamos sin necesidad de agregar nada.
Primero que nada haremos una aclaración global. El archivo menues.php tiene definido un arreglo con
todos los menues que existan y una función la cual muestra el menu actual. De esta forma es sencillo
agregar más opciones al menu, ya que solo hara falta agregar una entrada en dicho arreglo y bastará
para que se refleje en todas las páginas. La función mostrar_menu queda como ejercicio
interpretarla y entenderla.
La función crear_lista genera los tag de HTML necesarios para crear un combo con todas las
opciones que se le pasen a travez del arreglo $opciones.
El archivo configurar.php es el que almacena toda la magia de este sistema. La idea general es tener una
cookie que se llame color y que tenga como valor el color que se quiere mostrar (en el formato que usa
HTML). Si la cookie no esta seteada quedará el tag BGCOLOR de BODY vacío, que por lo general, los
navegadores lo interpretan como blanco.
Para comenzar saltearemos los primeros dos ifs y analizaremos el HTML generado.
El tag BODY posee la opción BGCOLOR (para darle el color de fondo) seteada con el valor de una
variable (color_elegido) que será la que contenga el color. Luego se ejecutará la función
mostrar_menu para mostrar el menu del sistema con la opción actual seleccionada (Configurar).
Luego se crea un formulario y un tag SELECT (con la función crear_lista) para poder elegir entre
todos los colores que hay definidos.
Ahora analizemos el segundo if. Este se ejecutará cuando se presione sobre el botón actualizar. Su
Carrera Linux 2008 Programacion PHP 86
tarea será la de crear la cookie si no existe y modificarla si existe. Simplemente hace falta llamar a la
función setcookie para hacer esto. El primer parámetro es el nombre de la cookie (color en nuestro
ejemplo) y el segundo el valor (el que fue seleccionado en el SELECT). Esta función se encargará de
crear la cookie si no existe o de modificarla si ya existe. Por lo tanto, cuando se envie esta página, le ira
al navegador la respuesta junto con una cookie que se reenviará en las proximas paginas que pida.
Como acabamos de seleccionar un color, le cambiamos el valor a la variable color_elegido al que
se acaba de elegir para que en esta misma ejecución ( que no recibio ninguna cookie) se vea el color
elegido.
El segundo if es para setear el color cuando se accede a la página y ya se esta enviando la cookie. Si
ya habiamos seteado el color y navegamos por las demás páginas, cuando volvamos aquí será necesario
(al igual que en las demás páginas) setear el color basandose en la cookie existente. Por eso, si la cookie
existe se usa ese color.
Las otras dos páginas son similares. Simplemente toman el valor de la cookie y lo mandan a la opción
BGCOLOR directamente. Si la cookie no llega a existir simplemente quedará vacío el color y el
navegador mostrará el fondo en blanco. El resto de la página es HTML puro para completar con algo
interesante en el ejemplo.
Veamos otro ejemplo. Este ejemplo sirve para contar cuantas veces se presionó el boton de refresh en
una página.
Archivo: cuenta_refresh.php
<?php
if(isset($_COOKIE["cont"])) {
$contador = $_COOKIE["cont"] + 1;
} else {
$contador = 0;
}
setcookie("cont", $contador);
?>
<HTML>
<HEAD>
<TITLE>Cuenta refresh</TITLE>
</HEAD>
<BODY>
<h1>Contador de refreshs</h1>
Se apretaron <b><?php echo $contador; ?></b> veces el boton de refresh<br>
Presione el boton de refresh para incrementar el contador
</BODY>
</HTML>
La magia de este ejemplo reside en el if. Este if determina si existe o no la cookie llamada cont. Si no
existe (recién se carga la página) inicializa el contador en 0 y genera una cookie con valor 0. Si llega a
existir le suma 1 al valor anterior y crear (o modifica mejor dicho) una cookie con igual nombre pero
con un valor 1 más grande.
Cada vez que se recargue la página la cookie se enviará y se incrementará hasta el infinito o hasta que
alguien se aburra de apretar refresh.
Carrera Linux 2008 Programacion PHP 87
Sesiones
Al utilizar cookies toda la información que nos interesa viaja constantemente entre el cliente y el
servidor. Con cada acceso de página toda la información tiene que viajar dos veces. Esto, además de
poco eficiente, hace que sea más probable que alguien modifique esa información intencionalmente,
alterando el normal funcionamiento del sitio.
Para ello existen las sesiones. Una sesión es una conjunto de variables que permanencen en el servidor
y solo viaja del cliente al servidor (y viceversa) un identificador de la misma. De esta forma, es posible
tener para cada cliente la información pertinente (distinta para cada usuario) en forma local y solo viaja
el mínimo de información necesaria. Utilizando sesiones resulta más sencillo identificar que usuario
esta accediendo a cada pagina ya que cada usuario tendra su propia sesión.
Inicio de una sesión
Para crear o utilizar una sesión en PHP utilizaremos la función session_start. Esta función no
lleva ningún parámetro y su tarea es crear una nueva sesión o utilizar una que ya exista. Hay que
destacar que las sesiones deben inicializarse, al igual que con las cookies, antes de que halla cualquier
tipo de salida HTML.
Cuando tenemos una sesión podemos crear variables de sesiones. Estas variables no se perderán cuando
se termine el script, sino que quedarán almacenadas en el servidor para la próxima vez que se corra el
script con esa misma sesion (para el mismo usuario).
Para inicializar la sesión solo hay que ejecutar:
session_start();
Cuando se genera la sesión se le crea un identificador único, el cual puede ser obtenido mediante la
función session_id.
Variables de sesión
Luego tenemos dos formas de crear variables de sesiones. La primera es utilizando la función
session_register. Esta lleva como parámetro el nombre de la variable PHP que se guardará. Por
ejemplo:
session_register('persona');
$persona = "Mr Blue Sky";
Aquí la variable $persona (no importa cuando se llama a session_register, puede ser antes o
despues de usar la variable) estará disponible en la sesión. También es posible guardar arreglos de igual
forma:
session_register('personas');
$persona = array("Mr Blue Sky", "Mister IO", "Vespuscio");
Carrera Linux 2008 Programacion PHP 88
La segunda forma de guardar variables de sesión es utilizando el arreglo _SESSION. Este es un
arreglo que crea automaticamente PHP (al igual que _POST y _GET) el cual contiene todas las
variables de sesión creadas en el momento de la ejecución. Si lo modificamos, los cambios se verán
reflejados en la próxima ejecución. Esta forma es la recomendada ya que es la más clara y la más
segura. Para hacer el mismo ejemplo de antes:
Las variables de sesión se podran acceder, entonces, desde el mismo arreglo _SESSION. Si en otro
script queremos mostrar todas las personas que tenemos cargadas hasta el momento solo hara falta:
foreach($_SESSION['personas'] as $nombre) {
echo "$nombre<br>";
}
ya que $_SESSION['personas'] es un arreglo válido que ya fue cargado.
Destrucción de la sesión
Para terminar con la sesión debemos llamar a la función session_destroy (no lleva argumentos).
Esta función debe ser llamada luego de llamar a session_start, asi PHP puede identificar que
sesión destruir.
Esta función no elimina la cookie de la sesión que viaja entre el cliente y el servidor, por lo que habra
que agregar un mecanismo extra para determinar cuando se termino la sesión.
Controlando las variables de sesión
Cuando utilizamos sesiones es útil saber si esta o no cargada una variable en la sesión. Para ello (y una
vez abierta la sesión con session_start) dispondremos de la función session_is_register
la cual dándole el nombre de la variable nos dira verdadero o falso si esta o no esa variable registrada.
Por ejemplo:
if(session_is_register('persona')) {
echo "La persona esta presente<br>";
} else {
echo "La persona no ta<br>";
}
Si antes de ejecutar este código, habíamos ejecutado el ejemplo anterior, el if será verdadero sino será
falso.
Verificando la sesión
Como no es posible eliminar la cookie que utiliza la sesión, siempre la sesión estará presente. Para
saber si un usuario esta o no "logueado" en la sesión, debemos guardar por lo menos una variable fija
Carrera Linux 2008 Programacion PHP 89
que mientras este, la sesión será válida. Cuando el usuario se salga del sistema (mediate
session_destroy o por que se le acabo el tiempo) esta variable sí se perdera y nuestro script podrá
notarlo.
Para ello, por ejemplo, guardaremos en la sesión una variable que le daremos el nombre ID_SESION
(puede ser cualquiera) y le daremos el id de la sesión actual.
Cuando el usuario inicia la sesión ejecutaremos (luego de session_start):
$_SESSION['ID_SESSION'] = session_id();
o
session_register("ID_SESSION");
$ID_SESSION = session_id();
ya que es lo mismo.
Luego en cada script al cual solo los usuarios válidos puedan acceder, habrá que controlar por lo menos
que esta variable exista:
session_start();
if(!session_is_register("ID_SESSION")) {
echo "ERROR!!! PELIGRO!!! DANGER!!! CORRAN POR SUS VIDAS!!!";
exit(); # No ejecuta mas nada
}
Si paso por este if, entonces es seguro mostrar la página.
Veamos un ejemplo:
Archivo: control_acceso.php
<?php
session_start();
if(!session_is_registered("ID_SESION")) {
include('error.html'); # Trae la pagina con el mensaje de error
exit(); # Termina la ejecucion del script
} else {
echo "<h1 align=center>Acceso Permitido</h1>";
}
?>
Archivo: login.php
<?php
require_once("funciones.php");
session_start();
mostrar_menu("LOGIN", $menues);
?>
Archivo: pagina1.php
<?php
require_once("control_acceso.php");
require_once("funciones.php");
mostrar_menu("Pagina 1", $menues);
echo "<h2>ID_SESION: ", $_SESSION["ID_SESION"], "</h2>";
<?php
require_once("control_acceso.php");
require_once("funciones.php");
mostrar_menu("Pagina 2", $menues);
echo "<h2>ID_SESION: ", $_SESSION["ID_SESION"], "</h2>";
<?php
require_once("control_acceso.php");
require_once("funciones.php");
mostrar_menu("LOGOUT", $menues);
session_destroy();
?>
<BODY BGCOLOR=#666677>
<H1 ALIGN=CENTER>Venias de la pagina <?php echo $_SESSION[pagina_anterior]; ?>
y ahora... Estas afuera...</H1>
<BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR>
<P ALIGN=RIGHT><FONT SIZE=-2>adios . . .</FONT></P>
</BODY>
</HTML>
Archivo: funciones.php
<?php
$menues = array("LOGIN" => "login.php", "Pagina 1" => "pagina1.php", "Pagina 2"
=> "pagina2.php", "LOGOUT" => "logout.php");
<HTML>
<HEAD>
<TITLE>Acceso denegado</TITLE>
Carrera Linux 2008 Programacion PHP 92
</HEAD>
<BODY BGCOLOR=#FF9988>
<H1 ALIGN=CENTER>¡ACCESO DENEGADO!</H1>
Usted esta tratando de acceder a un area restriginda a la cual (ovbiamente)
usted no tiene acceso.<br>
Presione <A HREF=login.php>aqui</A> para ir a la pagina principal o vayase a
otro sitio distinto que sea mas divertido que este.
<br>
Ah, ¡y muchas gracias por visitar nuestro sitio web!
</BODY>
</HTML>
Este ejemplo consta de 4 páginas principales: login.php, pagina1.php, pagina2.php y logout.php.
El inicio del sistema debe ser utilizando el script login.php. Este script crea una nueva sesión y si no
existía asigna el nuevo id a la variables de sesión ID_SESION (usada para controlar los accesos). Si ya
existía esa variable simplemente emite un mensaje.
Este proceso da de alta la sesión (en un sistema que tiene muchos usuarios antes de hacer este paso se
deberia verificar que el usuario y exista y la contraseña sea correcta). Luego se puede viajar a las demas
páginas.
Las páginas pagina1.php y pagina2.php son casi idénticas (salvo por la sabiduría del mensaje que
muestra) por lo que discutiremos una sola de ellas.
La magia esta en que todas las páginas que tenga que ser restrigindas incluyan el archivo
control_acceso.php. Este archivo revisa si existe la variable ID_SESION, si no existe, es porque el
usuario se ha deslogueado o a tratado de acceder a una página sin haber pasado por la de login.
En cualquier caso, la variable de sesion ID_SESION no estará definida y le traerá el archivo error.html
(con un hermoso mensaje de error) y terminará la ejecución del script (con la función exit) para que no
se ejecute más nada. Si la variable existía, mostrará un mensaje demostrativo (Este mensaje no suele
estar en sistemas reales).
Finalmente el script logout.php destruir todas las variables de sesión por lo que el usuario estará "fuera
del sistema". Para ello simplemente utiliza la función session_destroy.
Una vez ejecutada esta página será imposible acceder a pagina1.php o pagina2.php o al mismo
logout.php (intentarlo para ver el mensaje de error).
Desconectando a los usuarios
Si bien le es posible a los usuarios desconectarse utilizando el logout (que debería dar siempre mi
sistema), sería bueno poder desconectar a los usuarios si al cabo de un tiempo el usuario no hizo nada
(o sea no accedio a ninguna página).
Esto se limita dandole un tiempo máximo a la cookie de ID de sesión para que no se acepte más luego
de ese tiempo.
Una forma es configurándolo en el archivo de configuración de PHP (php.ini). Allí hay que buscar la
entrada session.cookie_lifetime y ponerle el valor (en segundos) al cual queremos que se
desconecte el usuario por inactividad. Por defecto tiene valor 0 que es ilimitado.
La segunda opción es setearlo manualmente para cada acceso. Es posible, entonces, modificar
manualmente la duración de la cookie. Para ello existe la función set_cookie_params a la cual
Carrera Linux 2008 Programacion PHP 93
podemos pasarle cuanto deseamos que dure la cookie a partir del momento en que se devuelve la
página. Esto habría que setearlo en el archivo control_acceso.php (o el análogo que usen) para que cada
vez que se accede a una página se renueve el tiempo.
Sería:
session_start();
session_set_cookie_params(900); # 900 segundos = 15 minutos
Si en 15 minutos el usuario no accede a nada, la cookie se eliminará del servidor. Por lo tanto, cuando
quiera volver a acceder, la verificación en control_acceso.php fallará y estará fuera del sistema.
Ejercicios
1. ¿Como funciona una cookie? ¿Como puedo recuperarlas desde mis scripts?
2. ¿De que sirve una sesion? ¿Como se pueden utilizar desde PHP?
3. Modificar el programa 3/4 de los ejercicios de la clase 14, para que los valores del numero al
azar, cantidad de aciertos, cantidad de fallos y cantidad de pasos se pasen a traves de cookies
4. Modificar el programa anterior para que los datos se guarden en una sesion en lugar de enviarse
por cookies
5. Se pide crear un carrito de compras sencillo.
Como base de datos de articulos utilizaremos un diccionario llamado articulos el cual sera
similar al siguiente:
my $articulos = array("Tornillo" => 0.1, "Tuerca" => 5.76, "Sillas" =>
39.25);
y un articulo con la cantidad de stock que hay de cada uno:
my $stock = array("Tornillo" => 1000, "Tuerca" => 200, "Sillas" => 50);
luego se debe generar una pagina que liste todos los articulos existentes y le permita al usuario
agregar a su carrito cuantos desee.
Finalmente, debe existir un link a una pagina que le haga un listado de todo lo pedido con total
incluido.
Carrera Linux 2008 Programacion PHP 94
Clase 16 Introducción a las bases de datos
relacionales y al Lenguaje de Definición de
Datos
MySQL es un motor de base de datos. La pregunta es ahora, ¿que es un motor de base de datos? Bien,
un motor de base de datos es un servidor el cual presta servicios para acceder y manipular datos. Esto
se hace utilizando el lenguaje SQL (Structured Query Language Lenguaje Estructurado de Consulta).
Dentro del motor los datos se almacenarán en tablas que a su vez estas se encuentran dentro de una base
de datos. Para aclarar un poco, diremos que dentro de un mismo motor pueden existir varias base de
datos distintas funcionando simultaneamente. Una base de datos agrupará datos del mismo proyecto
(aunque esto es totalmente arbitrario). En una base de datos se almacenarán tablas (también conocidas
como relaciones). En las tablas es en donde efectivamente se almacenará la información. Una tabla
consiste en uno o más atributos, donde un atributo es un tipo de valor que si quiere guardar. Por
ejemplo, si tenemos una tabla que guarda la información de un cliente, esta tendrá como atributos el
nombre, el código, la dirección, el teléfono, etc. Dentro de la tabla se podrá ir, luego, insertando
entradas con estos datos. A estas entradas se las conoce como filas, tuplas o registros. En definitiva una
tabla será como una matriz donde las columnas representan los atributos y las filas las tuplas.
Dentro de una tabla exisitrá uno o más campos que sirven para identificar a una fila de forma unívoca.
Estos campos se los conoce como claves alternativas. Podrán existir varias claves alternativas distintas y
se eligirá una como clave primaria. La clave primaria es una clave alternativa que se usará cuando se
quiera hacer referencia a una entrada específica de la tabla.
La idea de tener toda la información en un solo motor es para evitar la redundancia. De esta forma si
cambia, por ejemplo, el nombre de un cliente, entonces solo hará falta cambiarlo en la tabla de clientes
y automaticamente se vera reflejado en cualquier parte del programa que obtenga el nombre del cliente.
Esto se logra ya que la información de, en este caso el cliente, se encuentra en un único lugar. Cuando
se necesite buscar o hacer referencia a ese cliente se lo hará por la clave primaria logrando así el
cometido. Existiran otras tablas que necesitarán registrar al cliente (por ejemplo en una venta). Estas
tablas tendrán solamente como uno de sus campos a la clave primaria del cliente (digamos su código).
De esta forma, cualquier cambio que hagamos en la tabla de clientes no afectará a las demás que
pueden funcionar independientemente de este hecho. En la tabla de ventas, el atributo del código del
cliente será una clave foránea o externa (o sea, que hace referencia a otra tabla). Se le puede obligar al
motor de base de datos que compruebe en el momento de insertar una fila, en la tabla ventas, exista en
la tabla clientes al cliente que se esta tratando de ingresar. Esto es útil para asegurar que no entre basura
en la información.
Existen tres sublenguajes dentro de lo que hoy en día es SQL:
a. Data Definition Lenguage (DDL) (Lenguaje de Definición de Datos): Básicamente esto
incluirá las sentencias CREATE, DROP, ALTER
b. Data Manipulation (Management) Language (DML) (Lenguaje de Manipulación
(Administración) de Datos): Básicamente esto incluirá las sentencias SELECT, INSERT,
DELETE, UPDATE
Carrera Linux 2008 Programacion PHP 95
c. Security Management Language (SML) (Lenguaje de Administración de Seguridad):
Básicamente esto incluirá las sentencias GRANT, REVOKE
Introducción al servidor MySQL
Para instalar el servidor MySQL primero se deberá descargar el paquete desde su sitio web
(www.mysql.org). La instalación es sencilla, bajando el paquete que contiene los binarios
(recomendado).
En principio se debe desempaquetar el tgz en el directorio /usr/local/mysql. Ese será el directorio raíz
de nuestro servidor.
Luego hay que darle los siguientes comandos desde el shell:
cd /ur/local/mysql
scripts/mysql_install_db
chown -R root .
chown -R mysql data
chown -R mysql .
Una vez hecho esto ya estará listo para ser minimamente ejecutado.
Luego para iniciarlo dentro del directorio supportfiles se encuentra el script mysql.server (este puede
ser usado para ponerle en el rc.d y se ejecute automaticamente). Entonces ejecutaremos:
support-files/mysql.server start
y si todo marcho bien el servidor se estará ejecutando.
Para conectarnos con el servidor utilizaremos el comando mysql. Desde el shell simplemente
ejecutaremos:
mysql
y nos habremos conectados contra el servidor utilizando el usuario actual. Una vez hecho este paso se
podran ingresar todos los comandos que se describiran a partir de ahora.
El manejo de usuarios se verá en clases posteriores, por lo tanto, será necesario conectarse como root al
servidor ya que es el único usuario que existe en el motor al momento de instalarlo (¡y hasta no tiene
contraseña!).
El Lenguaje de Definición de Datos (DDL)
NOTA: De aquí en adelante en la sintaxis de los comandos lo que se encuentre encerrado entre
corchetes se interpretará como que es de caracter opcional. Los corchetes no forman parte de la
sintaxis de la sentencia en sí, solo sirve para expresar la opcionalidad de lo que encierran.
Cuando se encuentre un símbolo de tubería (|) se interpretará como un opción. Se podrá utilizar lo que
se encuentra a la izquierda del mismo o la derecha pero no ambas opciones.
Carrera Linux 2008 Programacion PHP 96
CREATE
El primer comando del DDL es el CREATE. CREATE nos permitirá crear base de datos y tablas. Para
crear una base de datos escribiremos:
Esto creará la nueva base de datos. Luego sera necesario elegirla para poder crear las tablas dentro de
ella. Para eso utilizaremos el comando USE:
USE nombre_de_la_bd;
Lo complejo aquí es crear las tablas ya que en ellas reside toda la inteligencia. Para ello utilizaremos
CREATE de la siguiente forma:
La definicion_create serán todas los atributos que tendra la tabla además de que allí se podran
definir, por ejemplo, la clave primaria.
La sintaxis de definicion_create es:
La primera de las opciones sirve para agregar un campo en la tabla. nombre_columna será el
nombre que tendrá el campo y tipo será el conjunto de valores que aceptará ese atributo (ver cuadro
más adelante). La opción NOT NULL o NULL sirve para especificar si ese campo puede o no tomar el
valor NULL. El valor NULL significa que no se tiene información sobre ese campo y es distinto a
cualquier otro valor que pueda llegar a contener ese campo.
La opción DEFAULT sirve para que en el caso de que un campo quede librado al motor para ser
llenado, el motor utilizará el valor que nosotros le especifiquemos.
La opción AUTO_INCREMENT se utiliza para que ese campo vaya auto incrementandose
automaticamente a medida que se agregan valores.
Finalmente si se especifica la opción PRIMARY KEY, ese atributo quedara elegido como clave
primaria.
La segunda alternativa se utiliza para especificar cual o cuales atributos serán la clave primaria. Si la
clave primaria esta compuesta por más de un atributo debera ser especificada de esta forma y no
dándole la opción PRIMARY KEY a cada atributo.
Finalmente la opción UNIQUE sirve para especificar que columnas serán claves alternativas, es decir,
que columnas tendran valores que no podran repetirse en ninguna otra fila.
Entre los tipos de datos que hay para una columna podemos encontrar:
Carrera Linux 2008 Programacion PHP 97
Tipo Tamaño (bytes)
TINYINT 1
SMALLINT 2
MEDIUMINT 3
INTEGER 4
BIGINT 8
FLOAT 4 u 8
DATE 3
DATETIME 8
TIMESTAMP 4
TIME 3
CHAR(M) M bytes donde 1 <= M <= 255
L+1 bytes donde L<=M y 1<=M<=255
VARCHAR(M)
L es la cantidad de caracteres usados
TINYBLOB/TINYTEXT L+1 L<2^8
BLOB/TEXT L+2 L<2^16
MEDIUMBLOB/MEDIUMTEXT L+3 L<2^24
LONGBLOB/LONGTEXT L+4 L<2^32
ENUM(valor1,valor2,...) 1 o 2
Finalmente el campo opciones en la definición de la tabla es:
[ COMMENT = "Comentario" ]
[ TYPE = {BDB|HEAP|ISAM|MyISAM|InnoDB|Merge} ]
La primer opción sirve para darle una descripción a la tabla para explicar su contenido. La segunda
opción sirve para especificar el tipo de tabla que se utilizará. Por defecto se utiliza el tipo MyISAM que
es el propio de MySQL. El otro tipo interesante es InnoDB que da soporte para hacer transacciones.
Carrera Linux 2008 Programacion PHP 98
DROP
La sentencia DROP se utilizará para destruir una tabla o una base de datos. Cuando se ejecuta DROP
sobre una tabla se perderá todo su contenido y además la estructura de la tabla. Si se baja una base de
datos se perderán todas las tablas con todos su contenido. Para borrar una tabla ejecutaremos:
y para bajar una base de datos ejecutaremos:
ALTER
Cuando se desea hacer una modificación a una tabla que ya existe (y probablemente tenga muchos y
valiosos datos cargados) se utiliza la sentencia ALTER TABLE. La sintaxis de esta sentencia es la
siguiente:
especificacion será la acción a tomar sobre la tabla. Encontraremos:
La primera de las posibilidades nos permite agregar una nueva columna a la tabla. Para ello
utilizaremos la misma sintaxis que en el CREATE (definicion_create). Lo diferente esta en el
opcional último parámetro. Este nos permite determinar en que posición agregaremos el atributo: si irá
al principio (FIRST) o luego de que columna (AFTER). Si no se especifica ninguno irá al final.
La segunda posibilidad nos permite asignarle la clave primaria a la tabla (similar a como se hacia en el
CREATE).
La tercera y cuarta posibilidad nos permiten quitar una columna (junto con todos sus datos) o quitarle
las claves primarias a la tabla.
La últimas dos posibilidades nos permiten cambiar a un atributo. Si utilizamos CHANGE podremos
cambiarle al atributo no solo la definición sino tambien el nombre del atributo (recuerden que en
definicion_create habia que especificar el nombre de la columna).
Si utilizamos MODIFY le podremos cambiar todas las opciones a una columna salvo su nombre.
Carrera Linux 2008 Programacion PHP 99
Ejemplo
Esta es una base de datos de ejemplo creada con datos generados al azar la cual servirá para los
ejemplos de esta clase y las siguientes.
El script con los datos a cargar puede ser descargado desde el sitio.
La base de datos de ejemplo(aviones.sql):
##################################################################################
######
# Reglas de integridad
Ejercicios
1. ¿Que es y para que sirve SQL?
2. ¿Es posible modificar la estructura de una tabla luego de ser creada? ¿Que problemas puede
traer aparejados?
3. Explicar para que sirve las sentencias CREATE, DROP y ALTER. ¿A que sublenguaje del SQL
corresponden?
4. Se pide generar el modelo para una aplicación que posee las siguientes características:
Se quiere generar una agenda. La misma usará como base un conjunto de personas. De las
misma se quiere poder almacenar: nombre y apellido; dirección; país; telefonos muchos y de
distintos tipos (casa, celular, trabajo, fax); fecha de nacimiento; observación.
Se debe tener precargados en la base de datos a los distintos países. Luego se debe poder
almacenar eventos. Los eventos tendrán una descripción, una observación, una fecha asociada (y
Carrera Linux 2008 Programacion PHP 103
además la hora y duración), y, opcionalmente, una hora asociada. Para cada evento, se debe
poder agregar los participantes (uno o más) del mismo. Estos deben estar ya cargados en la base
como una persona.
Los eventos deben estar categorizados según una lista de categorias cargada.
5. Se sugiere modelar algún sistema a voluntad sobre algún tema de interes particular.
Clase 17 Lenguaje de Manipulación de Datos
INSERT
La sentencia INSERT es la que se utiliza para agregar filas a una tabla.
Su sintaxis es:
Esta sentencia agregará valores a la tabla nombre_tabla. Lo que se encuentra entre paréntesis será
un registro a agregar. Hay que destacar que la cantidad de valores corresponderá a la cantidad de
columnas que tiene la tabla. El valor1 corresponderá a la primer columna, el segundo valor a la
segunda columna y así sucesivamente. También se permite especificar varias tuplas en una misma
sentencia INSERT separándolas por comas.
Por ejemplo para agregar un registro a la tabla PAIS podríamos escribir:
o si supieramos que ID queremo darle (235 por ejemplo), podríamos escribir:
DELETE
La sentencia DELETE sirve para eliminar tuplas de una tabla.
Su sintaxis es:
Si se llama esta sentencia sin la cláusula WHERE, DELETE eliminará todos los registros de la tabla.
Esto no es lo mismo que hacer un DROP, ya que la tabla seguirá existiendo. La cláusula WHERE se
Carrera Linux 2008 Programacion PHP 104
utiliza para seleccionar que tuplas se quiere borrar. Las tuplas a borrar serán todas aquellas que
cumplan con la condición especificada en definicion_where. Esta definición se verá en detalle en
el apartado del SELECT.
Si por ejemplo quicieramos borrar toda la tabla de paises podríamos escribr:
o si por ejemplo quicieramos borrar todos los pasajes del vuelo 15 podríamos escribir:
UPDATE
UPDATE se utiliza para actualizar valor en un registro que ya existe.
Su sintaxis es:
Esta sentencia actualizará las columnas especificadas luego de la cláusula SET al valor que se les
asigna allí. La cláusula WHERE cumple la misma función que para la sentencia DELETE.
Si desearamos cambiarle el nombre de la aerolina del avion 23 escribiríamos:
o si deseareamos subirle un 10% a todos los precios podríamos escribir:
SELECT
SELECT es el alma del motor de base de datos. Esta es la instrucción más utilizada ya que es la que se
utiliza para recuperar información de las tablas ya existentes.
Su sintaxis es:
Este sentencia permitirá obtener columnas o expresiones desde una o más tablas que cumplan con un
criterio de búsqueda dado. Las columnas y expresiones que devolverá son las especificadas al principio.
El * equivale por todas las columnas de todas las tablas que se esten utilizando.
La opción DISTINCT sirve para que todas las filas que pertenezcan al resultado sean distintas (las filas
que son iguales se descartan automaticamente).
La cláusula FROM nos permite espeficiar sobre que tablas vamos a trabajar.
La referencia_tabla se define como:
la parte que se encuentra entre corchetes puede repetirse indefinidamente.
Si se eligen tablas separandolas por coma lo que se hará es combinar cada fila de la primer tabla con
todas las filas de la segunda tabla. De esta forma se obtienen todas las combinaciones posibles. Si se
utiliza INNER JOIN se vinculan las tablas con respecto a la condición establecida (por lo general será
tabla1.atributo_clave=tabla2.atributo_clave). O sea, primero se buscaran las filas
de la tabla uno y luego con esos resultados se buscará en la tabla dos las filas que concuerden con la
condición dada.
Tomemos el ejemplo más sencillo, traer todos los datos de todos los aeropuertos que esten registrados.
Para ello escribiremos:
Como el nombre del país no aparece, relacionaremos esta tabla con la de paises para obtener los
nombres. Ahora quedaría como:
Para seguir mejorando la consulta, solo traeremos los campos que nos interese. Para nuestro ejemplo
traeremos el nombre del aeropuerto con su id y ademas el nombre del país.
Finalmente nos quedará:
Cláusula WHERE
La cláusula WHERE se utilizará para aplicar el criterio de búsquedas. Allí se podran utilizar todos los
operadores de comparación clásicos (= < <= > >= !=) para crear condiciones y las condiciones se
pueden juntar utilizando AND (y) y OR (o).
Si por ejemplo se busca al cliente 2425 la condicion podría ser:
Carrera Linux 2008 Programacion PHP 106
WHERE CODIGO=2425
Si por ejemplo quicieramos ver toda la información de los aviones pero solo de aquellos que sean del
tipo A, podríamos escribir:
En este ejemplo, no traeremos el campo AON_TATO_TIPO porque ya sabemos que tendrá siempre el
valor A.
Clásula GROUP BY y HAVING
La cláusula GROUP BY se utiliza para agrupar los resultados. Esta cláusula agrupará a los resultados
cuyas columnas tengan los mismo valores. Las columnas que se utilizarán para agrupar deben ser
enumeradas. Cuando se agrupa se pueden utilizar algunas funciones para seleccionar.
Si quicieramos saber cuantas escalas tiene un vuelo (contando el punto de partida y el de llegada),
deberiamos agrupar la tabla ESCALA por el campo que identifica a un vuelo (ELA_VLO_ID) y contar
cuantos registros hay. Esto nos quedará como:
La cláusula HAVING es similar a la del WHERE pero en vez de filtrar sobre todas las filas, lo hará sobre
las resultantes de la agrupación.
Si quicieramos acotar el resultado de la consulta anterior, por ejemplo, trayendo solamente aquellos que
tengan 4 o más escalas, podríamos escribir:
SELECT ELA_VLO_ID, COUNT(1) FROM ESCALA GROUP BY ELA_VLO_ID HAVING COUNT(1) >= 4
Clásula ORDER BY y LIMIT
La cláusula ORDER BY sirve para que el resulta salga ordenado por una o más columnas. A cada
columna se le puede poner DESC para que ordene en forma descendentemente o ASC para que lo haga
en forma ascendente (por defecto).
Como ejemplo obtendremos un listado con la cantidad de pasajes que tiene cada persona ordenados del
que más pasajes haya tenido al que menos haya tenido. Luego, para aquellos con iguales cantidades, lo
ordenaremos por apellido y nombre. Para ello escribiremos:
Aclararémos que si queremos utilizar para ordenar una función agregada (COUNT en este ejemplo), en
vez de un campo (pudimos haber ordenado el listado por apellido y nombre solamente), se le debe dar
un ALIAS a dicha función para que la cláusula ORDER BY pueda encontrarla.
También se pueden limitar la cantidad de resultados utilizando la cláusula LIMIT. Si solo se especifica
la cantidad se devolverán las primeras cantidad_filas de resultados. Si se espeficia offset,
(desplazamiento) se devolverá esa cantidad de filas pero partiendo desde el offset especificado.
Si quicieramos hacer un ranking de las 100 personas que más pasajes haya comprado, podríamos
agregarle a la consulta anterior:
Subconsultas
Una subconsulta es simplemente una consulta dentro de otra. O sea, es un mecanismo que nos permite
ejecutar un SELECT dentro de otra consulta (por lo general otro SELECT). El SELECT que se ejecuta
dentro de otra consulta se lo conoce como subconsulta y a la otra consulta como consulta externa
(outer query).
La subconsulta, también conocida como subquery, siempre debe escribirse entre paréntesis.
Para ver como se escribe una subconsulta veremos un ejemplo. Recuperaremos todos los vuelos con sus
aeropuertos de destino (donde termina el viaje). El problema esta que cada vuelo puede tener una
cantidad de escalas distinta (o sea que el campo ELA_ORDEN variará según el vuelo). Con lo visto
hasta ahora no habría forma de resolverlo en una única consulta. Una forma de resolverlo con
subconsultas es comparando en la cláusula WHERE el campo ELA_ORDEN con el máximo orden de
cada vuelo (la subconsulta). Esto nos quedaría:
Como se puede ver la subconsulta esta escrita entre paréntesis. Además como hemos utilizado la misma
tabla que en la consulta externa, en la consulta interna (se dice que es una subconsulta correlacionada)
deberémos darle un alias para que MySQL pueda diferencia entre los campos de una y de la otra.
En este ejemplo podemos ver que la subconsulta solo devuelve un único valor, pero podría devolver
más.
Carrera Linux 2008 Programacion PHP 108
Para ello en vez de utilizar solo el igual, utilizaremos, además, el operador ANY. De esta forma nos
quedará la condición como columna = ANY (subconsulta), lo que significará que el campo
columna puede concordar con cualquiera de los que devuelva subconsulta. También podemos
utilizar el operador IN en lugar de = ANY (en realidad IN es como un alias de = ANY).
Como ejemplo generaremos un listado con la cantidad de pasajes comprados por persona que vivan en
el mismo país que alguno de los aeropuertos existentes. Esta consulta nos quedará:
Como último ejemplo, utilizaremos una subconsulta pero para traer un dato extra dentro del listado de
campos. Traeremos la cantidad de pasajes vendidos para cada vuelo, pero solo para aquellos vuelos que
hayan vendido más de 200 pasajes. Además traerémos la cantidad de escalas que posee cada uno de los
vuelos seleccionados. Como la tabla VUELO con ESCALA tiene una relación de 1 a muchos y VUELO
con PASAJE también, no podemos relacionarlas todas directamente en el FROM.
Para ello escribiremos la siguiente consulta.
Para mejorar la salida hemos decidido asignarle una alias a la subconsulta. Esto es una buena
costumbre y además será extremadamente necesario hacerlo cuando estemos programando y querramos
recuperar dicha columna.
INSERT INTO tabla SELECT ...
Existe una variación del INSERT. Esta variación consiste en utilizar el resultado de un SELECT para
agregar valores en una tabla en vez de tener que especificar uno cada tupla. Se debe tener en cuenta que
el resultado de la búsqueda deberá devolver la misma cantidad de columnas (con en el mismo orden y
los mismo tipos de datos) que tiene la tabla en la cual se quieren ingresar los datos.
Ejercicios
Considerar el modelo de datos definido en la clase anterior.
1. Escribir un INSERT para cada una de las tablas existentes
Carrera Linux 2008 Programacion PHP 109
2. Escribir una consulta que devuelva todos los pasajes y la informacion de los pasajeros para un
vuelo determinado (para el vuelo 46 por ejemplo).
3. Escribir una consulta que devuelva la cantidad de personas que hay por pais. Modificar la
consulta para que agregue otra columna indicando cual es el porcentaje que representa cada
cantidad.
4. Averiguar escribiendo una consulta, cual es el pais que mas vuelos pasan por el.
5. Escribir una consulta que traiga la recaudacion total de cada vuelo y la cantidad de pasajes
vendidos.
6. Traer un listado de todos los vuelos con sus aeropuertos de origen y destino. Ademas se debe
indicar en el mismo listado, la cantidad de escalas que realiza y la cantidad de pasajes vendidos.
Clase 18 Lenguaje de Administración de
Seguridad.
Como funciona la seguridad
Primero que nada diremos que MySQL identifica a un usuario mediante su nombre de usuario y el
host desde el cual se esta conectando. De esta forma podemos tener dos usuarios con igual nombre
pero que tienen distintos conjuntos de privilegios (ya que se el usuario pepe en localhost es
distinto que pepe en algun_otro_lado.com).
En principio, el servidor controla la seguridad en dos momentos:
1. Cuando el usuario se loguea, se controla que su usuario/host/contraseña sean correctos.
2. Con cada sentencia que el usuario ejecuta, se controla que tenga los privilegios necesarios para
realizarla. Si el usuario pide hacer un SELECT, un CREATE o un DROP se contrará que tenga
los permisos, en caso de no tenerlos se le negará la sentencia.
La sentencia GRANT
Este sentencia se utiliza para otorgar privilegios a un usuario (o crearlo si no existe).
Su sintaxis es:
GRANT tipo_privilegio
ON objetos
TO usuario [ IDENTIFIED BY 'password' ]
GRANT otorga el privilegio especificado en tipo_privilegio sobre los objetos definidos en
objetos al usuario definido en usuario. Opcionalmente se le puede agregar una contraseña para
dicho usuario agregando la cláusula IDENTIFIED BY.
Al ejecutar esta sentencia, si el usuario no existe, es creado.
Carrera Linux 2008 Programacion PHP 110
Los tipos de privilegios posibles (tipo_privilegio) son:
Privilegio Descripción
ALL [PRIVILEGES] Otorga todos los privilegios simple, excepto GRANT
OPTION
ALTER Permite usar ALTER TABLE
CREATE Permite usar CREATE TABLE
CREATE TEMPORARY Permite usar CREATE TEMPORARY TABLE
TABLES
DELETE Permite usar DELETE
DROP Permite usar DROP TABLE
INDEX Permite usar CREATE INDEX y DROP INDEX
INSERT Permite usar INSERT
SELECT Permite usar SELECT
SHOW DATABASES Permite ejecutar SHOW DATABASES, el cual muestra
todas las bases de datos de la base
SHUTDOWN Permite usar mysqladmin shutdown
UPDATE Permite usar UPDATE
USAGE Sinónimo de NO PRIVILEGES
GRANT OPTION Permite otorgar privilegios
Los objetos permitidos son:
nombre_tabla | base_datos.* | *.*
Esto nos permite otorgar los privilegios sobre una sola tabla (nombre_tabla), sobre todas las tablas
de una base de datos (base_datos.*) o sobre todas las tablas de todas las bases de datos (*.*).
Finalmente, usuario define al usuario que se quiere crear / otorgar privilegios. Como mencionamos
anteriormente, un usuario esta identificado por su nombre y su host. Por lo tanto, el formato normal
para usuario es 'nombre'@'host'. Un ejemplo podría ser, 'pepe'@'locahost'.
MySQL permite el uso de wildcards en el campo host. Estos son el símbolo de porcentaje (%) y el
guión bajo (_). Ambos son análogos al asterisco (*) y al signo de interrogación (?) del shell. El
primero, %, concuerda con cualquier caracter, cualquier cantidad de veces. De esta forma podríamos
definir a un usuario como 'pepe'@'%.tuxsys.com.ar' para que el usuario 'pepe' pueda
conectarse desde cualquier dominio tuxsys.com.ar. O podríamos definir a un usuario como
'pepe'@'%' para que pueda loguearse desde cualquier lugar del planeta.
El guión sirve para lo mismo que el porcentaje pero solo concuerda con un caracter.
Por ejemplo, para crear un usuario pepe en la máquina local, que trabaja en un proyecto sobre una base
de datos llamada aviones y con contraseña 'epep', podríamos escribir:
Carrera Linux 2008 Programacion PHP 111
o para permitir al mismo usuario consultar todas las tablas de dicha base da datos:
La sentencia REVOKE
Esta sentencia se utiliza para quitarle privilegios a un usuario.
Su sintaxis es:
REVOKE tipo_privilegio
ON objeto
FROM usuario
Los parámetros tipo_privilegio, objeto y usuario son los mismo que para la sentencia GRANT.
Para quitarle todos los privilegios a un usuario se puede utilizar la siguiente sintaxis:
Utilidades Relacionadas
mysql
Esta aplicación es el cliente, para modo texto, que viene por defecto en toda paquete de MySQL. Desde
él podemos conectarnos a cualquier base de datos.
Para ello simplmemente debemos ejecutarlo desde la línea de comandos solo por su nombre. Por
defecto, si no especificamos un host o un usuario, tomará a la máquina local y al usuario con el que nos
hayamos logueado en el sistema.
Para especificarle el host al cual nos queremos conectar deberemos suministrarle la opción -h seguida
del nombre del host.
Para especificarle el usuario deberemos especificarle la opción -u seguida del nombre del usuario.
Si el usuario con el cual nos queremos conectar posee contraseña deberemos especifcicarle además la
opción -o, en caso contrario no nos podremos loguear.
También podemos especificarle sobre que base de datos queremos trabajar (ahorrándonos de hacer
luego un USE de la misma). Para ello simplemente nombraremos como último parámetro el nombre de
la misma.
Carrera Linux 2008 Programacion PHP 112
mysqladmin
Esta herramienta nos permite ejecutar algunas tareas administrativas sobre nuestro servidor, como crear
bases de datos, observar las consultas en proceso, chequear el estado actual y más.
La sintaxis de este comando es:
Entre los comando que existen podemos destacar:
Comando Descripción
create Crea una base de datos con el nombre base_datos
base_datos
drop Elimina la base de datos que posee el nombre base_datos
base_datos
kill id, id, Termina a la fuerza bruta consultas que se esten ejecutando
... (ver processlist)
password Cambia la contraseña del usuario con el que se esta
"nueva_contr conectando mysqladmin
aseña"
ping Cheque si el servidor esta levantado.
processlist Muestra una lista con todos los hilos que se estan ejecutando
en el servidor. En cada hilo se ejecuta una consulta. Aquí
podemos ver que id del hilo le corresponde a que consulta,
como así también que usuario la esta ejecutando (y desde que
host), sobre que base de datos, cuanto tiempo lleva
ejecutándose y en que estado se encuentra.
shutdown Detiene el servidor
status Muestra algunas estadísticas sobre el estado del servidor. En
particular se verá: El tiempo (en segundos) que se ha estado
ejecutando el servidor; La cantidad de hilos activos (clientes);
La cantidad de consultas procesadas; La cantidad de consultas
que han tomado más que long_query_time (definido por
parámetro al inicializar el servidor) en ejecutarse; La cantidad
de tablas que ha abierto el servidor; La cantidad de tablas
abiertas en el momento;
variables Muestra el contenido de las variables globales de MySQL
version Muestra la versión actual
mysqlcheck
Esta herramienta se utiliza para comprobar y corregir tablas que hayan quedado rotas por algún motivo.
Carrera Linux 2008 Programacion PHP 113
Solo sirve para tablas del tipo MyISAM.
Su sintaxis es:
En el primero de los casos, se aplica el comando sobre todas las tablas de base_datos, a no ser que se
especifiquen tablas.
El segundo de los casos se aplica sobre todas las tablas de las bases de datos especificados.
Finalmente, el útlimo modo es sobre todas las tablas de todas las bases de datos.
Entre las opciones importantes encontramos:
Opción Descripción
--check Comprueba si la tabla esta en un estado correcto.
--repair Repara una tabla si posee errores
--optimize Optimiza las tablas. Esto es recuperar el espacio empleado por
registros que han sido eliminados. MySQL siga guardando dicho
espacio para reutilizarlo con nuevos registros y no tener que
volver a pedir ese espacio al Sistema Operativo.
mysqldump
Esta utilidad sirve para hacer copias de respaldo de bases de datos/tablas.
Este comando generará un archivo con todas las sentencias SQL para poder volver a crear las tablas y
cargar los datos de las bases especificadas.
Su sintaxis es:
En el primero de los casos se generará el SQL necesario para generar la base de datos base_datos
completa. Si se especifica además las tablas (separadas por espacios) se generará solo de aquellas tablas
y no de la base completa.
La segunda posibilidad nos permite generar SQL para varias base de datos pasándole como parámetro
--databases y luego el nombre de cada una de las bases que queremos.
Por último, podemos hacerlo sobre todas las bases de datos de nuestro sistema utilizando el parámetro
--all-databases.
En todos los casos, mysqldump enviará todo el SQL necesario a la salida estándar. Para guardar en un
archivo para utilizarla luego, deberemos redireccionar la salida al mismo:
Entra las OPCIONES importantes podemos encontrar:
Opción Descripción
--add-drop- Esta opción agregar delante del CREATE TABLE un DROP
table TABLE. De esta forma, podemos correr el script sobre una
base que ya exista sin que nos arroje errores al tratar de crear
las tablas.
-- Permite generar SQL compatible con otros motores de bases
compatible=ti de datos. Entre los posibles valores de tipo podemos
po encontrar: ansi, mysql323, mysql40,
postgresql, oracle, mssql, db2, maxdb,
no_key_options, no_table_options, o
no_field_options
--no-create-db No agrega la línea del CREATE DATABASE al bajar una
base de datos.
--no-create-
No agrega los CREATE TABLE de cada tabla
info
--no-data No agrega los INSERT con el contenido de las tablas. Esto
nos permite obtener un archivo con solo la estructura de la
base de datos sin los datos.
mysqlhotcopy
Este script nos permite crear backups de la base de datos duplicando las mismas en un nuevo directorio.
Su sintaxis es:
De esta forma, se generará una copia de la/s base/s de datos base_dato1, base_dato2, etc en el
directorio /nuevo/directorio.
mysqlimport
Esta aplicación sirve para cargar datos desde archivos de texto a tablas (es una aplicación sobre la
sentencia LOAD DATA INFILE).
El formato del archivo debe ser un registro por línea y cada campo separado por un delimitador
(generalmente una tabulación o una coma).
La sintaxis del comando es:
El nombre de la tabla se determinará por el nombre del archivo, quitandole cualquier extensión que
posea. Por lo tanto, los archivos AVION.txt, AVION.text o AVION.csv harán referencia a la tabla AVION.
Carrera Linux 2008 Programacion PHP 115
Entre las opciones destacadas podemos encontrar:
Opción Descripción
-- Es una lista (separada por comas) de los nombres de las
columns=lista_c columnas. De esta forma se concordarán las columnas en
olumnas el archivo de texto con la correspondiente en la tabla de
la base de datos.
--delete Vacía la tabla antes de agregar los registros
--fields-
terminated- Determina que caracter es el delimitador de los campos.
by=caracter
--ignore En caso de que se trate de agregar un registro que ya
existe (clave duplicada) el nuevo registro se ignora y se
continua insertando los demás.
--replace En caso de que se trate de agregar un registro que ya
existe (clave duplicada) el viejo registro se reemplaza
por el último y se continua insertando los demás.
mysqlshow
Esta herramienta nos permite consultar sobre la estructura de las bases de datos.
Su sintaxis es:
Este comando mostrará información dependiendo la cantidad de argumentos, según el orden
establecido.
Si no se le pasa ningún argumento, mostrará todas las bases de datos que haya en el sistema.
Si soló se completa el argumento base_datos, mostrará todas las tablas que haya dentro de dicha base
de datos.
Si además se completa tabla, entonces mostrará la estructura de la misma. Incluyendo todas las
columnas, con sus tipos de datos y demás configuraciones.
Si se especificá columna solo se mostrará la información del punto anterior pero solo para la columna
especificada.
Entre las opciones disponibles podemos encontrar:
Opción Descripción
--keys En el caso de esta viendo la información de una tabla, también se
agregan todos los índices creado sobre la misma.
--status Muestra información extra sobre las tablas.
Carrera Linux 2008 Programacion PHP 116
Ejercicios
1. ¿Como se aplica la seguridad en MySQL?
2. ¿Que sentencias se poseen para manejar usuarios? ¿A que sublenguaje de SQL pertenecen?
¿Hasta que nivel puedo aplicar la seguridad?
3. Crear un usuario "stokes" con contraseña "akl84hg" para que solo pueda consultar las tablas de
las clases anteriores. Corroborar que el usuario no pueda crear, borrar ni modificar tablas.
4. ¿Que herramienta utilizaria para hacer una copia de respaldo de una base de datos? Justifique su
respuesta
Clase 19 Indices e Integridad Referencial
Aumentando la velocidad de acceso
Cuando se esta trabajando con tablas que poseen pocos registros, no es posible notar si el sistema tiene
o no una buena performance. De movida, con cada SELECT que se ejecuta se deberá barrer todos los
registros de la tabla para encontrar aquellos que concuerden con el criterio pedido. Al aumentar la
cantidad de registros el sistema comienza a volverse más y más lento, aún para las consultas más
sencillas. Esto ocurre ya que para realizar una búsqueda, el motor necesariamente necesita recorrerse
toda la tabla (FULLSCAN) para verificar que registros concuerdan.
Esta situación puede y debe ser remediada haciendo uso de índices. Un índice es una estructura auxiliar
la cual ayuda a encontrar registros sin necesidad de hacer un barrido completo de la tabla. Existen
varios tipos de índices pero actualmente, MySQL soporta solo un tipo: el ArbolB.
Los índices se crean sobre una o más columnas de una tabla. Esto implica que toda esa información
estará "duplicada", o sea, que el índice ocupará un espacio un poco mayor al tamaño total de las
columnas seleccionadas. Al usar el índice se aumentará la velocidad al tratar de recuperar registros en
base a esas columnas pero tendrá el costo de actualizarse cuando se inserta o borra una fila. Es por eso
que los índices pueden ser beneficiosos pero si se usan en exceso pueden llegar a no serlo.
Un ArbolB es una estructura que posee forma de árbol que crece de la raíz hacia la hojas. En un arból
habrá un nodo raíz el cuál tendrá N hijos. A su vez cada hijo de la raíz puede tener N hijos y así
sucesivamente. A cada camino que se va formando se lo llama rama. Aquellos nodos que se encuentren
al final de cada rama se los denomina hoja.
Si se arma un ArbolB sobre una columna, por ejemplo CODIGO de la tabla CLIENTES, en promedio
para buscar un CODIGO en una tabla de 1.000.000 de registros, tomará 20 accesos. Este valor es
mucho menor a barrerse el millón de registros.
Los índices se crearán sobre las columnas en las cuales hagamos consultas frecuentemente. Por lo
expuesto anteriormente, no es beneficioso poner índices en todas las columnas. Por lo tanto, habrá que
analizar que consultas se harán y en donde conviene crear los índices.
Internamente, MySQL, al determinar una(s) columna(s) como clave primaria, generará un índice único
sobre dichas columnas. Por lo tanto, sobre la clave primaria siempre se tiene buena velocidad de
Carrera Linux 2008 Programacion PHP 117
acceso. Esto se debe a que las relaciones siempre se hacen sobre las claves primarias por lo tanto si no
se posee dicha columna indexada tomará mucho tiempo relacionar dos tablas.
Los índices pueden o no aceptar valores duplicados. Si creamos un índice único, entonces los valores
de esa columna nunca se repetirán. Cuando utilizabamos el UNIQUE en el CREATE TABLE, lo que se
creabá era un índice que aseguraba esto.
Una vez creado el índice MySQL se encargará automaticamente de determinar cuando conviene
utilizarlo y cuando no. Por lo tanto, no hará falta en cada consulta escribir explicitamente que índice
debe usar ni como.
En MySQL para crear un índice se utilizará el comando:
En donde, la palabra UNIQUE es opcional y determina si el índice aceptará o no aceptará duplicados.
nombre_indice es simplemente el nombre que se la dará al indice (para poder eliminarlo luego si hace
falta).
tabla es el nombre de la tabla sobre la cual se creará el índice.
Y campos son todos los campos (1 o más) que tomará el índice. Si se necesitan más de un campo se los
debe separar por comas.
Una vez creado el índice es posible eliminarlo si hace falta. Para ello se utlizará el comando DROP
INDEX de la siguiente forma:
En donde, nombre_indice es el nombre que se le dió al indice cuando se creo y tabla es el nombre de la
tabla sobre la cual esta el índice.
Integridad Referencial
Cuando comenzamos a hablar de base de datos hicimos mención de la integridad referencial. La
integridad referencial significa poder decirle al motor explícitamente que campo hace referencia a que
clave primaria de que tabla. Por lo tanto, tendriamos las relaciones metidas dentro del motor(reglas de
integridad), lo cual nos asegura que la base siempre esta en un estado consistente. Esto significa que
nunca encontraríamos relaciones mal hechas o códigos que no existen.
Las tablas estandar (MyISAM) no pueden utilizar integridad referencial. Para ello hay que crear las
tablas del tipo InnoDB como hemos visto en clases anteriores (utilizando la opción TYPE en el
CREATE TABLE). Además existe otra restricción: para crear una relación ambas columnas, la clave
foránea como la clave referenciada, deben tener un índice creado. Esto se debe a que en el caso
contrario, la performance disminuiría significativamente con cada INSERT, DELETE y UPDATE ya
que las reglas de integridad se deben verificar en cada una de estas operaciones.
Para definir una relación entre dos tablas utilizaremos la sentencia ALTER TABLE de la siguiente
forma:
Carrera Linux 2008 Programacion PHP 118
Aquí tabla es la tabla que posee una columna que es clave foránea. Esta es la columna que hará
referencia a otra tabla.
nombre_constraint es el nombre que se le dará a la relación. Esta alternativa (es opcional) existe
simplemente para respetar el estándar ya que MySQL la ignora.
columnas_clave_foranea son el nombre de la o las columnas (separadas por comas) que hacen
referencia a la tabla independiente.
tabla_independiente es la tabla la cual es referenciada y columnas_independientes su clave primaria
(que deberán concordar con las de columnas_clave_foranea).
Antes de ver las otras opciones veamos un ejemplo:
ALTER TABLE VENTAS ADD FOREIGN KEY (VAS_CES_ID) REFERENCES CLIENTES (CES_ID);
En este ejemplo, CLIENTES es la tabla independiente. Además su clave primaria esta compuesta por la
columna CES_ID. Por lo tanto, toda tabla que haga referencia a un cliente, debe poner el código de
esta columna. VENTAS es la tabla que hace referencia a un cliente. Por lo tanto se definió una columna,
VAS_CES_ID, que contendrá el código del cliente que realizó la operación. Como será una clave
foránea se creó un índice sobre la misma. Luego, el ALTER TABLE correspondiente relaciona la
columna VAS_CES_ID de la tabla VENTAS con la columna CES_ID (clave primaria) de la tabla
CLIENTES.
Como recomendación práctica diremos que es mejor, dentro del script que generá la base de datos,
Carrera Linux 2008 Programacion PHP 119
definir primero todas las tablas y luego todas las relaciones. De esta forma siempre que se vaya a
definir una relación ya se poseen las tablas intervinientes creadas y no hay que estar moviendo
definiciones por todo el archivo para que al momento de definir la relación ambas tablas existan.
Por último veamos las opciones restantes ON DELETE y ON UPDATE. Esta reglas le dicen al motor
que hacer en caso que se borre o actualice el valor de la clave referenciada (en el ejemplo CES_ID de
CLIENTES). Hay 4 acciones posibles: CASCADE, SET NULL, NO ACTION y RESTRICT. Las
acciones son similares para DELETE y UPDATE con la única diferencia que DELETE borrará y
UPDATE actualizará.
La opción CASCADE propagará la operación a las tablas referenciadas. En el ejemplo, si borramos un
cliente se borrarán de la tabla VENTAS todos los registros que contengan a ese cliente.
La alternativa SET NULL pondrá el valor NULL en la columna de la clave foránea (VAS_CES_ID) si y
solo si la columna acepta valores nulos. Si no los acepta no se podrá realizar la operación (el DELETE
o UPDATE fallarán).
La opción NO ACTION (no recomendada) no tomará ninguna acción y la base quedará en un estado
inconsistente.
Finalmente, la opción RESTRICT prohibirá la ejecucíon del DELETE o del UPDATE y nunca podrá ser
eliminada o actualizada la clave primaria de la tabla independiente.
Ejercicios
1. ¿Para que se utilizan los indices?
2. ¿Que ventajas trae utilizar indices?
3. ¿Que desventajas trae utilizar indices?
4. Se pide agregar todas las reglas de integridad referencial a la agenda creada anteriormente.
5. Se pide agregar todas las reglas de integridad referencial al sistema generado a voluntad.
Clase 20 PHP y MySQL
Introducción
Para utilizar MySQL desde PHP hay que conocer solo un par de funciones que viene incluidas con
PHP.
La idea es la misma que al utilizar el cliente de MySQL: primero se debe crear una conexión y elegir
sobre que base de datos se quiere trabajar. Luego es posible ejecutar las sentencias.
Para ejecutar un sentencia los pasos serán: ejecutar la sentencia e ir recuperando de a una las filas del
resultado.
Creando una conexión
Para conectarse a un servidor MySQL se utiliza la función mysql_connect. Esta función lleva
Carrera Linux 2008 Programacion PHP 120
como parámetros la dirección del servidor, con que usuario se va a conectar y cual es su contraseña.
Recordemos que al instalar MySQL por defecto solo esta el usuario root y sin contraseña, que si bien
no es lo más seguro sirve para poder practicar.
La función mysql_connect devolverá un recurso a traves del cual podremos utilizar el motor en su
totalidad. En caso de que la conexión haya fallado por algun motivo, mysql_connect devolverá
falso.
Ejemplo:
NOTA: la función mysql_error devuelve una cadena con el error de la última operación realizada.
La función exit termina la ejecución del script.
Seleccionando una Base de Datos
El siguiente paso es elegir sobre que base de datos se desea trabajar. Para ello se emplea la función
mysql_select_db que lleva como parámetros el nombre de la base de datos y la conexión creada
anteriormente (que devuelve mysql_connect).
Esta función devolverá verdadero si se pudo realizar la operación y falso en caso contrario.
Ejemplo:
El ejemplo es similar al anterior. Si falla no será posible utilizar la base de datos y se termina le
ejecución del script.
Enviando Sentencias
Para enviar cualquier sentencia de SQL se puede utilizar la función mysql_query. Esta función lleva
como parámetro una cadena con la sentencia (aquí no hace falta poner el carácter ; ) y la conexión al
motor.
Como esta sentencia es muy utilizada, es posible (y muy común) llamarla sin el parámetro de conexión.
Si este no se especifica, se utilizará el de la última conexión hecha. Como la mayoría de las veces se
trabaja con una sola conexión, nos ahorra de escribir siempre la variable de la conexión, aumentando,
además, la posibilidad de errores de tipeo y tiempo en depurarlo luego. En realidad, todas las funciónes
que lleven como parámetro la conexión, pueden omitirse seguramente este parámetro al trabajar con
una sola conexión.
Carrera Linux 2008 Programacion PHP 121
Esta función devuelve un recurso que representa el resultado. Si hubo algún error devolverá falso y la
función mysql_error nos dirá cual fue el error.
Ejemplo:
En este ejemplo hemos agregado una fila a la tabla AVIONES.
Recuperando los resultados
Una vez ejecutada una sentencia será necesario, en ocasiones, recuperar los resultados. Algunas
sentencias, como INSERT, UPDATE o DELETE, no devuelven ningún resultado, en cambio, el
SELECT devuelve cero o más filas como resultado.
Para recuperar los resultados tenemos, en principio, dos funciones: mysql_fetch_row y
mysql_fetch_array.
La función mysql_fetch_row irá devolviendo de a uno los resultados en forma de un arreglo con
indices numéricos. Devolverá falso una vez que se trate de leer más alla de la última fila del resultado.
Ejemplo:
Este ejemplo creará una tabla en HTML con los resultados de la consulta. Para cada ciclo del while, se
cargará en el arreglo $avion una fila del resultado, de forma que en la posición 0 se encuentre el valor
de la primer columna seleccionada, en la 1 el valor de la segunda columna seleccionada y así
sucesivamente.
Esta función tiene la desventaja que al modificar el orden de los campos (o al agregar) los indices se
Carrera Linux 2008 Programacion PHP 122
modificarán y habra que retocar el código por todas partes.
Para solventar esta deficiencia podemos utilizar la función mysql_fetch_array. Esta función
opera de la misma forma que la anterior, pero devuelve un arreglo asociativo, en donde las claves serán
los nombres de las columnas seleccionadas.
Modificando el ejemplo anterior nos quedaría:
Como se puede apreciar, para acceder al ID, por ejemplo, se hará a traves de $avion["AES_ID"]
en vez de $avion[0]. Esto demuestra que la posición no es importante al utilizar
mysql_fetch_array.
Cerrando la conexión
Para cerrar la conexión se utiliza la función mysql_close que lleva como parámetro la conexión. Por
lo general no se utiliza mucho esta función ya que al finalizar el script se cierran automáticamente todas
las conexiones abiertas.
Ejemplo:
mysql_close($link);
Funciones varias
Veremos otras dos funciones que pueden ser de utilidad: mysql_num_rows y mysql_insert_id.
La primera de ellas devuelve la cantidad de filas que produjo un resultado válido devuelto por
mysql_query.
Ejemplo:
Carrera Linux 2008 Programacion PHP 123
La función mysql_insert_id devuelve el último id generado automáticamente por una columna
con atributo AUTO_INCREMENT.
Ejemplo:
De esta forma es posible crear el ID automáticamente y luego utilizarlo para relacionarlo en otras
tablas.
Ejercicios
1. ¿Como se hace para recuperar el resultado de una consulta?
2. ¿Que diferencias presentan los distintos metodos?
3. Hacer un sistema que permita cargar encuestas dentro de una base de datos. Luego se debera
crear una pagina que muestre la encuesta actual (marcada en la base de datos como tal) y
permita a los usuarios votar en la misma, registrando el voto.
Luego se debera crea otra pagina que permita consultar el estado de cualquier encuesta viendo
cuante gente voto en cada opcion y que porcentaje respresenta el mismo.
4. Primero, considere la base de datos definida anteriormente.
Luego se desea generar una página que permita consultar los vuelos disponibles y asignar los
pasajes para dichos vuelos.
El primer paso es generar una página que permite encontrar si hay vuelos disponibles
mencionando el Origen y el Destino. El sitio debe informar sobre que vuelos tiene ese trayecto,
en que fecha salen, los aeropuertos de salida/ llegada y cantidad de pasajes libres por clase.
Luego se debe poder ir, presionando sobre el vuelo, a otra página que de la información
detallada del vuelo y que sea posible asignar (vender) pasajes. Esta pagina debe informar todo
sobre el vuelo: que avión es el que lo realiza (ID + AEROLINEA + TIPO), todas sus escalas
(con toda la información del Aeropuerto) con los horarios correspondientes y en orden, el total
recaudado por Clase con la cantidad de asientos ocupados y el total de asientos, y el total
recaudado.
Con toda esta información en pantalla el usuario podrá decidir si viajar o no en ese vuelo. Luego
debería presentar un link para ir a la asignación de pasajes. Aqui se deben mostrar todos los
asientos que haya en el avión. Aquellos que ya estan ocupados los marcará como ocupados y los
que esten libres deberá poner un checkbox al costado para poder seleccionarlos. Con todos los
asientos que el usuario haya marcado se asignarán luego los pasajes.
5. Se desea realizar un pequeño sistema para generar un GuestBook. Un GuestBook (o Libro de
Visitas) sirve para que los navegantes dejen sus mensajes en la página y que estos puedan ser
Carrera Linux 2008 Programacion PHP 124
vistos por todo el mundo.
El sistema debe permitir:
Que los usuarios dejen mensajes. Para ello el usuario debera completar: nombre, email,
calificacion del sitio y el mensaje. Luego el sistema registrará además la fecha y hora en que se
dejó dicho mensaje. Permitir ver los mensajes por páginas. O sea que se deben ver los últimos
10 mensajes, permitiendo volver hacia atrás de a 10 mensajes hasta que se acaben.
Generar un cuadro basado en la calificación con la siguiente forma:
+--------------------------------------+
| Calificacion | Cantidad | Porcentaje |
|--------------+----------+------------|
| Excelente | 60 | 30% |
|--------------+----------+------------|
| Muy Bueno | 40 | 20% |
|--------------+----------+------------|
| Bueno | 60 | 30% |
|--------------+----------+------------|
| Regular | 20 | 10% |
|--------------+----------+------------|
| Pesimo | 20 | 10% |
+--------------------------------------+
Las calificaciones deben estar en una tabla (pueden ser las cinco mencionadas, o pueden ser
más o pueden ser menos, el sistema debe funcionar para cualquier cantidad) y al usuario se le
deberá presentar el <SELECT> correspondiente para que eliga.