Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Curso PHP5 - 2005
Curso PHP5 - 2005
PHP 5
Iv n S nchez Ortega a a ACM Captulo de Estudiantes Facultad de Inform tica, UPM a Marzo 2005
Curso de PHP 5
c 2005 ACM Captulo de Estudiantes - Facultad de Inform tica UPM a ACM Captulo de Estudiantes Facultad de Inform tica - Universidad Polit cnica de Madrid a e Campus de Montegancedo s/n 28660 Boadilla del Monte MADRID (SPAIN) Esta obra puede ser distribuida unicamente bajo los t rminos y condiciones expuestos en Creative Commons e Reconocimiento-CompartirIgual 2.0 o superior (puede consultarla en http://creativecommons.org/licenses/by-sa/2.0/es/ ). ACM Captulo de Estudiantes - Facultad de Inform tica UPM no se responsabiliza de las opiniones aqu vertidas por el a autor.
Indice general
1. Introducci n o 1.1. Paradigma de la programaci n web . . . . o 1.1.1. Modelo cliente-servidor . . . . . 1.1.2. Generaci n din mica de contenido o a 1.2. Recursos . . . . . . . . . . . . . . . . . . 1.2.1. CD y documentaci n del curso . . o 1.2.2. php.net . . . . . . . . . . . . . . 1.2.3. pear.php.net . . . . . . . . . . . . 1.2.4. dotgeek.org . . . . . . . . . . . . 1.2.5. php-mag.net . . . . . . . . . . . 1.2.6. triqui..upm.es . . . . . . . . . . 1.2.7. Un editor de texto . . . . . . . . . 1.3. Lo m s b sico . . . . . . . . . . . . . . . a a 1.3.1. Incrustando c digo . . . . . . . . o 1.3.2. Qu hora es? . . . . . . . . . . . e 1.3.3. Comentarios . . . . . . . . . . . 2. Variables y Operadores 2.1. Denici n din mica de variables . . . . o a 2.2. Tipos b sicos . . . . . . . . . . . . . . a 2.2.1. Booleano . . . . . . . . . . . . 2.2.2. Entero . . . . . . . . . . . . . . 2.2.3. Coma otante . . . . . . . . . . 2.2.4. Cadena . . . . . . . . . . . . . 2.2.5. Nulo . . . . . . . . . . . . . . 2.3. Tipos compuestos . . . . . . . . . . . . 2.3.1. Recursos . . . . . . . . . . . . 2.3.2. Arrays . . . . . . . . . . . . . . 2.3.3. Objetos . . . . . . . . . . . . . 2.4. Operadores . . . . . . . . . . . . . . . 2.4.1. Expresiones . . . . . . . . . . . 2.4.2. Aritm ticos . . . . . . . . . . . e 2.4.3. De cadenas . . . . . . . . . . . 2.4.4. Asignaci n . . . . . . . . . . . o 2.4.5. Comparaci n . . . . . . . . . . o 2.4.6. De Errores . . . . . . . . . . . 2.4.7. Post/pre incremento/decremento 2.4.8. L gicos . . . . . . . . . . . . . o 2.4.9. Bit a bit . . . . . . . . . . . . . 2.4.10. Ternario ? : . . . . . . . . . . . 2.5. Magia con las variables . . . . . . . . . 2.5.1. Referencias a variables . . . . . 2.5.2. Comprobando los tipos . . . . . 2.5.3. Type casting . . . . . . . . . . 2.5.4. Variables variables . . . . . . . 1 1 1 2 3 3 3 3 3 3 3 3 4 4 4 4 5 5 6 6 6 6 6 7 7 7 7 7 7 7 8 8 8 9 9 9 10 10 10 11 11 11 11 11
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
I
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
2.6. (In)denici n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . o 2.6.1. unset() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.6.2. isset() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3. Estructuras de control 3.1. Bifurcaci n . . . . . . . . . o 3.1.1. if-else . . . . . . . . 3.1.2. if-elseif-elseif-else . 3.1.3. switch-case . . . . . 3.2. Bucles . . . . . . . . . . . . 3.2.1. while . . . . . . . . 3.2.2. do-while . . . . . . 3.2.3. for(inic;cond;accion)
12 12 12 13 13 13 13 14 14 15 15 15 17 17 17 17 18 19 19 20 20 21 21 21 22 22 23 23 23 24 24 25 26 26 26 26 27 27 27 27 27 28 28 28 29 29 29 29 30 30 30 31
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
4. Arrays 4.1. Construyendo un array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1.1. array() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1.2. Expansi n de arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . o 4.1.3. [0] [1] [2] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1.4. [ ] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1.5. [foo] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1.6. Arrays recursivas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1.7. print r() , var dump() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.2. Iteraci n sobre arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . o 4.2.1. Iteraci n sobre arrays: el malo . . . . . . . . . . . . . . . . . . . . . . . . o 4.2.2. Iteraci n sobre arrays: el bueno foreach, foreach con referencia . . . . . o 4.2.3. Iteraci n sobre arrays: el feo . . . . . . . . . . . . . . . . . . . . . . . . . o 4.2.4. list(), each(), prev(), current(), reset(). Puntero interno, devolviendo arrays. 4.3. Magia con arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.3.1. array push(), array pop(), array shift(), array unshift() . . . . . . . . . . . 4.3.2. explode(), implode() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.3.3. sort(), asort(), ksort(), natsort() . . . . . . . . . . . . . . . . . . . . . . . . 4.3.4. (un)serialize() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.3.5. Y otras cosas raras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5. Procesamiento de formularios 5.1. Los viejos tiempos . . . . 5.2. $ GET . . . . . . . . . . . 5.3. $ POST . . . . . . . . . . 5.4. $ FILES . . . . . . . . . . 5.5. $ COOKIE, $ SESSION . 5.6. $ REQUEST . . . . . . . 5.7. $ SERVER . . . . . . . . 5.8. Superglobales . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
6. Ficheros 6.1. The C way: fopen(), fread(), fwrite(), fclose() . . . . . . . . . . 6.2. The PHP way . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.2.1. le() . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.2.2. le get contents(), le put contents() . . . . . . . . . . 6.2.3. fpassthru(), le exists(), nl2br(), is dir(), basename(), etc 6.3. include(), require() . . . . . . . . . . . . . . . . . . . . . . . . 6.4. Ficheros especiales . . . . . . . . . . . . . . . . . . . . . . . . 6.4.1. Ficheros remotos . . . . . . . . . . . . . . . . . . . . . 6.4.2. pipes, fos . . . . . . . . . . . . . . . . . . . . . . . . 6.4.3. sockets . . . . . . . . . . . . . . . . . . . . . . . . . .
II
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
7. Funciones 7.1. El Concepto . . . . . . . . . . . . . . . . . . . . 7.1.1. Reusabilidad de c digo . . . . . . . . . . o 7.1.2. function foo() . . . . . . . . . . . . . . 7.2. Argumentos . . . . . . . . . . . . . . . . . . . . 7.2.1. function foo($bar) . . . . . . . . . . . . 7.2.2. function foo($bar) { return($foobar); } . 7.2.3. Argumentos predenidos . . . . . . . . . 7.2.4. Argumentos variables: func get args() . . 7.2.5. Referencias: function foo(&$bar) . . 7.3. Visibilidad . . . . . . . . . . . . . . . . . . . . . 7.3.1. Visibilidad reducida dentro de funciones . 7.3.2. Variables globales, scope global . . . . . 7.4. Lambda-programaci n . . . . . . . . . . . . . . o 7.5. Tic tac! . . . . . . . . . . . . . . . . . . . . . . 7.6. Cierra la puerta al salir . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
32 32 32 32 33 33 33 33 34 34 35 35 35 35 36 36 37 37 37 38 38 39 40 41 41 42 42 42 42 43 44 44 44 45 45 45 46 47 47 48 48 50 50 50 50 50 50 51 51 51 51 51 51 52 52
8. Programaci n Orientada a Objetos o 8.1. Objetos por todos lados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.1.1. M todos y atributos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . e 8.1.2. Instancias: instanceof (comprueba que es un objeto es una instancia de una clase) 8.1.3. Apto para todos los p blicos: public, protected, private, visibilidad - E STRICT . u 8.1.4. Herencia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.1.5. Expansi n de propiedades . . . . . . . . . . . . . . . . . . . . . . . . . . . . . o 8.2. Magia con . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.2.1. construct() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . destruct() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.2.2. 8.2.3. autoload() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.2.4. sleep(), wakeup() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.2.5. toString() - s lo con echo() !! . . . . . . . . . . . . . . . . . . . . . . . . . . o 8.2.6. get() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . set() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.2.7. 8.2.8. call() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.3. Patrones de dise o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . n 8.3.1. Constantes y cosas est ticas . . . . . . . . . . . . . . . . . . . . . . . . . . . . a 8.3.2. Paamayim Nekudotayim . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.3.3. Solteros de oro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.3.4. F bricas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . a 8.3.5. Clases abstractas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.3.6. Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.3.7. Es mi ultima palabra! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.3.8. Type hinting (sobrecarga de funciones) . . . . . . . . . . . . . . . . . . . . . . 9. BBDD 9.1. Porqu ? . . . . . . . . . . . . e 9.2. Cu l? . . . . . . . . . . . . . . a 9.2.1. SQLite . . . . . . . . . 9.2.2. MySQL . . . . . . . . . 9.2.3. Oracle 10 . . . . . . . . 9.2.4. PostgreSQL . . . . . . . 9.2.5. Otros competidores . . . 9.2.6. Cu l elijo? . . . . . . . a 9.3. C mo? . . . . . . . . . . . . . o 9.3.1. Funcionalidades b sicas a 9.3.2. Funciones de SQLite . . 9.3.3. Conexiones persistentes 9.4. Cu ndo? . . . . . . . . . . . . a
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
III
9.4.1. Vendiendo pan, primera 9.4.2. Vendiendo pan, segunda 9.4.3. Con esto basta . . . . . 9.5. Qui n? . . . . . . . . . . . . . e 9.5.1. Inyecci n de SQL . . . o 9.5.2. Autenticaci n . . . . . o 10. Autenticaci n y sesiones o 10.1. Nos conocemos de antes? . . . 10.1.1. Memoria de pez . . . . . 10.1.2. Leche y galletas . . . . . 10.1.3. Sobrepeso . . . . . . . . 10.2. Sesiones . . . . . . . . . . . . . 10.2.1. No m s ping-pong . . . a 10.2.2. Adivina! . . . . . . . . 10.2.3. Almacenando sesiones . 10.3. 403 Forbidden . . . . . . . . . . 10.3.1. Cabeceras HTTP . . . . 10.3.2. Programando con cabeza
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
52 52 53 53 53 53 54 54 54 54 55 55 55 57 57 58 58 61 62 62 62 62 62 62 63 63 63 64 65 65 65 66 66 67 67 67 68 69 69 69 69 69 69 69 70 70 70 70 70 70 70
11. XML 11.1. Panacea . . . . . . . . . . . . . . . . 11.1.1. Una soluci n a todos los males o 11.1.2. O no? . . . . . . . . . . . . 11.2. XML Simple: SimpleXML . . . . . . 11.2.1. Lee y parsea . . . . . . . . . 11.2.2. Busca, busca! . . . . . . . . 11.3. Y ya est ? . . . . . . . . . . . . . . a 11.3.1. Modicando informaci n . . . o 11.3.2. Creando XML . . . . . . . .
12. Tratamiento de errores 12.1. Tipos de errores . . . . . . . . . . . . . . . . . . . . . . 12.1.1. No es tan grave como parece . . . . . . . . . . . 12.1.2. Ahora te veo, ahora no . . . . . . . . . . . . . . 12.1.3. Me tropiezo yo mismo . . . . . . . . . . . . . . 12.2. Qui n es el general failure y qu hace en mi disco duro? e e 12.2.1. Ojos que no ven... . . . . . . . . . . . . . . . . 12.2.2. Ojos que s ven... . . . . . . . . . . . . . . . . . 12.3. Excepciones . . . . . . . . . . . . . . . . . . . . . . . . 13. Miscel nea a 13.1. C digo din mico . . . . . . . . . . . . . . . o a 13.2. Aplicaciones no web . . . . . . . . . . . . . 13.3. Output Buffering . . . . . . . . . . . . . . . 13.4. Pruebas automatizadas . . . . . . . . . . . . 13.5. Frameworks, sistemas de templates . . . . . . 13.6. Im genes, PDFs, Flash, RTF . . . . . . . . . a 13.7. Iteradores sobre clases, PHP Standard Library 13.8. C lculo num rico . . . . . . . . . . . . . . . a e 13.9. Servicios web . . . . . . . . . . . . . . . . . 13.10. ncriptaci n . . . . . . . . . . . . . . . . . . E o 13.11. xtensiones al motor de PHP . . . . . . . . . E 13.12. ptimizadores y m quinas virtuales . . . . . O a 13.13. asta el innito y m s all . . . . . . . . . . H a a . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
IV
Captulo 1
Introducci n o
Bienvenidos todos al curso de ACM sobre PHP5. Este curso est dirigido a todas aquellas personas con conocimientos a previos de programaci n (preferentemente con algo de C), interesados en conocer a fondo PHP5, un lenguaje dominante o en la programaci n de sitios web din micos hoy en da. o a En este curso se ver n ciertos aspectos oscuros de PHP que suelen pasar desapercibidos en la mayora de los manuaa les y tutoriales, pero que son funcionalidades interesantes, o que hay que tener en cuenta para programar correctamente. Seg n diversas estadsticas, la arquitectura LAMP (Linux + Apache + MySQL + PHP) es, si no la m s usada, una de u a las mayoritarias.
La programaci n web es muy distinta a la programaci n tradicional, pero se fundamenta en muchos de sus conceptos. o o El m s importante que hay que tener en cuenta es el concepto de entrada y salida est ndar, ya que sobre el se estableci el a a o est ndar CGI, que permiti la programaci n de sitios web en cualquier lenguaje de programaci n que pudiera compilarse a o o o y sacar datos por salida est ndar. M s adelante se especializaron algunos lenguajes para esta tarea, e incluso se crearon a a algunos especcos para ello (como fue el caso de PHP all por el a o 1995). a n
Antes de entender lo que es un CGI, o un programa del lado del servidor, hay que entender c mo funciona esto de la o WWW: 1
CAPITULO 1. INTRODUCCION
Normalmente, un navegador web (o cliente) lanza una petici n HTTP, normalmente por el puerto 80 de TCP, a o un servidor web. Un demonio que se est ejecutando en ese servidor web (apache, IIS, boa, tux, thttpd o cualquier otro e software) recoge y analiza esa petici n, y devuelve una p gina web (texto plano, formateado con HTML o XHTML) de o a vuelta al navegador.
Entonces ya tenemos una aplicaci n web: una p gina que no se almacena en el servidor web, sino que se genera o a
1.2. RECURSOS
autom ticamente cuando se visita. El est ndar CGI indica que los datos (la petici n de la p gina) se le han de pasar al a a o a programa por entrada est ndar o por los argumentos de ejecuci n, y la salida est ndar de ese programa ser devuelta al a o a a navegador web. Este m todo se ha ido renando, llevando a la automatizaci n el proceso de an lisis de la petici n HTTP, dejando que e o a o el programador se centre en la l gica de su programa, y no en la manera de encauzar los datos. Como veremos, PHP es o totalmente transparente a todo este proceso.
1.2. Recursos
Bien, supondremos que con esto hemos sido convincentes y est s deseando ponerte a programar en PHP, pero te est s a a preguntando qu necesitas... e
1.2.2. php.net
Una URL que no pod is olvidar: PHP (http://www.php.net). La p gina ocial, en la que se encuentra el manual e a ocial, y las ultimas versiones disponibles. Una curiosidad que conviene saber es que si se teclea como direcci n http://www.php.net/loquesea, iremos o directamente a la p gina de manual correspondiente a loquesea. Esta caracterstica es muy util para buscar r pidamente a a la referencia de una funci n sin necesidad de usar un motor de b squeda o navegar por el manual. o u
1.2.3. pear.php.net
PEAR (http://pear.php.net), o PHP Extension and Application Repositoryes un repositorio de c digo, o clases de apoyo, peque os frameworks y trozos de c digo que realizan funciones m s o menos complejas a la vez que n o a cotidianas, y que se pueden usar en vuestras aplicaciones libremente. Algunos ejemplos son las libreras de abstracci n o de bases de datos, las de manejo y dibujado de gr cos, autenticaci n o parseo de XML. a o
1.2.4. dotgeek.org
DotGeek es un servidor gratuito, mantenido por aut nticos gur s de PHP, que se ofrece como servidor de pruebas. e u Si quieres probar tu programa con la versi n de anoche de PHP5, o sencillamente eres muy vago como para instalar o un servidor web en tu propio ordenador, pide una cuenta en DotGeek (http://www.dotgeek.org). Tambi n se e celebran concursos y maratones de programaci n de vez en cuando, con premios. o
1.2.5. php-mag.net
International PHP Magazine (http://www.php-mag.net) es una publicaci n bimensual sobre las ultimas teno dencias en PHP. Muchas eminencias del tema escriben artculos aqu, perfectos para estar a la ultima.
1.2.6. triqui..upm.es
Todos aquellos estudiantes de la FI que tengan una cuenta en Triqui (http://triqui.fi.upm.es) ya tienen autom ticamente un servidor web con soporte para PHP donde probar sus programas. a
CAPITULO 1. INTRODUCCION
tiene a sueldo a muchos de los desarrolladores del n cleo). Sin embargo, lo normal es que se oiga hablar de PHP que es u gratis y se pase por alto la existencia de las herramientas de Zend.
1.3. Lo m s b sico a a
No esperemos m s! Manos a la obra! Programemos como locos el trozo de c digo m s sencillo que se pueda! a o a
1.3.3. Comentarios
Para comentar c digo, se usa la sintaxis de C o de Bash: o <? // Un comentario de una sola lnea /* Un comentario de varias lneas */ # Comentario al estilo shell scripting. ?> Como pasa en otros lenguajes, el anidar comentarios de bloque causa problemas.
Captulo 2
Variables y Operadores
Todo esto es muy bonito, pero no vale de nada si no podemos almacenar informaci n en alg n sitio - veamos c mo o u o son las variables en PHP.
2.2.2. Entero
Los n meros enteros son casi siempre de 32 bits, con signo (salvo en algunas arquitecturas). El entero m s grande u a representable es, por tanto, 231 y el menor posible es el (231 ) + 1 (m s/menos dos mil millones aproximadamente). a Tambi n se pueden representar n meros enteros directamente en notaci n octal o hexadecimal o binaria: e u o <? $decimal = 42; $octal = 0755; // Con un 0 delante // Con 0x delante
// Notacin cientfica o
2.2.4. Cadena
Las cadenas son cadenas de texto ASCII normal y corriente (no Unicode). El tama o m ximo de una cadena viene n a limitado unicamente por la cantidad de memoria disponible para el proceso de PHP que se ejecute en ese momento (que seg n conguraci n de f brica, es de 8 MiB). No existe el tipo car cter. u o a a Las cadenas se encierran o bien en comillas simples ( ) o bien en comillas dobles ( ). Las diferencias son: Las comillas simples no tienen en cuenta ning n car cter de escape, excepto \ (que se escapa por una comilla u a simple) y \\ (que se escapa por una contrabarra). Las comillas dobles hacen expansi n de variables. Esto es, cualquier nombre de variable (con d lar includo) que o o haya dentro de una cadena con comillas dobles ser sustitudo por su valor, siempre y cuando la variable sea de un a tipo simple (no compuesto). Dentro de comillas dobles, no es necesario escapar la comilla simple.
<? $nombre = Pepe; echo Hola $nombre<br>; $frase = "Hola $nombre<br>"; echo $frase; echo "Hola \$nombre<br>"; echo "Las cadenas pueden ocupar varias lneas sin ningn problema, incluyendo u saltos de lnea, <pero hay que tener cuidado de cerrar las comillas!"; ?> Los caracteres de escape son \n, \r, \t, \\, \, \, \$ y \x00, donde 00 es un n mero hexadecimal, lo que se sustituye u por el car cter ASCII correspondiente. a Las cadenas en PHP son binary-safe , es decir, pueden amacenar contenido que no sea texto, sin riesgo de perder informaci n (recordemos el \0 de C). Esto permite trabajar con im genes, sonido y otros formatos de informaci n. o a o
2.2.5. Nulo
El tipo nulo s lo tiene un valor posible: NULL. Se suele usar como valor de retorno para signicar que no hay datos o (lo cual es distinto de un cero decimal, o de una cadena vaca).
2.3.1. Recursos
Los punteros a chero, socket, pipe o fo, las conexiones a Bases de Datos, las estructuras para el tratamiento de im genes y otras variables que se usan para trabajar con datos externos toman el tipo resource . No es posible (y mucho a menos recomendable) manejar manualmente este tipo de variables.
2.3.2. Arrays
Un array es a la vez un vector, una lista, un conjunto, una tabla hash, una matriz, una pila, una cola y un arbol. Se ver n en profundidad m s adelante. a a
2.3.3. Objetos
El t rmino Programaci n Orientada a Objetosda el suciente miedo como para dedicarle una secci n entera. e o o
2.4. Operadores
2.4.1. Expresiones
PHP, al igual que C y muchos de sus derivados, maneja el concepto de expresiones. Una expresi n es cualquier cosa o terminada en punto y coma, y que vale algo. Por ejemplo:
5+1; // Esto "vale" 6. $a = 5+1; // Esto "vale" 6. substr("Hola",0,2); // Esto "vale" "Ho". $b = substr("Hola,0,2); // Esto "vale" "Ho". ?>
$a = "33 peras" + "9 manzanas"; // $a vale 42. // Quin dijo que no se podan sumar peras y manzanas (o cadenas)? e ?>
2.4.3. De cadenas
El punto (.) concatena cadenas (y hace conversi n de tipos si es necesario). o <? $uno = 1; $a = Mary tena . $uno . " corderito"; ?>
2.4.4. Asignaci n o
El operador b sico de asignaci n da un valor a una variable. Pero hay otros operadores de asignaci n, que realizan a o o operaciones aritm ticas o de concatenaci n de cadenas sobre la variable sobre la que hacen la asignaci n: e o o <? $a = 1; $a $a $a $a += *= /= -= 2; 8; 4; 1; // $a vale 1. // // // // equivale equivale equivale qeuivale a a a a $a $a $a $a = = = = $a $a $a $a + * / 2; 8; 4; 1; $a $a $a $a vale vale vale vale 3 24 6 5
2.4. OPERADORES
?>
2.4.5. Comparaci n o
Los operadores de comparaci n devuelven siempre un booleano, son: o == : Igualdad. Hace conversi n de tipos as que (5 == 5.0) es verdadero y (5 == 5) tambi n es verdadero. o e != : Desigualdad. Como la igualdad, pero justo al rev s. e === : Equivalencia. Como la igualdad, pero adem s, comprueba los tipos. As que (5 === 5) es verdadero, pero (5 a === 5) es falso. !== : Inequivalencia. Como la equivalencia, pero justo al rev s. e <, >, <=, => : Mayor que, menor que, etc. . . Pueden comparar n meros, o pueden comparar cadenas alfab ticau e mente (seg n tabla ASCII). u
2.4.6. De Errores
Un operador curioso es la arroba, el operador de supresi n de error. Sirve para no mostrar el posible error que pueda o ocurrir al ejecutar una funci n: o <? $fd = @fopen(fichero.txt); // Si el fichero no existe, no se mostrar ningn error a u ?> Sin embargo, esto no quiere decir que no se vayan a producir errores. Siempre hay que comprobar el valor de retorno para ver si todo ha ido bien.
// Post-incremento: $b == 5 y $a == 6.
// Pre-incremento:
$b == 6 y $a == 6.
// Post-decremento: $b == 5 y $a == 4.
// Pre-decremento:
$b == 4 y $a == 4.
10
2.4.8. L gicos o
El unico operador l gico unario es la admiraci n (!), que niega la expresi n que le sigue. Los operadores l gicos o o o o binarios son: && - Yl gico o ||- Ol gico o and - Yl gico o or - Ol gico o xor - xor l gico o Hay que tener en cuenta que los operadores binarios hacen evaluaci n perezosa. Si la primera expresi n de un Ol gio o o co es falsa, la segunda expresi n no se eval a (no se calcula, y no se ejecuta en caso de que sea una funci n). o u o Como podr is imaginar, los operadores l gicos hacen conversi n implcita de tipos, y siempre devuelven un booleano e o o (verdadero o falso). En concreto, cualquier n mero distinto de 0 equivale a falso, al igual que una cadena vaca, las cadenas u 0y false, el array vaco, y NULL. Por esto es importante darse cuenta de cuando estamos esperando un booleano y recibimos otro tipo (por ejemplo, cuando una funci n puede devolver o bien un booleano a falso o bien un array vaco, y o signican cosas distintas). Recordad usar el operador de identidad (===) cuando sea necesario. El porqu de la existencia de dos operadores Yy dos Ol gicos viene dada por su precedencia, and, xory e o ortienen la precedencia m s baja, y por tanto se eval an despu s de todo. Un uso curioso de los operadores l gicos es a u e o el control de errores b sico. En muchos programas se usa algo como lo siguiente: a <? @hacer_algo_que_puede_fallar() or die(Algo ha ido mal); ?> De esta manera, si la funci n hacer algo que puede fallarcausa un error (y, por tanto devuelve algo distinto de cero), o no se mostrar ning n error (operador @), y se terminar la ejecuci n mostrando un breve mensaje (die();). a u a o
2.4.10. Ternario ? :
La panacea de la criptoprogramaci n; la expresi n que hay que usar si no quieres que nadie entienda tu c digo; la o o o manera m s sencilla de liar a alguien; el modo m s raro de compactar c digo de manera eciente: es el operador ternario: a a o <? $a = ( $b ? $c : $d ); ?> Si $b, entonces lo que hay entre par ntesis vale $c, y si no, vale $d. e
11
$a = (boolean) 56-7; // $a es el booleano "true". ?> Tambi n se puede usar la funci n settype() para el mismo prop sito, pero hacer type casting suele resultar en un e o o c digo m s legible. o a
12
<? $nombre = el_sentido_de_la_vida; $nombre = 42; echo $el_sentido_de_la_vida; // Devolver por salida estndar "42". a a ?>
2.6. (In)denici n o
En PHP podemos crear variables cuando nos venga en gana, simplemente asignando un valor a una variable hasta entonces inexistente. En un principio, no hay ninguna variable denida, y conforme se van usando se van deniendo (se van creando). De cualquier manera, siempre podemos intentar saber el valor de una variable no denida. Para PHP, cualquier variable que no est denida equivale a NULL. e
2.6.1. unset()
Pero tambi n podemos destruir una variable, liberando memoria, o simplemente limpiando datos de entrada para evitar e sorpresas posteriores. Esto se hace con unset(): <? $el_sentido_de_la_vida = 42; unset($el_sentido_de_la_vida); echo $el_sentido_de_la_vida; // No imprimir nada, ya que se evala a u // la variable, ahora inexistente, como NULL. ?>
2.6.2. isset()
Por ultimo, con isset() sabremos si una variable est denida o no. Esto es util para ver si un navegador me ha mandado a datos (como veremos m s adelante), o ver si existe determinada variable global. a
Captulo 3
Estructuras de control
3.1. Bifurcaci n o
Cuando queremos que el programa llegado a cierto punto ejecute o no ciertas instrucciones dependiendo de una o varias condiciones nos serviremos de las estructuras de control de ujo: if-else, if-elseif-elseif-else y switch-case.
3.1.1. if-else
La estructura de control if-else ejecuta una de las dos posibles ramas dependiendo de la evaluaci n de la condici n. o o Por ejemplo: <? $a = 8; $b = 3; // Esto "vale" 8. // Esto "vale" 3.
if ($a < $b) // Evaluamos la condicin: >a es menor que b? o { echo "a es menor que b"; // Esto se ejecuta si la condicin se evala a cierto. o u } else { echo "a no es menor que b"; // Esto se ejecuta si la condicin se evala a falso o u } ?> En este caso la condici n se evaluar a cierto y se ejecutar la primera rama. Es decir el programa imprimir por o a a a pantalla a es menor que b
3.1.2. if-elseif-elseif-else
La estructura de control if-elseif-elseif-else permite anidar tantas condiciones como queramos. La palabra reservada elseif permite denir en una sola lnea una nueva condici n. Por ejemplo: o <? // Introducimos diferentes mensajes de bienvenida para cada idioma $espanol = "Hola"; $ingles = "Hello"; $frances = "Bonjour"; // Leemos una variable del navegador que nos indica cul es su lengua oficial a 13
14
$idioma=substr($_SERVER[\HTTP_ACCEPT_LANGUAGE\],0,2); if ($idioma == "es") // >La lengua del navegador es "espaol"? n { echo "$espanol"; // Imprimimos la variable con el saludo en espaol. n } elseif ($idioma == "fr") // >La lengua del navegador es "francs"? e { e echo "$frances"; // Imprimimos la variable con el saludo en francs. } else // En cualquier otro caso. { e echo "$ingles"; // Imprimimos la variable con el saludo en ingls. } ?> Podemos anidar tantas estructuras elseif como queramos.
3.1.3. switch-case
La estructura de control switch-case podemos ejecutar unas u otras instrucciones dependiendo del valor de una variable. Por ejemplo: <? $color = "azul"; switch ($p_cardinales) { case "rojo": // Si color = rojo echo "El color rojo es primario"; break; case "amarillo": // Si color = amarillo echo "El color amarillo es primario"; break; case "azul": // Si color = azul echo "El color azul es primario"; break; default: // Si es otro color echo "Es un color no primario"; } ?> En este caso ejecutaramos la rama del case azul y se imprimira por pantalla El color azul es primario. Si la varible no es igual a ninguno de los case, entonces se ejecuta el c digo que hay tras la palabra reservado default. Contemplar un o caso default por si fall n todos los dem s es optativo pero altamente recomendable. a a
3.2. Bucles
Los bucles permiten ejecutar un conjunto de instrucciones un determinado n mero de veces dependiendo de la evau luaci n de una condici n. o o
3.2. BUCLES
15
3.2.1. while
El bucle while posiblemente sea el m s sencillo y el m s usado. Mientras se cumpla la condici n se ejecutan un a a o conjunto de instrucciones. Su estructura es: <? while (condicin) o { intrucciones a ejecutar. } ?> Un ejemplo que va incrementando el tama o de la fuente de letra: n <? $size = 1; while ($size <= 6) { echo"<font size=$size>Tamao $size</font><br>\n"; n $size++; } ?>
3.2.2. do-while
El bucle do-while es muy parecido al anterior la diferencia es que primero se ejecutan el conjunto de instrucciones y despu s se eval a la condici n para comprobar si se sale del bucle o se sigue iterando. Esto signica que en cualquier e u o caso al menos una vez se ejecutar el bloque de instrucciones. Su estructura es: a <? do { intrucciones a ejecutar. } while (condicin) o ?>
3.2.3. for(inic;cond;accion)
El bucle for se comporta de manera similar a los anteriores pero con la salvedad de que se le pasan tres expresiones dentro del par ntesis. Las expresiones van separadas por ; y signican lo siguiente: e Inicializaci n. Esta expresi n se ejecuta s lo una vez antes de entrar en el bucle. Generalmente lo usaremos para o o o inicializar un contador. Condici n. Esta expresi n se eval a a cierto o falso y dependiendo de su valor se itera otra vez o no. o o u Acci n. Esta expresi n se ejecuta en cada iteraci n despu s de ejecutar el bloque de instrucciones entre corchetes. o o o e Generalmente lo usaremos para incrementar un contador. Un ejemplo para construir una tabla:
16
<? $colum = 5; $fil = 3; echo("<table border=\"1\">\n"); for ($i=1;$i<=$fil;$i++) { echo("<tr>\n"); for ($j=1;$j<=$colum;$j++) { echo ("<td>fila $i, columna $j<td>\n"); } echo("</tr>\n"); } echo("</table>") ?>
Captulo 4
Arrays
Nunca un nombre tan peque o ha escondido una estructura de datos tan grande. n
$a = array(Hola , ,
mundo , !);
echo $a[0] . $a[1] . $a[2] . $a[3]; // Esto sacar por salida estndar "Hola mundo!" a a echo $a; // Esto sacar la cadena de texto "Array" por salida estndar, ojo con esto!! a a ?> (En realidad, array() no es una funci n, sino una construcci n del lenguaje: puede usarse en sitios donde una funci n o o o no podra, como valores por defecto para variables).
18
CAPITULO 4. ARRAYS
// Esto no va a funcionar bien. echo "Hola {$a[2]}"; // Esto sacar "Hola mundo" por salida estndar. a a ?>
unset($a[2]); // $a[3] sigue existiendo, no se "mueve" de sitio. ?> Lo cual nos lleva a una interesante observaci n: los elementos de un array no tienen porqu ser consecutivos: o e <? $a[1] = Hola mundo!; $a[24] = 3.1416; $a[2] = true; $a[50] = 42; ?> Consecuencia: es mala idea, pero muy mala, iterar sobre un array suponiendo que sus elementos son consecutivos. Si en el ejemplo anterior sabemos que $a tiene cuatro elementos, y accedemos a $a[0], $a[1], $a[2] y $a[3], probablemente nos llevemos una sorpresa.
19
4.1.4. [ ]
El operador especial [ ] a ade un elemento con clave num rica a un array, siendo la clave num rica una unidad m s n e e a grande que la mayor clave num rica denida... e <? $a[1] = Hola mundo!; $a[24] = 3.1416; $a[] = true; // Equivale a $a[25] = true; $a[50] = 42; $a[3] = 333; $a[] = Ranita; // Equivale a $a[51] = Ranita; ?>
4.1.5. [foo]
Pero no s lo se pueden denir arrays con claves num ricas, sino tambi n con claves alfanum ricas: o e e e <? $persona[nombre] = Ivn; a $persona[apellidos] = Snchez Ortega; a $cosa = dni; $persona[$cosa] = 123456789; // Equivale a $persona[dni] = 123456789; ?> Normalmente se pone la clave alfanum rica entre comillas, por precauci n. Hace unos a os era costumbre hacer e o n referencia a las variables con clave alfanum rica sin las comillas, pero si haba denida una constante del lenguaje, o se e usaba una palabra reservada como clave, todo empieza a fallar. Hoy en da tambi n se puede usar la sintaxis sin comillas, e pero es muy, muy, muy preferible evitar problemas a posteriori. Tambi n se pueden usar variables que contengan una cadena, como se ve en el ejemplo anterior. Y tambi n se puede e e usar una cadena con comillas dobles, y con una variable dentro que se expanda... Un array puede tener s lo claves alfanum ricas (cadenas), s lo claves num ricas (enteros, positivos o negativos), o e o e ninguna clave (el array vaco), o ambos: <? $a[1] = Hola mundo!; $a[pi] = 3.1416; ?> No se pueden usar como claves n meros en coma otante, ni booleanos, ni ning n otro tipo de datos. u u La funci n array() tambi n permite denir claves alfanum ricas, o en el orden en que queramos: o e e <? $a = array( 1 => Hola mundo! , pi = 3.1416 ); ?>
20
CAPITULO 4. ARRAYS
21
print_r($matriz); echo </pre>; ?> Una funci n similar es var dump(), pero esta ultima no formatea el resultado como lo hace print r(). Sin embargo, es o util para conocer m s datos de una variable: tipo, en caso de que sea una cadena, su longitud, etc tera. a e
22
CAPITULO 4. ARRAYS
foreach() hace todo el trabajo por nosotros, sin posibilidad de error. Adem s, si queremos podemos tambi n obtener a e cada par clave/valor, de la siguiente manera: <? $personas[12345678] $personas[20300400] $personas[45268732] $personas[21459870] = = = = Pepito; Fulanito; Menganito; Zutanito;
foreach($personas as $dni => $nombre) { echo "$nombre tiene el DNI nmero $dni <br/>"; u } ?>
reset($personas); while ( list($dni,$nombre) = each($personas)) { echo "$nombre tiene el DNI nmero $dni <br/>"; u } ?> Puede parecer una sintaxis compleja, pero ahora veremos en qu se basa para iterar bien sobre un array... e
4.2.4. list(), each(), prev(), current(), reset(). Puntero interno, devolviendo arrays.
En PHP, un array no es un array en el sentido tradicional de la palabra, sino una estructura de datos mucho m s potente: a se trata de un map ordenado. Y como todo buen map ordenado que se precie, consta de un puntero interno (invisible para el programador) que apunta a uno de sus elementos. Para trabajar con este puntero se usan, principalmente: reset() - hace que el puntero apunte al primer elemento, y devuelve su valor end() - hace que el puntero apunte al ultimo elemento, y devuelve su valor current() - devuelve el valor del elemento actual next() - avanza el puntero al siguiente elemento, y devuelve su valor prev() - retrocede el puntero al elemento anterior, y devuelve su valor Todas estas funciones devuelven el booleano falso en caso de que el array est vaco o el puntero se haya intentado e salir del array. Cuando se itera usando next() o prev(), conviene inicializar el puntero (ponerlo al principio o al nal) para evitar sorpresas. Sin embargo, el usar prev() o next() tiene un problema, y es que si nos encontramos con un booleano falso, no sabemos si es que hemos llegado al nal del array (o al principio), o si un elemento del array contiene el valor
23
booleano falso. Si adem s usamos comparaciones (==) y no identidades (===), nos encontraremos con este problema a cuando el valor de un elemento sea 0, una cadena vaca, o cualquier otra variable que se eval e a falso. u Para evitar este problema, se usa each(), que funciona de manera parecida a next(). Al usar each() sobre un array, la funci n devuelve tanto la clave y el valor del elemento actual (a su vez, en un array de la forma array(0clave,1valor) o ), o falso si se ha llegado al nal del array; y avanza el puntero interno al siguiente elemento. Y si tengo un array (como el que devuelve each() ), c mo lo convierto a variables normales y corrientes de manera o sencilla? Pues con la funci n list(): o <? $a[1] = Hola mundo!; $a[pi] = 3.1416; list ($hola,$pi) = $a; ?> De esta manera, si quiero saber cu l es el par clave/valor del elemento actual y, de paso, avanzar al siguiente, s lo a o tengo que: <? list ($clave,$valor) = each($array); ?>
24
CAPITULO 4. ARRAYS
asort($personas); // Ahora $personas est ordenado alfabticamente por los nombres. a e ksort($personas); // Ahora $personas est ordenado por DNI. a // sort($personas) destruira la informacin que suponen los DNIs. o reset($personas); while ( list($dni,$nombre) = each($personas)) { echo "$nombre tiene el DNI nmero $dni <br/>"; u } ?> La ordenaci n se hace ascendentemente, y seg n lo que resulte de aplicar los operadores de comparaci n mayor o u o quey menor que. Si queremos hacer la ordenaci n de manera descendente, se usan las funciones gemelas rsort, arsort o y krsort. Si no queremos usar la comparaci n habitual (mayor/menor que), podemos usar usort, uasort y uksort. Un caso o concreto es la ordenaci n natural , muy util cuando ordenamos nombres de chero que empiecen por n meros sin ceros o u a la izquierda.
4.3.4. (un)serialize()
A veces, cuando llega la hora de guardar los datos en un chero o en una base de datos, puede que usar una estructura compleja no sea la mejor idea. Pero si queremos guardar un array y despu s volverlo a tener como nuevo, podemos e serializarel array, convirti ndolo en una cadena de texto. De igual manera, al des-serializaruna cadena obtendremos e un array (si la cadena no ha sido modicada, claro):
25
<? $a[1] = Hola mundo!; $a[pi] = 3.1416; $texto = serialize($a); $b = unserialize($texto); ?>
Captulo 5
Procesamiento de formularios
5.1. Los viejos tiempos
Antes de los inicios de PHP, se cre un est ndar, el Common Gateway Interface (CGI), para denir c mo pasar o a o datos a una aplicaci n web. Un programa que se comunique con un servidor web mediante CGI recibir ciertos datos o a como variables de entorno, y ciertos datos por entrada est ndar. En la epoca de PHP/FI (antes de PHP3) era comun usar a parse str() y decode url() para acceder a los datos enviados a una aplicaci n web hecha en PHP. o Con el paso del tiempo y la proliferaci n de aplicaciones web, naci la necesidad de simplicar este proceso. Por eso, o o PHP parsea autom ticamente las variables pasadas al script, para que el programador se las encuentre ya listas. a
5.2. $ GET
La manera m s f cil de pasar datos a nua aplicaci n web es mediante GET. Esto es, mediante la inclusi n de pares a a o o variable-valor en la URL de la p gina a la que visitamos: con un signo de interrogaci n despu s de la URL, y pares a o e variable=valorseparados por &. Por ejemplo, la siguiente URL: http://www.loquesea.org/donde/algo.php?var1=valor1&var2=valor2 Har que el script algo.php reciba estos valores dentro de un array superglobal $ GET, un elemento del array por cada a par variable-valor, como si se hubieran declarado de la siguiente manera: <? $_GET[variable1]= valor1; $_GET[variable2]= valor2; ?> De esta manera, es muy f cil construir URLs que sirvan para pasar datos a otros scripts, as como recoger estos datos. a Sin embargo, si queremos pasar un dato que contenga un car cter raroque pueda dar problemas (espacios, interrogaa ciones, &, y por extensi n cualquier car cter no estrictamente alfanum rico) es conveniente escapar este dato antes de o a e pasarlo a la URL. Esto se puede hacer de manera autom tica usando encode url(). a Los formularios (X)HTML que usen el m todo GET har n que el navegador construya una URL con los datos introe a ducidos, y la visite a continuaci n. o
5.3. $ POST
El paso de par metros por GET tiene varios inconvenientes. Los dos m s notables son la limitaci n del tama o a a o n (alrededor de 8 KiB en total), y la visibilidad de los datos a posteriori (en logs del servidor web, o en la cach o el historial e del navegador web). Por estas razones, se suelen usar formularios con m todo POST. e Aquellos elementos pasados por POST se recoger n por un programa PHP como elementos de la variable superglobal a a $ POST, de manera an loga a $ GET. Hay que recordar que la clave del elemento del array equivale al nombre que se le ha dado al elemento del formulario en la p gina anterior, y el valor es el contenido de ese elemento (lo que ha introducido a un usuario en un campo de texto, o el valuede un elemento de una lista desplegable o una casilla de selecci n). o 26
5.4. $ FILES
27
5.4. $ FILES
El unico elemento de formulario que es tratado de manera especial es el usado para subir cheros (<le type=le. . . >), entre otras cosas porque el mecanismo para enviar el chero diere de el usado para enviar variables por POST. Si subimos un chero al servidor por medio de un formulario, la variable superglobal $ FILES contendr no el chero, sino datos a acerca de el (entre otros, el tama o, nombre real, y localizaci n temporal). El tratamiento de cheros subidos al servidor n o est explicaco en un apartado especco del manual ocial de PHP. a
5.6. $ REQUEST
$ REQUEST es unicamente la uni n de $ SESSION, $ COOKIE, $ POST, $ GET y $ ENV (que contiene las varia o bles de entorno). Si no queremos preocuparnos de c mo ha llegado el dato a la aplicaci n web, es la superglobal a la que o o hay que hacer referencia. En caso de que varios pares variable-valor lleguen a la vez, pero con distinto contenido, se llenar $ REQUEST con a el que tenga mayor precedencia, seg n una directiva de conguraci n variables order. El orden por defecto es EGPCS, u o que signica que cualquier variable de entorno quedar sobreescrita con una variable por GET con el mismo nombre, una a variable por GET quedar sobreescrita por una variable POST del mismo nombre, etc tera. a e
5.7. $ SERVER
Tambi n hay datos que no se reciben por CGI, pero que est n ah, como por ejemplo la IP desde la que visitan e a la p gina, el nombre del servidor web, o la identicaci n del navegador. Estos datos se almacenan dentro del array a o superglobal $ SERVER. Para ver todos estos datos, podemos usar php info(), que adem s nos dar informaci n sobre la a a o conguraci n de PHP, as como de los m dulos cargados. o o
5.8. Superglobales
Lo que diferencia a las variables superglobales aqu descritas, aparte de que se llenanautom ticamente con datos, a es que pueden ser accedidas desde cualquier punto de un programa en PHP, bien sea desde el ujo principal, o dentro de cualquier funci n. Esto aporta mucha comodidad para ver los datos que el script recibe, pero a veces puede causar o molestias y hacer que sea necesaria la utilizaci n de una librera que evite la modicaci n de estos datos. o o
Captulo 6
Ficheros
Fichero: dcese de la secuencia de bytes que tiene sentido y, en la mayora de los casos, soporte fsico. Un chero es la forma b sica de almacenar informaci n en un soporte no vol til (tpicamente un disco duro), pero tambi n son un medio a o a e para intercambiar informaci n con otros programas. o
29
6.2.1. le()
La funci n le() nos permite leer un chero, y almacenar cada una de las lneas que lo componen (separadas e o incluyendo el salto de lnea al nal de la misma) como elementos de un array. Es muy util cuando necesitamos parsear poco a poco un chero de texto con formato sencillo, pues tan s lo tenemos que iterar sobre el array que nos devuelve o le() para recorrerlo.
30
CAPITULO 6. FICHEROS
Lo normal es usar includes para incluir cheros que contienen deniciones de funciones y/o clases. Tambi n es e habitual hacer que un chero includo incluya a otro (por ejemplo, una funci n necesita que tengamos otra declarada). o Esto puede provocar problemas si, por error, se intenta incluir dos veces el mismo chero y como consecuencia se intenta denir dos veces la misma funci n. Para evitar esto usaremos include once(). include once() funciona de la misma manera o que include(), pero con una excepci n: si se llama una segunda (o sucesiva) vez con el mismo nombre de chero, no hace o nada. Tambi n es habitual que nuestro programa dependa de uno de estos cheros que estamos incluyendo. En estos casos, e lo recomendable es usar require(), que funciona como include() salvo que producir un error y detendr la ejecuci n a a o del programa si no se puede incluir el chero (porque no exista o porque no haya permisos para leerlo). An logamente, a tambi n existe require once(). e
31
6.4.3. sockets
Un socket es otro tipo especial de chero, que sirve para enviar o recibir datos a otro ordenador, normalmente mediante TCP/IP (aunque tambi n podemos hacerlo mediante UDP, ICMP, o usando IPv6). De esta manera, podemos acceder e manualmente a servicios de red si conocemos los detalles del protocolo o nos gusta hacer las cosas a mano . Por ejemplo, abriendo un socket al puerto 23 de otro ordenador podemos hacer que nuestro programa en PHP enve comandos a la otra m quina por medio de una sesi n de telnet. a o Las funciones de manejo de sockets se usan para establecer los par metros de la comunicaci n (o cerrarla, u obtener a o metadatos sobre ella), y tienen su propio apartado en el manual de PHP. Para enviar y recibir datos, se usan fread() y fwrite() como si se tratara de un chero.
Captulo 7
Funciones
7.1. El Concepto
Una funci n (o subrutina, o procedimiento) es un fragmento de c digo que realiza una funci n especca, separada o o o de un programa en el cual se integra.
7.2. ARGUMENTOS
33
{ function foo() { echo Hola mundo!; } } foo(); ?> Tambi n hay que tener en cuenta que una funci n no puede ser re-denida. Sin embargo, podemos saber qu funciones e o e hay denidas usando get dened functions() y function exists().
7.2. Argumentos
7.2.1. function foo($bar)
Si queremos declarar una funci n que acepte argumentos, unicamente hay que poner el nombre de los argumentos, o como si fueran variables, en la denici n de la funci n: o o <? function foo( $parametro ) { echo "He recibido $parametro ."; } foo(5); foo(Hola); ?> Es importante observar que no hace falta declarar el tipo de los par metros, puesto que toda variable en PHP es de a tipo multivariante.
34
CAPITULO 7. FUNCIONES
<? function concatena ($cadena1=Hola ,$cadena2=Mundo!) { return $cadena1.$cadena2; } echo concatena(); echo concatena(Uno,Dos); echo concatena(Adios ); ?> Hay que tener en cuenta que si a una funci n no se le pasan todos los argumentos no predenidos, se generar un o a error. Por esta raz n, es recomendable poner los argumentos predenidos en ultimo lugar. o
7.3. VISIBILIDAD
35
7.3. Visibilidad
7.3.1. Visibilidad reducida dentro de funciones
Se denomina visibilidad (o scope ) a las variables a las que se pueden acceder desde un determinado fragmento de c digo. En otras palabras, la visibilidad dentro de una funci n son las variables que se pueden verdentro de la misma. o o Normalmente, dentro de una funci n s lo podremos ver los par metros que ha recibido, y las variables superglobales o o a (v ase captulo sobre tratamiento de formularios). Si denimos (usamos) una variable dentro de una funci n, s lo se e o o podr usar dentro de la misma, y ser destruida cuando la funci n devuelva el ujo de ejecuci n. Esto es extensible a a o o tambi n a m todos de objetos. e e
7.4. Lambda-programaci n o
La Lambda-programaci n, o programaci n con funciones an nimas, se basa en usar funciones denidas en tiempo o o o de ejecuci n, que no tienen nombre por s mismas, y que son referenciadas por variables (que, a su vez, pueden ser o par metros de otras). a
36
CAPITULO 7. FUNCIONES
Las t cnicas de lambda-programaci n son muy extensas, y puede encontrarse mucha informaci n sobre ellas en buee o o nos libros o cursos de algortmica, en particular aquellos que abarquen alg n lenguaje de programaci n funcional, como u o por ejemplo Haskell. En PHP, una funci n an nima toma la forma de una variable, aunque sera m s preciso decir que la variable es un o o a puntero a la funci n (como pasa en otros lenguajes). La manera de denir funciones an nimas es usando create function(). o o Su uso y ejemplos est n perfectamente documentsods en el manual ocial de PHP. a
Captulo 8
38
8.1.2. Instancias: instanceof (comprueba que es un objeto es una instancia de una clase)
Una confusi n com n es no diferenciar claramente entre clasey objeto. Una clase es una denici n abstracta: una o u o persona, una asignatura, un coche. Un objeto, que debe ser una instancia de una clase, es una entidad propia: Pepito P rez, e Estructuras de Datos II, el BX blanco con matrcula 6609-JW. Dos objetos son iguales (==) si sus propiedades (variables) son iguales; dos objetos son id nticos (===) s lo si son e o la misma instancia (una referencia). Tambi n se pueden clonar objetos, lo cual crea una instancia igual, pero no id ntica. e e M s informaci n sobre clones de objetos en el manual de PHP. a o Para saber a qu clase pertenece un objeto en concreto, se puede usar instanceof o get class(): e <? class alumno { public $nombre; public $dni; } $pepe = new alumno; $pepe->nombre = Pepito Prez; e $pepe->dni = 123456789; if ($pepe instanceof alumno) { // Hacer cosas } echo get_class($pepe); ?>
8.1.3. Apto para todos los publicos: public, protected, private, visibilidad - E STRICT
Hasta ahora, hemos visto propiedades y m todos p blicos, que se pueden acceder desde fuera del objeto sin ning n e u u problema. Muchas veces, no queremos que las propiedades de un objeto se cambien desde fuera. Por ejemplo, si tenemos una pila, queremos que s lo se puedan hacer las operaciones de push y pop. Para esto, declararemos propiedades como privada: o <? class pila { private $datos=array(); public function push($dato) { array_push($this->datos,$dato); } public function push($dato) { return array_pop($this->datos); } } $mi_pila = new pila; $mi_pila->push(5);
39
$mi_pila->datos = array(5,8,7); // Esto dar un error, puesto que no puedo acceder a la propiedad $datos a ?> En el ejemplo hemos aprovechado para ilustrar tambi n propiedades por defecto: al crearse una instancia de la clase e pila, la propiedad $datos ser siempre un array vaca. a
8.1.4. Herencia
A veces ya tenemos una clase dise ada, pero queremos a adirle funcionalidad, o crear una clase similar. En estos n n casos en los que queremos ampliar lo que una clase puede hacer (pero queremos conservar la antigua), se usa la herencia de clases. Cuando una clase (clase hija) hereda de otra (clase padre), al declararla como class hija extends padre, toma todas las propiedades y m todos del padre. De esta manera, si se llama a un m todo o propiedad y este no est denido e e a en el hijo, se tomar la denici n del padre y se obrar en consonancia. a o a Sin embargo, hay que tener otra consideraci n: un m todo o propiedad declarada como privada s lo se puede usar en o e o el contexto de una clase, no en el contexto de una clase que herede de ella (una clase hija). Si queremos que una propiedad o elemento se pueda acceder desde el contexto de una clase hija pero no desde fuera de un objeto, no la declararemos como privada (private ), sino como protegida (protected ). Para usar algo que s lo est en el contexto de una clase padre (como puede ser una funci n que hayamos redenio a o do), accederemos a ese contexto usando parent::. Esto es el operador de contexto, que veremos con detenimiento m s a adelante. Ilustraremos esto con un ejemplo: <? class pila { private $datos=array(); public function push($dato) { array_push($this->datos,$dato); } public function push($dato) { return array_pop($this->datos); } } class pila_acotada extends pila { private $elementos=0; private $max_elementos=30; public function esta_vacia() { return ($this->elementos == 0); } public function esta_llena() { return ($this->elementos == $this->max_elementos); } public function push($dato) { if ($this->esta_llena())
40
return false; // Error $this->elementos++; parent::push($dato); return true; } public function pop() { if ($this->esta_vacia()) return false; // Error $this->elementos--; return parent::pop(); } } $mi_pila = new pila_acotada; $mi_pila->push(5); ?>
Veamos qu hace este ejemplo. La funcionalidad b sica (almacenar datos en una pila) est en el padre, y s lo en el e a a o padre. El hijo aporta una funcionalidad extra (la acotaci n), pero no se preocupa lo m s mnimo de c mo se almacenan los o a o datos (llama al push y el pop del padre, en su contexto). De hecho, el hijo no podra acceder directamente a $thisdatos, puesto que est denida como variable privada. S que podra acceder, sin embargo, si fuera una variable protegida. a
41
?> Si se omiten las llaves, nos encontraremos con un poco descriptivo Objecten vez de la propiedad que queremos.
8.2.1.
construct()
La funci n constructora de clases se ejecuta al instanciar un objeto. En otros lenguajes, la funci n constructora toma o o el mismo nombre que la clase, pero PHP tom la decisi n de usar el mismo nombre para todos los constructores, para o o ganar en claridad. El constructor de una clase se ejecuta justo despu s de crear la instancia. Puede (o no) llamarse con argumentos. e Normalmente se usa el constructor para inicializar el estado del objeto, siempre que se necesite que el estado del objeto dependa de las condiciones que se den en el momento de crearlo (en el ejemplo a continuaci n, la fecha en la que se hace o la instancia): <? class alumno { public $nombre; public $dni; private $fecha_matriculacion; public __construct($fecha=NULL) { if (!$fecha) $this->fecha_matriculacion = date(m/Y); // Mes/Ao actual n else $this->fecha_matriculacion = $fecha; // Fecha que nos hayan pasado al instanciar el objeto } public function suspender_redes() { echo "{$this->nombre} ha suspendido redes y est muy triste."; a } public function aprobar_redes() { echo "{$this->nombre} ha aprobado redes y est muy contento."; a } } $pepe = new alumno; // Se llama al constructor sin argumentos $pepe->nombre = Pepito Prez; e $pepe->dni = 123456789; $juan = new alumno(09/2003); // Se llama al constructor con un argumento $juan->nombre = Juan Juarez; $juan->dni = 987654321; ?>
42
8.2.2.
destruct()
De manera an loga al constructor, existe el destructor, que se ejecuta justo antes de hacer desaparecer un objeto. a Recordemos que una variable (en nuestro caso, un objeto) se destruye siempre cuando se eliminan todas las referencias a ella, y siempre que termine la ejecuci n. No hace falta destruir especcamente todos los objetos que hemos creado, o puesto que ya se destruir n al terminar la ejecuci n. a o
8.2.3.
autoload()
El autoload es uno de los mejores inventos desde el pan de sandwich. Todo buen programador fragmenta su c digo o en cheros m s o menos peque os, m s manejables que un chero grande conteniendo todo el c digo - una muy buena a n a o pr ctica es denir una clase en un chero con el nombre de la clase, y es una pr ctica muy extendida. a a Ahora bien, lo m s normal es incluir todos los cheros que denen clases, aunque no se usen, no vaya a ser que a intentemos instanciar algo que no hemos denido. Antes de la llegada de PHP5, algunos programadores optaron por soluciones un tanto raras para evitar tener que incluir y denir todas las clases (menos clases declaradas = menos c digo o que interpretar en tiempo de ejecuci n = m s r pido), sobre todo cuando juegan con unos pocos cientos de clases. o a a De qu va esto de autoload() ? Si autoload() se dene en el contexto global (fuera de cualquier clase o funci n), y e o se intenta instanciar una clase no denida, se llamar a autoload() pasando como par metro el nombre de la clase, y se a a a instanciar la clase cuando autoload() haya terminado. Lo m s normal es que autoload() haga un include (o require) a del chero que dene la clase que se busca. <? // // // // // Antes require_once(class.alumno.php); require_once(class.pila.php); require_once(class.coche.php); require_once(class.tenedor.php);
// Ahora function __autoload($clase) { require_once("class.$clase.php"); } $juan = new alumno(09/2003); $mi_pila = new pila; ?>
8.2.4.
sleep(), wakeup()
Como los arrays, los objetos se pueden serializar para ser convertidos en una cadena de texto que despu s podemos e salvar a chero o BBDD. sleep prepara al objeto para ser serializado (se llama autom ticamente justo antes de serializar), a y wakeup se ejecuta justo despu s de des-serializar un objeto. (siempre que sleep y/o wakeup est n denidas en la e e clase, claro est ). a Uno de los usos que se le da es cerrar cheros y conexiones a BBDD en sleep y volver a abrirlos en wakeup.
8.2.5.
Normalmente, cuando hacemos un echo de un objeto, nos encontraremos con un inspido y poco descriptivo Ob jecten salida est ndar. Para aliviar esto, y facilitar en muchos casos el debug de programas grandes, est toString. a a toString se llama siempre que se hace un echo o un print() de un objeto: <? class alumno
43
{ public $nombre; public $dni; public function suspender_redes() { echo "{$this->nombre} ha suspendido redes y est muy triste."; a } public function aprobar_redes() { echo "{$this->nombre} ha aprobado redes y est muy contento. "; a } public function __toString() { return $this->nombre; } } $pepe = new alumno; $pepe->nombre = Pepito Prez; e $pepe->dni = 123456789; $pepe->aprobar_redes(); echo "$pepe hoy no quiere ir a clase."; ?> En el ejemplo, se nos mostrar la propiedad $nombre cuando hagamos referencia al objeto en general. Esto, combinado a o o con un print r() o un var dump(), puede ayudar enormemente a la depuraci n de c digo.
8.2.6.
get()
get se llama autom ticamente si se intenta acceder a una propiedad que no est denida en una clase. Sirve, junto con a e set y call, para construir clases que aparenten ser m s de lo que son, que aparenten tener m s m todos o propiedades a a e de los que realmente tienen. <? class ficheros_configuracion { public function __get($var_name) { if (file_exists($f = /etc/.$var_name) && is_readable($f)) return file_get_contents($f); else return false; } } $fich = new ficheros_configuracin; o echo $fich->hosts;
44
// Imprimir el contenido del fichero /etc/hosts . a echo $fich->hwhurgsbsd; // Esto devolver falso, porque /etc/hwhurgsbsd probablemente no existe. a ?>
8.2.7.
set()
set funciona de manera an loga a get: se llama autom ticamente cuando se quiere asignar un valor a una propiedad a a no denida. <? class ficheros_configuracion { public function __get($var_name) { if (file_exists($f = /etc/.$var_name) && is_readable($f)) return file_get_contents($f); else return false; } public function __set($var_name,$valor) { if (file_exists($f = /etc/.$var_name) && is_writable($f)) return file_put_contents($f); else return false; } } $fich = new ficheros_configuracin; o $fich->hosts = $fich->hosts . "\n127.0.0.1 www.loquesea.com\n"; // Aade una entrada al fichero /etc/hosts. n ?>
8.2.8.
call()
La ultima de las funciones m gicas (al menos, hasta que introduzcan m s en PHP5) es call. Similar a get y set, a a call se llama autom ticamente cuando se llama a un m todo no denido. call() recibe dos argumentos: el nombre del a e m todo que se ha querido llamar, y un array con los argumentos. De esta manera, podremos tener clases con todos los e m todos virtuales que queramos. e
45
46
8.3.4. F bricas a
Las f bricas tienen un prop sito sencillo: devolver un objeto de una clase que determina la f brica, dependiendo de a o a ciertas condiciones. Por ejemplo, si tengo varias libreras que sirven para el mismo prop sito (QT, GTK+ y Motif para objetos gr cos, por o a ejemplo), las cuales implementan algo com n (una barra de desplazamiento, por ejemplo) pero de manera distinta (seguu a a ramente tenemos qt scrollbar, gtk scrollbar y motif scrollbar), una f brica me permitir tener una barra de desplazamiento sin preocuparme de qu librera use por debajo mi aplicaci n. e o En PHP quiz s este no es un ejemplo descriptivo (ya que normalmente no interact a con el usuario a trav s de una a u e interfaz gr ca). Pero ilustraremos la idea de las f bricas con un ejemplo sencillo: a a <? class coche { public function conducir() { return Estoy conduciendo un . get_class($this); } } class coche_fiat extends coche { public static $precio = 8900; } class coche_citroen extends coche { public static $precio = 7650; } class coche_mercedes extends coche { public static $precio = 15750; } class concesionario // Mi fbrica de coches a { static function compra_un_coche_caro($dinero) { if ($dinero >= coche_mercedes::$precio) return new coche_mercedes; elseif ($dinero >= coche_fiat::$precio) return new coche_fiat; elseif ($dinero >= coche_citroen::$precio) return new coche_citroen; else { echo "No tienes dinero suficiente"; return -1; } } }
47
8.3.6. Interfaces
Un interfaz sigue la idea de una clase abstracta, pero de una forma muy especca: un interfaz es s lo una lista de o m todos que una clase debe implementar (como mnimo) para acomodarse al interfaz. e <? interface coche { public function echar_gasolina($litros); public function recorrer($kilometros); } class coche_fiat implements coche { public static $precio = 8900; private $gasolina = 0; const max_gasolina = 55; public function echar_gasolina($litros) { if ($gasolina < 0) return -1; $this->gasolina = ($this->gasolina + $litros < self::max_gasolina)
48
? $this->gasolina + $litros : self::max_gasolina; echo "He echado gasolina y ahora tengo {$this->gasolina} litros.<br/>"; } public function recorrer($kilometros) { // Supongamos 9 litros a los 100 km if ($kilometros < 0) return -1; $this->gasolina -= $kilometros * 9 / 100; if ($this->gasolina <= 0) { $this->gasolina = 0; echo "Me he quedado sin gasolina<br/>"; } else { echo "He recorrido $kilometros kilmetros sin problemas y me o quedan {$this->gasolina} litros.<br/>"; } } } $mi_coche = new coche_fiat; $mi_coche->echar_gasolina(20); $mi_coche->recorrer(150); $mi_coche->recorrer(100); ?>
49
taller_citroen::arreglar($mi_coche); ?>
Captulo 9
BBDD
9.1. Porqu ? e
En muchas aplicaciones web, al crecer, llega un momento en el que trabajar con una cantidad grande de datos se hace inmanejable si se usan cheros para almacenarlo todo. En estos casos, la soluci n m s pr ctica es usar una Base de Datos o a a para almacenar toda al informaci n, y trabajar con ella de forma m s eciente y r pida (desde el punto de vista del tiempo o a a de ejecuci n). o
9.2. Cu l? a
En el mercado de los sistemas de bases de datos, hay relativamente pocos competidores. A continuaci n veremos los o sistemas m s com nmente usados: a u
9.2.1. SQLite
SQLite naci hace poco como una alternativa a los grandessistemas de BBDD. Lo que hace atractivo a SQLite o es que almacena la BBDD en un chero, lo cual elimina la necesidad de un servidor de BBDD en el ordenador. Esto simplica sobremanera la instalaci n y distribuci n de una aplicaci n que use una BBDD por debajo. Si no queremos o o o complicarnos la vida con instalaciones de software, SQLite es la mejor opci n para aplicaciones con PHP5. o SQLite no tiene un gran motor de BBDD, sino tan s lo alrededor de 250 KiB de c digo en unas 30000 lneas de C. o o Esta ligereza hace que PHP5 incluya a SQLite dentro de una instalaci n est ndar. Puede no tener todas las funcionalidades o a de un gran motor de SQL, pero es mucho m s que suciente para aplicaciones peque as y medianas. a n Sin embargo, el mayor problema de SQLite es la eciencia. Aunque es tremendamente r pido para cantidades pea que as de datos (y extremadamente portable), en cuanto se trabaja de manera rutinaria con varios MiB de datos, es n recomendable pensar en otra alternativa. M s informaci n en http://www.sqlite.org/ a o
9.2.2. MySQL
Uno de los pilares de la plataforma LAMP (Linux + Apache + Mysql + PHP), MySQL es un sistema servidor de bases de datos grauito, de c digo libre, altamente escalable, eciente y con muchsima popularidad entre las aplicaciones o desarrolladas tanto en PHP como en otros lenguajes. Cuenta con una implementaci n completa de ANSI SQL, incluyendo o control de transacciones. MySQL AB, la empresa detr s de MySQL, ofrece formaci n y herramientas avanzadas para diversos prop sitos. Con a o o esto, MySQL es una excelente elecci n para aplicaciones medianas o grandes. o M s informaci n en http://www.mysql.com/ a o
9.2.3. Oracle 10
Oracle, la corporaci n gigante en cuesti n de BBDD y su motor de BBDD, Oracle 10. Oracle 10 es m s o menos o o a parecido a MySQL (servidor de BBDD, escalable, eciente, soporta alta carga, distintos tipos de tablas, transacciones, etc), pero la principal diferencia es que Oracle es muy, muy caro. Es la unica opci n disponible si a tu jefe le ha hecho o una visita un comercial de Oracle. 50
9.3. COMO?
51
9.2.4. PostgreSQL
Otro gran motor de BBDD grauito y de c digo libre, con grandes funcionalidades, y tambi n ampliamente usado en o e multiud de aplicaciones. De nuevo, una buena opci n para aplicaciones medianas o grandes. o M s informaci n en http://www.postgresql.org/ a o
9.2.6. Cu l elijo? a
Comparar los distintos grandes sistemas de BBDD es entrar en una contnua guerra religiosa entre los fans de un sistema y los devotos de otro, que distuten calurosamente sobre la funcionalidad que tiene su sistema pero de la que carece el competidor. Por el momento, usaremos SQLite para los peque os ejemplos. A la hora de elegir un sistema mayor, hay n que estudiar pacientemente las alternativas y elegir la que mejor se adapte a nuestras necesidades y posibilidades. S lo veremos la funcionalidad que me permite interactuar con SQLite, desde PHP5. Para documentaci n sobre otros o o sistemas de BBDD, v ase el manual de PHP. e
9.3. C mo? o
9.3.1. Funcionalidades b sicas a
Todo sistema de BBDD basado en SQL implementa una API con, al menos, la siguiente funcionalidad: Abrir una conexi n a una BDD. o Ejecutar una query SQL. Acceder a los resultados de una query SQL. Control de errores en sentencias SQL. Cerrar la conexi n a la BDD. o
52
CAPITULO 9. BBDD
9.4. Cu ndo? a
Ya basta de teora; empecemos ahora mismo a ver alg n ejemplo. u
9.5. QUIEN?
53
9.5. Qui n? e
Muchas veces podemos tener gente graciosillaque se dedique a maltratar nuestra aplicaci n web. Ahora veremos o los riesgos de seguridad b sicos contra los que hay que estar avisado y prevenido. a
9.5.2. Autenticaci n o
Otro error, pero menos com n, es dejar a la vista de cualquier usuario p ginas que permitan la edici n de datos que u a o se supone que un usuario no debera poder tocar. En nuestro ejemplo, cualquier usuario podra visitar admin.php (alguien que se aburra mucho puede empezar a teclear painas al azar a ver si existen) y modicar todo nuestro sistema. La soluci n pasa por autenticar al usuario; ya sea por usuario/contrase a, IP desde la que se visita, CAPTCHAs, o o n m todos biom tricos o criptogr cos. Cada cual tiene sus pros y sus contras; y veremos algo m s sobre la autenticaci n e e a a o de usuarios en el siguiente captulo.
Captulo 10
Autenticaci n y sesiones o
10.1. Nos conocemos de antes?
10.1.1. Memoria de pez
A riesgo de caer pesado, repetir algo que ya se ha dicho antes: en la programaci n web, cada p gina que se visita e o a equivale a une ejecuci n de un programa. Los m s avispados habr n observado que esto conlleva un problema: un visitante o a a o usuario habitual de una aplicaci n web visitar decenas de p ginas y, por tanto, har que en el servidor web se ejecuten o a a a decenas de programas en momentos de tiempo separados. C mo podemos lograr que estos programas, que se ejecutan de o manera separada, compartan informaci n (como, por ejemplo, la identicaci n de un usuario o su carrito en una aplicaci n o o o de tienda on-line)?
10.2. SESIONES
55
espacio en blanco antes del primer <?, la cookie no se enviar correctamente al navegador. Veremos porqu al hablar de a e cabeceras HTTP. (Una cookie, adem s del nombre y el valor, se compone tambi n del servidor web para el que es v lido, la caducidad, a e a si se enva s lo a ciertas p ginas en un path concreto del servidor, y si se aplica s lo a p ginas pedidas por https). o a o a
10.1.3. Sobrepeso
Las cookies fueron una buena idea en un buen momento, pero con el auge y el crecimiento descontrolado de apliaciones web por todos lados (a veces mal programadas), se hicieron visibles los fallos de este mecanismo: por un lado, por cada p gina que un usuario visita, se le mandan al servidor web todas las cookies que el servidor haya mandado al a navegador en un primer momento; en algunas aplicaciones web esto puede suponer una sobrecarga de unos 10 o 15 Kb, que puede superar a la p gina en s. Por otro lado, un usuario avispado con un navegador decente (hoy en da, cualquier a cosa que no sea un IE) puede editar las cookies que manda al servidor y as enga ar a la aplicaci n web. n o Por eso, hoy en da, el uso intensivo de cookies ha dejado paso al uso intensivo de sesiones.
10.2. Sesiones
10.2.1. No m s ping-pong a
Las sesiones se basan de nuevo en el principio de que en navegador enve informaci n a cada p gina que visite en el o a servidor, de manera que se corrigen los problemas de usar cookies para todo. En primer lugar, el navegador mandar un a solo par variable-valor al servidor (normalmente una variable con nombre PHPSESSIDy un md5sum de un n mero u aleatorio como valor). En segundo lugar, los datos que pasan de p gina a p gina (de ejecuci n de programa a ejecuci n a a o o de programa) se almacenan en el servidor y no en el navegador (en el cliente): un usuario listillo no puede cambiar estos datos que pasan de programa en programa. C mo se las arregla el mecanismo de sesiones para que el navegador mande un par variable-valor a cada p gina? o a Usando una cookie, de la que el programador no debe preocuparse en absoluto. Adem s, si el navegador no acepta cookies, a PHP detectar esto, y a adir un par variable-valor a cada petici n que se haga por get, o a cada formulario que se enve a n a o por post, para que este par variable-valor siempre llegue bien. C mo almaceno datos de sesi n? Simplemente usando la variable superglobal $ SESSION. Los contenidos de esta o o variable ser n id nticos para cada ejecuci n de cada p gina si se hacen desde el mismo navegador, y distintas para distintos a e o a navegadores. Es una manera mucho m s natural (y mucho m s segura) que las cookies para que el programador almacene a a datos persistentes entre las ejecuciones de distintas p ginas de una misma aplicaci n web. A los elementos del array a o superglobal $ SESSION se les denomina variables de sesi n. o <? if (!$_SESSION[primera_visita]) echo Vaya vaya, veo que es tu primera visita; else echo Bienvenido de nuevo; $_SESSION[primera_visita] = 1; ?> Una funcionalidad tpica es permitir acceso a determinadas p ginas si y s lo si el visitante de la web ha introducido a o usuario y password. Suponiendo que tengamos una p gina con un formulario que pida estos dos datos, la comprobaci n a o se hara m s o menos as: a <? if ($_POST[usuario]==scott && $_POST[passwd]==tiger) { $_SESSION[usuario_autentificado] = TRUE; $_SESSION[usuario] = $_POST[usuario]; } else
56
if {
($_SESSION[usuario_autentificado])
// Dar la bienvenida, mostrar men de operaciones slo para usuarios, etc u o } else { // Redirigir al visitante a la pgina de login a } ?> Obviamente, el m todo deja bastante que desear cuando hay varios usuarios registrados. Otra posible opci n, si tenee o mos una base de datos con una tabla que contenga informaci n sobre usuarios y passwords, sera: o <? $bd = sqlite_open(base_de_datos.bdd); $r = sqlite_query("select * from usuario where usuario={$_POST[usuario]} and password = {$_POST[passwd]}"); if (sqlite_fetch_array($r)) // Si la consulta me devuelve una fila vlida... a { $_SESSION[usuario_autentificado] = TRUE; $_SESSION[usuario] = $_POST[usuario]; } else { $_SESSION[usuario_autentificado] = FALSE; unset ($_SESSION[usuario]); }
if {
($_SESSION[usuario_autentificado])
// Dar la bienvenida, mostrar men de operaciones slo para usuarios, etc u o } else { // Redirigir al visitante a la pgina de login a } ?> Este m todo tendra dos fallos fundamentales: primero, los passwords se almacenan en texto claro en la base de datos e (si nos roban la base de datos, alguien tendra los passwords de muchas personas sin mayor complicaci n). Segundo, al no o comprobar las variables de entrada de la query, somos susceptibles de sufrir una inyecci n de SQL. El primer problema o se soluciona almacenando hashes de los passwords (v ase la funci n md5() o las funciones de criptografa mediante e o algoritmos sha1 y similares); el segundo problema se resuelve aplicando sqlite escape string() sobre las variables que provengan del navegador y que se vayan a usar en la query. En cualquier otra p gina de nuestra aplicaci n web, tan s lo tendramos que comprobar la variable $ SESSION[ usuaa o o rio autenticado ], y redirigir al usuario a la p gina de login si no tiene valor verdadero. Por supuesto, en $ SESSION a
10.2. SESIONES
57
podemos almacenar cualquier otra informaci n que sea de importancia para la aplicaci n y extensible s lo a un usuao o o rio: contenidos del carrito en una tienda on-line, estilo gr co de la web en caso de que podamos elegir entre varios, a preferencias, soluciones a acertijos y CAPTCHAs (http://www.captcha.net), etc tera. e
10.2.2. Adivina!
A continuaci n se expone un ejemplo de c mo utilizar variables de sesi n para almacenar un dato que queremos mano o o tener entre distintas ejecuciones de una misma p gina web, pero que no queremos que el usuario pueda ver ni modicar, a en este caso la respuesta a un peque o acertijo: n <? // To Do: Aadir doctype y cabeceras html! n session_start(); if (!isset($_SESSION[secreto]) || $_REQUEST[accion]==reset) { $_SESSION[secreto] = mt_rand(1,100); // mt_rand = numero aleatorio $_SESSION[intentos] = 0; } if ($_REQUEST[numero] == $_SESSION[secreto]) { echo "Enhorabuena, has adivinado el nmero tras {$_SESSION[intentos]} u intentos. <br><br><a href={$_SERVER[PHP_SELF]}?accion=reset> Empezar de nuevo</a>"; } else { $_SESSION[intentos]++; echo "Intenta adivinar el nmero que he pensado (entre 1 y 100)!"; u // Debug... // echo " Pssst, no se lo digas a nadie: es el {$_SESSION[secreto]}"; if (isset($_REQUEST[numero])) if ($_SESSION[secreto] < $_REQUEST[numero]) echo " El nmero que tengo en mente es \textbf{menor} que u {$_REQUEST[numero]}"; else echo " El nmero que tengo en mente es \textbf{mayor} que u {$_REQUEST[numero]}"; echo "<br><br>Creo que es el: <form method=post action={$_SERVER[PHP_SELF]}><input type=text lenght=3 size=3 name=numero> <input type=submit></form>"; } ?>
58
C mo funciona esto de las sesiones? Porqu en un ejemplo aparece la funci n session start() y en los dem s no? o e o a A d nde vamos? De d nde venimos? Los interesados en conocer las respuestas a las dos ultimas preguntas, acudan a o o un l sofo o a una secta religiosa. Los interesados en conocer las respuestas a las dos primeras, sigan leyendo. o Las variables de sesi n (los contenidos de $ SESSION) se guardan en el servidor, normalmente en un chero plano o o directamente en memoria si es posible, en una tabla que relaciona un identicador de sesi n (normalmente un md5 de o un n mero aleatorio) con un conjunto de variables de sesi n. Lo que el motor de PHP debe hacer a cada ejecuci n es u o o comprobar si el navegador le ha enviado un identicador de sesi n, y en caso armativo recuperar las variables de sesi n o o correspondientes. El problema es que esta recuperaci n de variables de sesi n no es autom tica en algunos casos. Lo es si la directiva o o a de conguraci n session.auto startest a 1, pero si no lo est , entonces hay que pedir explcitamente que se haga este o a a proceso con session start(). Si tenemos cientos o miles de visitantes, tambi n podemos almacenar las variables de sesi n en una base de datos, e o en vez de en cheros planos, para aumentar la eciencia y reducir la carga. Tambi n lo podemos hacer por motivos e de privacidad (encriptar datos) o de replicaci n (si no podemos arnos de un sistema de chero, al estar la aplicaci n o o repartida en varios servidores para balancear carga, por ejemplo). Esto se puede hacer usando session set save handler() antes de session start(). De esta manera, cada vez que un navegador mande un identicador de sesi n, se consultar la o a base de datos y se sacar n de ah las varaibles de sesi n. Los m s atrevidos pueden experimentar con esto y construir de a o a manera autom tica variables de sesi n mediante session set save handler(). a o Toda la informaci n referente a este aspecto, as como directivas de conguraci n, otras funciones para trabajar con o o sesiones de manera intensiva y algunos ejemplos se pueden consultar en el manual ocial de PHP, en la secci n de o funciones de sesi n. o
59
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>401 Authorization Required</title> </head><body> <h1>Authorization Required</h1> This server could not verify that you are authorized to access the document requested. Either you supplied the wrong credentials (e.g., bad password), or your browser doesn\t understand how to supply the credentials required.</p> <hr> <address>Apache/2.0.52 (Gentoo/Linux) Server at www.dondesea.org Port 80 </address> </body></html>
Es interesante notar que el servidor responde en dos fases: una primera de cabeceras, las cuales son generadas autom ticamente por el servidor web, y normalmente un dise ador o programador no debe preocuparse de ellas. Despu s, a n e tras dos saltos de lnea consecutivos, la p gina web en s (o, si se pide una imagen, la imagen, etc tera). a e El navegador, al ver una cabecera 401 Authorization Required, pedir al usuario un usuario y password, y volver a a a pedir la p gina al servidor, pero esta vez autentic ndose: a a
GET /loquesea.php HTTP/1.1 Connection: Keep-Alive User-Agent: Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.10-1-k7; i686; es) KHTML/3.3.2 (like Gecko) Accept: text/html, image/jpeg, image/png, text/*, image/*, */* Accept-Encoding: x-gzip, x-deflate, gzip, deflate Accept-Charset: iso-8859-15, utf-8;q=0.5, *;q=0.5 Accept-Language: es, en Host: www.dondesea.org Authorization: Basic uYT6OTefMjeyoXc
El usuario y password van en la lnea Authorization, codicados sencillamente en base64 (v ase base64 decode() y e base64 encode()), separados por dos puntos. Esto no es un m todo muy seguro de transmitir informaci n como usuario y e o password, as que ojito con los sniffers, y usad siempre que pod is HTTP sobre SSL (el conocido https://...). a Si el servidor web ve que el usuario/password son correctos, enviar al navegador algo as como: a
HTTP/1.1 200 OK Date: Tue, 01 Mar 2005 23:01:15 GMT Server: Apache/2.0.52 (Gentoo/Linux) Last-Modified: Thu, 30 Dec 2004 02:56:31 GMT ETag: "5ba9d-24e-6ee115c0" Accept-Ranges: bytes Content-Length: 590 Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Content-Type: text/html; charset=ISO-8859-1 <?xml version="1.0" encoding="latin-1"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional/EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional"> <html> <head> </head> <body>
60
Ahora bien, aunque normalmente no vamos a hacer nada con las cabeceras (PHP y el servidor web hacen el trabajo por nosotros), podemos tocarlas con la funci n header(), que debe llamarse antes de que se haya enviado al navegador o el principio de la p gina web, puesto que en tal caso ya se habr n enviado las cabeceras y los dos saltos de lnea, siendo a a imposible mandar otra cabecera despu s. Esto quiere decir que si se ejecuta un echo() (o algo con funci n similar, como e o a print(), print r() o var dump()), o ya se ha devuelto parte de la p gina web si tenamos algo dentro de <? ? >, no es posible enviar cabeceras, y PHP devolver un error. a C mo podemos usar autenticaci n en una aplicaci n web com PHP? Con algo que tenga m s o menos esta pinta: o o o a <? $usuario = sqlite_escape_string($_SERVER[PHP_AUTH_USER]); $passwd = sqlite_escape_string($_SERVER[PHP_AUTH_PW]); $bd = sqlite_open(base_de_datos.bdd); $r = sqlite_query("select * from usuario where usuario=$usuario and password = $passwd"); if (!sqlite_fetch_array($r)) // Si la consulta *no* me devuelve una fila vlida... a { header(WWW-Authenticate: Basic realm="My Realm"); header(HTTP/1.0 401 Unauthorized); echo <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>401 Authorization Required</title> </head><body> <h1>Authorization Required</h1> Anda, machote, la prxima vez pon el usuario y password correctos. o </body></html>; die(); } else { echo "<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>Bienvenido</title> </head><body> <h1>Hola $usuario</h1> Bienvenido a www.dondesea.org </body></html>"; } // Resto de la pgina a ?> Y habra que hacer este tipo de comprobaci n al inicio de cada p gina que necesite autenticaci n. Una pista: es buena o a o idea usar include()s.
61
Captulo 11
XML
11.1. Panacea
11.1.1. Una soluci n a todos los males o
Hace ya unos cuantos a os, se dijo que ATM sera la soluci n que unicara a todas las tecnologas de red (ya fueran n o Ethernet, X25, bra optica, IP sobre paloma mensajera o un vag n de tren cargado de cintas magn ticas). De igual manera, o e hace unos pocos a os, se dijo que XML sera la soluci n para los innitos formatos de intercambio de informaci n. n o o Al usar una sintaxis unicada y una manera m s o menos sencilla de denir las posibles maneras de estructurar un a tipo de informaci n (los DTDs), se supone que XML es capaz de almacenar cualquier tipo de informaci n f cilmente, de o o a manera legible.
11.1.2. O no?
Sin embargo, XML tiene sus desventajas. Una de ellas es que, aunque el formato estuvo listo en poco tiempo, no hay demasiadas herramientas sencillas y potentes para trabajar con XML: muchas de ellas son libreras de programaci n o que implican recorrer una estructura jer rquica a mano . Otro problema es el espacio desaprovechado: para algunas a aplicaciones que intercambian muy poca cantidad de datos, el encapsularlo dentro de XML puede suponer un aumento del 500 % en lo que a tama o (y tiempo de transmisi n) se reere. n o Moraleja: no es conveniente usar XML si existe otro formato, f cil de interpretar y de trabajar con el, que haga el a trabajo (v anse serializaciones de estructuras de datos, por ejemplo). S es conveniente usar XML si queremos desarrollar e un formato m s o menos complejo que sea legible por una persona y que sea m s o menos f cil de manejar mediante a a a nuestros propios programas.
Para parsear un chero en XML s lo hace falta instanciar un objeto de la clase simplexml. Usaremos una receta de poo llo a la vasca en formato RecipeML que podemos encontrar en http://dsquirrel.tripod.com/recipeml/indexrecipes : <? $fichero = Basque_Chicken.xml; $xml = simplexml_load_file($fichero) or die (Unable to load XML file!);
62
11.3. Y YA ESTA?
63
echo <pre>; print_r($xml); echo </pre>; ?> Dentro de un nodo de XML (cualquier fragmento dentro de un tag de apertura <> y uno de cierre <>), podemos acceder a los nodos hijos como si fueran atributos del objeto; y podemos acceder a las propiedades del nodo (el hrefdentro de un <a href=http://loquesea.org>) como elementos de un array (por ejemplo, $xml[href]): <? $fichero = Basque_Chicken.xml; $xml = simplexml_load_file($fichero) or die (Unable to load XML file!); echo "Versin de RecipeML: {$xml[version]} <br>"; o echo "Ttulo de la receta: {$xml->recipe->head->title} <br>"; ?>
11.3. Y ya est ? a
B sicamente esto es lo necesraio para parsear de manera sencilla informaci n en XML. Aunque se puede hacer a o de maneras m s complejas y potentes, el hecho de que la clase implemente propiedades virtuales y funcionalidad para a aparentar ser un array y ser recorrida facilita mucho el navegar por la estructura del arbol de nodos.
64
<? $fichero = Basque_Chicken.xml; $xml = simplexml_load_file($fichero) or die (Unable to load XML file!); foreach( $xml->recipe->ingredients->ing as & $ingredient ) { if ($ingredient->item == Salt) { $ingredient->amt->qty *= 2; } } $xml->asXML(Basque_Chicken_double_salt.xml); ?>
Captulo 12
Tratamiento de errores
Como en cualquier lenguaje, en PHP5 se cometen fallos. En este captulo veremos c mo se clasican los distintos o tipos de error, c mo atraparlos para conseguir m s informaci n o para ocultar el error al usuario nal, y una estructura al o a o estilo Java para tratamiento de errores.
Aunque es preferible evitar el uso del operador de supresi n de errores desde un principio, produciendo c digo m s o o a limpio: <? if (is_readable(/tmp/un_fichero_que_no_existe)) $f = @fopen(/tmp/un_fichero_que_no_existe,r); else echo No he podido abrir el fichero; ?> 65
66
S lo quedan los errores propiamente dichos, tambi n llamados errores fatales. Un error fatal genera un mensaje de o e error por salida est ndar, e inmediatamente despu s causa la detenci n del programa. Ejemplos de errores fatales incluyen a e o el intentar crear una instancia de una clase inexistente, llamar a una funci n no denida. Los errores fatales no suelen o suprimirse, ya que indican un fallo grave en la programaci n. o Adem s de los tres tipos de error b sicos, PHP cuenta con distintos niveles de error, para las distintas capas en las que a a se pueden producir. As, aparte de los errores generados por el propio c digo, tenemos errores y warnings generados por o el motor de PHP, y errores y warnings generados por el parser/compilador. Tambi n se pueden provocar errores, que ser n e a de otros tres tipos (user notice, user warning y user error). En PHP5, se a adi otro nivel de error m s, para ayudar al programador a seguir la sintaxis estricta de PHP5, y evitar n o a el uso de funciones o directivas obsoletas. Un programa que en PHP4 es correcto, muy probablemente no dar ning n a u error en PHP5 siempre y cuando no se muestren los errores de sintaxis estricta (que act an como notices). Un ejemplo de u este tipo de error es el usar el obsoleto vary no public, privateo protectedpara declarar propiedades de una clase. Es muy recomendable activar la impresi n de los errores de sintaxis estricta si queremos que nuestro c digo aproveche o o todas las capacidades de PHP5, y quede libre de funciones obsoletas.
67
68
set_error_handler(oops); // provocamos un error funcion_que_no_existe(); // Y declaramos la funcin de tratamiento... o function oops($tipo, $mensaje, $fichero, $lnea, $contexto) { echo "<h1>Error!</h1> o Ha ocurrido un error en nuestra aplicacin, pero nuestros ingenieros a a altamente cualificados ya estn avisados para corregirlo lo ms antes posible. Por favor, disculpe las molestias."; mail (becario@dondesea.org,<Arregla esto!," Cdigo de error: $tipo o Mensaje de error: $mensaje Script y lnea: $fichero - $linea Contenidos de la pila: " . var_export($contexto,1)); } ?> var export() devolver los contenidos completos de una variable de manera similar a como print r los imprime, y a mail() se encargar de enviar un correo electr nico a alguien, siempre y cuando el motor de php pueda ejecutar sendmail. a o
12.3. Excepciones
El modelo de tratamiento de errores de PHP5, como en tantos otros lenguajes, ha ido complic ndose hasta llegar a un a tratamiento moderno y completo con un sistema de excepciones. El uso de excepciones para provocar e interceptar errores, as como sistemas para su tratamiento, se est haciendo m s popular cada da. Sin embargo, es una materia demasiado a a amplia como para tratarla en profundidad aqu. En el manual ocial de PHP5 est toda la informaci n necesaria. a o
Captulo 13
Miscel nea a
PHP5 no se acaba aqu. Hay muchos otros aspectos que no hemos podido cubrir en este curso pero que son, sin duda, interesantes.
70
13.10. Encriptaci n o
Podemos ocultar ciertos datos usando algoritmos como DES, Blowsh o SHA para cifrarlos antes de volcarlos a chero o a BDD.