Está en la página 1de 76

CURSO DE

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.

1.1. Paradigma de la programaci n web o

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

1.1.1. Modelo cliente-servidor

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

Figura 1.1: Modo cliente-servidor

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.

1.1.2. Generaci n din mica de contenido o a


El servidor lee del disco duro un chero y se lo devuelve al navegador. Qu pasa si en vez de eso, hacemos que una e petici n ejecute un programa, y devolvemos la salida est ndar de ese programa al navegador? o a

Figura 1.2: Servidor con scripts

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.1. CD y documentaci n del curso o


En el CD que deberais recibir junto con esta documentaci n tendr is las herramientas necesarias para ejecutar pro o e gramas en PHP: servidores web con m dulos de PHP e int rpretes, as como aplicaciones de ejemplo. o 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

1.2.7. Un editor de texto


Y qu nos hace falta para programar? Un editor. Con un simple editor de texto basta. Mi recomendaci n personal es e o usar Kate en Linux, o un Ultraedit en Windows. pod is usar tambi n un textpad, emacs, vi, glimmer o vuestro preferido, e e o bien notepad (o incluso un ed) si no ten is nada mejor a mano. e Una de las razones por las que se subestima a PHP como lenguaje para profesionales es la falta de un entorno de programaci n completo. Esto es una falsa impresi n, ya que Zend (http://www.zend.com) vende y distribuye Zend o o Studio, que es un entorno de programaci n especco para PHP. Zend es la empresa que m s invierte en PHP (de hecho, o 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.1. Incrustando c digo o


Como PHP se dise o especcamente para programaci n web, se incrusta dentro de una p gina HTML, de la siguiente n o a manera: <html><body> <? echo Hola Mundo!; ?> </body></html> Todo lo que est fuera de los tags especiales <?? > lo mandar sin procesar al navegador. Todo lo que est dentro e a e se ejecutar , y el resultado de esa ejecuci n (lo que salga por salida est ndar) se devolver al navegador. a o a a Esta manera de incrustar c digo hace muy f cil a adir a una p gina HTML ya existente, peque as partes din micas. o a n a n a Hoy en da, y dado el nivel de implantaci n de PHP, es m s normal ver scripts que comienzan por <? y terminan por ? >, o a y no tienen nada fuera de estos tags. echo() es una funci n muy simple que unicamente pasa a salida est ndar lo que se le da como par metro. o a a (Realmente echo() no es una funci n, sino una construcci n del lenguaje. V ase c mo es la unica funci n que no o o e o o necesita que sus par metros se les pasen dentro de unos par ntesis.) a e Tambi n vemos que toda instrucci n de c digo se termina en punto y coma, como en C. e o o

1.3.2. Qu hora es? e


Veamos un peque o ejemplo mejor que el tpico Hola Mundo: n <html><body> <? echo date(H:i:S); ?> </body></html> En este caso, la funci n date() se encarga de calcular la hora actual en funci n de un formato que se le pasa como o o par metro, y echo() se encarga de enviar eso a salida est ndar (es decir, al navegador). a 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.1. Denici n din mica de variables o a


(d lar como en shell scripting) o Los creadores de PHP son vagos, muy vagos. Tan vagos que robaron muchos conceptos de otros lenguajes. Uno de ellos es el nombrado de las variables, que es igual que en bash scripting: Todos los nombres de variable empiezan por d lar ($), y no hace falta denir las variables con antelaci n: o o <? $el_sentido_de_la_vida = 42; echo $el_sentido_de_la_vida; ?> Al usar una variable por primera vez, esta se dene y se reserva espacio en memoria para ella. Adem s, el tipaje es a din mico. Esto quiere decir que puedo re-denir el tipo de una variable en tiempo de ejecuci n: a o <? $el_sentido_de_la_vida = 42; $el_sentido_de_la_vida = "<Cuarenta y Dos!; echo $el_sentido_de_la_vida; ?> Otro dato importante: Los nombres de variable son sensibles a may sculas y min sculas! Esto puede crear m s de u u a un quebradero de cabeza, y es un error muy com n. u <? $el_sentido_de_la_vida = 42; $El_Sentido_De_La_Vida = "Cuarenta y Dos"; echo $el_sentido_de_la_vida; echo <br>; echo $El_Sentido_De_La_Vida; ?> 5

CAPITULO 2. VARIABLES Y OPERADORES

2.2. Tipos b sicos a


2.2.1. Booleano
Una variable booleana es aquella que es verdadera o falsa. <? $de_verdad = true; $de_mentira = false; ?>

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

$hexadecimal = 0x45D0D0AF; ?>

2.2.3. Coma otante


N meros en coma otante de 64 bits, seg n formato est ndar de IEEE (salvo algunas arquitecturas que no lo soportan). u u a <? $pi = 3.1416;

// Notacin normal o // Notacin cientfica o

$cinco_millones_y_medio = 5.5e6; $siete_milesimas = 7e-3; ?>

// 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.

2.3. TIPOS COMPUESTOS

<? $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. Tipos compuestos


(Se ver n m s tarde) a a

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:

CAPITULO 2. VARIABLES Y OPERADORES

<? 5; // Esto "vale" 5.

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". ?>

2.4.2. Aritm ticos e


Los operadores aritm ticos son la suma (+), la resta (-), la multiplicaci n (*), la divisi n (/) y el m dulo ( %), as como e o o o el operador unario de negaci n (el smbolo de la resta, puesto antes de una expresi n). o o Hay que tener en cuenta que los operadores aritm ticos har n conversi n autom tica de tipos cuando sea necesario: e a o a <? $a = 5 + 1.2; // $a es un float y vale 6.2 $a = 3 / 2; // La divisin de enteros devuelve un float o

$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

$a .= " tartas de manzana"; // $a es la cadena "5 tartas de manzana".

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.

2.4.7. Post/pre incremento/decremento


Los operadores de post/pre incremento/decremento incrementan (o disminuyen) en una unidad el valor de una variable antes (pre) o despu s (post) de la evaluaci n de la expresi n: e o o <? $a = 5; $b = $a++; $a = 5; $b = ++$a; $a = 5; $b = $a--; $a = 5; $b = --$a; ?>

// 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

CAPITULO 2. VARIABLES Y OPERADORES

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.9. Bit a bit


No muy usados (algunos los consideran una cosa oscura), los operadores de bit a bit son similares a los de C: & - Yaplicado bit a bit a dos variables. |- Oaplicado bit a bit a dos varaibles. - xor bit a bit; no usar como si fuera el operador de potencia!! - negaci n de los bits de la variable que le sigue o $a $a $b - desplazamiento de los bits de $a a la derecha, tantas veces como indique $b. $b - desplazamiento de los bits de $a a la izquierda, tantas veces como indique $b.

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

2.5. MAGIA CON LAS VARIABLES

11

2.5. Magia con las variables


2.5.1. Referencias a variables
En PHP, al ser un lenguaje de alto nivel, no hay punteros. Sin embargo, existen las referencias a variables. Una referencia no se debe entender como un puntero, sino como un segundo nombre para una misma variable. En concreto, el sistema funciona de manera similar a un sistema de cheros tipo UNIX (a n record is algo de u a SSOO de segundo, verdad?). Un puntero tpico se podra comparar a un enlace simb lico: al consultarlo, me dice d nde o o est lo que busco. Una referencia es m s bien como un enlace duro (o enlace fsicoo hard link): al consultarlo, me a a da directamente lo que quiero, de manera totalmente transparente. Otra similaridad que encontramos es el borrado: un chero se elimina cuando tiene cero enlaces duros (hard links) apunt ndole; una variable se destruye cuando hay cero a referencias a la misma. (En realidad, una referencia es un alias en la tabla de smbolos interna del motor de PHP.) Para hacer referencias a variables, se utiliza el operador &, que convierte lo que le sigue en una referencia (puede ser una variable, o un valor de retorno de una funci n, o un objeto reci n creado con new): o e <? $a = 42; $b = & $a; // $b vale 42. De hecho, $a y $b apuntan a la misma // celda de memoria, en la que est el valor 42. a $b++; $c &= 58; ?> // tanto $a como $b pasan a valer 43. // Esto dar un error. a

2.5.2. Comprobando los tipos


Como hemos visto, todas las variables son multivariantes (tipado din mico), y si nos descuidamos y se opera como no a se debe, al nal no sabremos con qu estamos trabajando. Para conocer el tipo de una variable existe un grupo de funciones, e las funciones de variables, que permiten saber el tipo de una variable en un determinado momento. Algunas de ellas son is int(), is array() o is string(), y no necesitan demasiada explicaci n. Tambi n tenemos gettype, que devuelve una o e cadena que contiene el nombre del tipo de la variable que se le pasa.

2.5.3. Type casting


Y si quiero darle a una variable exactamente el tipo que quiero? Bueno, puedo hacer type casting sobre una expresi n, o precedi ndola del nombre del tipo entre par ntesis: e e <? $a = (string) 5; // $a es la cadena "5".

$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

2.5.4. Variables variables


Una variable variable es una variable cuyo nombre es variable. Repetid eso seguido unas diez veces (si pod is). Este e mecanismo es anterior a las referencias, y con el podemos crear variables con los nombres que queramos:

12

CAPITULO 2. VARIABLES Y OPERADORES

<? $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

CAPITULO 3. ESTRUCTURAS DE CONTROL

$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

CAPITULO 3. ESTRUCTURAS DE CONTROL

<? $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

4.1. Construyendo un array


4.1.1. array()
La funci n array() acepta un n mero variable de par metros, y siempre devuelve un array; con tantos elementos como o u a par metros se le pasen. Los arrays creados de esta manera empiezan en el elemento cero. a Para hacer referencia a un elemento del array en concreto, se pone el nombre del array, seguido de la clave que identica a uno de sus elementos entre corchetes: <? $a = array(); // $a es un array vaco

$a = array(hola); // $a tiene un solo elemento, $a[0], que vale "hola".

$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).

4.1.2. Expansi n de arrays o


Al ver las cadenas, se explic lo que es la expansi n de variables: al poner una variable dentro de una cadena delimitada o o por comillas dobles, se reemplaza ese nombre de variable por su valor. Para evitar ambig edades, hay que a adir llaves u n cuando se quieran escapar arrays: <? $a = array(hola , , echo "Hola $a[2]"; 17 mundo , !);

18

CAPITULO 4. ARRAYS

// Esto no va a funcionar bien. echo "Hola {$a[2]}"; // Esto sacar "Hola mundo" por salida estndar. a a ?>

4.1.3. [0] [1] [2]


No s lo podemos crear un array desde cero, sino poco a poco, deniendo elementos uno a uno, igual que si deni rao e mos variables una a una. <? $a[0] $a[1] $a[2] $a[3] ?> Por supuesto, no hay nada que nos diga que todos los elementos de un array tienen que ser del mismo tipo: <? $a[0] $a[1] $a[2] $a[3] ?> Y tambi n puedo destruir (indenir) un elemento de un array, igual que si indeniera una variable normal con unset() e : <? $a[0] $a[1] $a[2] $a[3] = = = = Hola mundo!; 3.1416; true; 42; = = = = Hola mundo!; 3.1416; true; 42; = = = = Hola; ; mundo; !;

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.

4.1. CONSTRUYENDO UN ARRAY

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

4.1.6. Arrays recursivas


Como no, un elemento de un array puede ser un array en s: <? $a[1] = Hola mundo!; $a[24] = 3.1416; $a[] = true; // Equivale a $a[25] = true; $a[] = array(); $a[] = array(1,2,3); $matriz[0] = array(1,2,3); $matriz[1][0] = 4; $matriz[1][1] = 5; $matriz[1][2] = 6; $matriz[][0] = 7; $matriz[][1] = 8; // Esto no va a funcionar bien... >porqu? e $matriz[][2] = 9; ?> Con un poco de ganas, y a base de arrays, se construyen arboles de datos sin la menor complicaci n: o <? $arbol[izqda][izqda][dcha] = 1234; $arbol[izqda][dcha][izqda][izqda] = 4567; $arbol[izqda][dcha][izqda][dcha] = 6543; ?>

4.1.7. print r() , var dump()


Antes se ha visto que si hacemos un echo() de un array, veremos un indescriptivo texto Arrayque no nos dice nada acerca del contenido. Hay varias maneras de ver los contenidos completos de un array; una de ellas es iterar sobre el array e imprimir todo; pero un m todo muy usado es el usar la funci n print r(). Esta funci n imprimir de manera legible los e o o a contenidos de cualquier variable; si se trata de un array, imprimir todos sus elementos. El rsignica que es una funci n a o recursiva: si hay un array dentro de un array, podremos ver todos sus contenidos. Hay que tener en cuenta que print r() no imprime < br/ > , sino saltos de lnea (\n ), as que hay que tener un poco de cuidado para formatear, o ver correctamente, el resultado de imprimir un array con print r(). <? $matriz[0] = array(1,2,3); $matriz[1][0] = 4; $matriz[1][1] = 5; $matriz[1][2] = 6; $matriz[][0] = 7; $matriz[][1] = 8; // Esto no va a funcionar bien... >porqu? e $matriz[][2] = 9; print_r($matriz); // No usar echo(print_r()); !! echo <pre>;

4.2. ITERACION SOBRE 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

4.2. Iteraci n sobre arrays o


Tenemos uns estructura de datos potente, podemos ver todos sus elementos... pero para poder trabajar con todos ellos necesitamos iterar sobre el array...

4.2.1. Iteraci n sobre arrays: el malo o


Lo que muchos noveles programadores hacen es pensar que todo array es num rico y compacto, con las claves e consecutivas, empezando desde cero. Despu s cuentan los elementos que tiene el array con count() (funci n que devuelve e o el n mero de elementos presentes en un array), y rematarlo todo con un for(;;) : u <? $a[1] = Hola mundo!; $a[24] = 3.1416; $a[] = true; // Equivale a $a[25] = true; $a[] = array(); $a[] = array(1,2,3); $c = count($a); for ($i=0; $i<= $c; $i++) { echo $a[$i]; } ?>

4.2.2. Iteraci n sobre arrays: el bueno foreach, foreach con referencia o


Para hacer bien las cosas, PHP nos ofrece una construccion del lenguaje para iterar sobre un array: foreach(): <? $a[1] = Hola mundo!; $a[24] = 3.1416; $a[] = true; // Equivale a $a[25] = true; $a[] = array(); $a[] = array(1,2,3); foreach($a as $elemento) { echo $elemento; } ?>

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 } ?>

4.2.3. Iteraci n sobre arrays: el feo o


En tiempos de PHP3 no exista foreach(), as que se usaba un m todo que ha quedado relegado a aplicaciones viejas e y museos de c digo: o <? $personas[12345678] $personas[20300400] $personas[45268732] $personas[21459870] = = = = Pepito; Fulanito; Menganito; Zutanito;

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

4.3. MAGIA CON ARRAYS

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); ?>

4.3. Magia con arrays


4.3.1. array push(), array pop(), array shift(), array unshift()
Necesitas una pila o una cola? No hay problema! array push() - Como [ ], a ade un elemento al nal del array (aunque puede a adir varios a la vez). n n array pop() - Elimina el ultimo elemento de un array y devuelve su valor. array shift() - Elimina el primer elemento en un array (normalmente el que est en la posici n cero), y desplaza e o (renumera) el resto de elementos. array unshift - A ade un elemento (o varios) al principio de un array, y desplaza (renumera) el resto. n Para crear una pila, usaremos array push() y array pop(). Para crear una cola se puede usar array push() y array shift().

4.3.2. explode(), implode()


Se pueden convertir arrays a cadenas y viceversa, de manera muy c moda en muchas ocasiones, con explode() e o implide(). explode() dividir una cadena en varios trozos (un array de cadenas), haciendo la divisi n por un separador que a o le especiquemos. implode() har lo contrario, uniendotodos los elementos de un array en una misma cadena: a <? $frase = "En un lugar de la mancha"; $palabras = explode( ,$frase); $frase = implode (-,$palabras); echo $frase; // En-un-lugar-de-la-mancha ?>

24

CAPITULO 4. ARRAYS

4.3.3. sort(), asort(), ksort(), natsort()


Antes hemos visto que un array es un map ordenado. Hay que tener en cuenta que el orden de un array depende de c mo se dena. Adem s, los operadores de igualdad (==) e identidad (===) funcionan de manera distinta, al tener en o a cuenta (o no) el orden de un array: <? $a[1] = Hola mundo!; $a[pi] = 3.1416; $b[pi] = 3.1416; $b[1] = Hola mundo!; $c = ($a == $b); $d = ($a === $b); ?> Aprovechando esto, podemos aplicar funciones de ordenaci n sobre un array. Las b sicas son: o a sort() - Ordena los valores y reasigna las claves num ricamente. e asort() - Ordena los valores pero mantiene la asociatividad clave/valor. ksort() - Ordena por claves. <? $personas[12345678] $personas[20300400] $personas[45268732] $personas[21459870] = = = = Pepito; Fulanito; Menganito; Zutanito; // $c es verdadero // $d es falso

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):

4.3. MAGIA CON ARRAYS

25

<? $a[1] = Hola mundo!; $a[pi] = 3.1416; $texto = serialize($a); $b = unserialize($texto); ?>

4.3.5. Y otras cosas raras


Otras cosas raras que podemos hacer incluyen construir arrays a partir de un array de claves y otro de valores, calcular la diferencia, uni n o intersecci n; aplicar una funci n a todos los elementos, recortar trozos, barajararrays, extraer o o o elementos al azar, aplanar, y un largo etc tera. M s informaci n en el apartado de arrays del manual ocial de PHP. e a o

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.5. $ COOKIE, $ SESSION


$ GET y $ POST no son las unicas maneras en las que un script puede recoger datos. Los datos pasados al servidor mediante cookies, o los datos almacenados en una sesi n, son elementos dentro de las arrays superglobales $ COOKIE y o $ SESSION, respectivamente. Ambos m todos se ver n m s adelante. e a 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

6.1. The C way: fopen(), fread(), fwrite(), fclose()


PHP no es muy original, y soporta acceso a cheros de manera an loga a como lo hacen lenguajes como C: mediante a un descriptor de chero que se abren con fopen(), leyendo o escribiendo datos a trav s de ese descriptor con fread() y e fwrite(), y cerrando el descriptor con fclose(). <? $fd = fopen(/tmp/qwertyuiop,w); // A fopen() se le pasa nombre de fichero y modo (en este caso escritura) fwrite($fd,Hola mundo!); fclose($fd); $fd2 = fopen(/tmp/qwertyuiop,r); // Abrimos el mismo fichero, pero ahora para lectura $texto = fread($fd2 , filesize(/tmp/qwertyuiop)); // fread() necesita descriptor de fichero y longitud a leer fclose($fd2); echo $texto; ?> Otras funciones para trabajar con descriptorres de cheros, como fseek(), fgetc(), fputs(), etc tera, tambi n est n e e a disponibles y funcionan de la misma manera que sus an logos en C. a Un punto que hay que tener en cuenta es que PHP cierra autom ticamente todos los recursos abiertos cuando naliza a la ejecuci n de un programa, as que podemos tranquilamente olvidarnos de cerrar los cheros (a no ser que tengamos o concurrencia u otras circunstancias de por medio que nos obliguen a cerrarlo). Para el tratamiento espor dico de datos a esto es una pr ctica aceptable; para el tratamiento intensivo de datos es mejor usar una BBDD. a

6.2. The PHP way


El acceso a cheros de forma tradicionalno es recomendable cuando estamos en un lenguaje de scripting con una curva de aprendizaje muy baja. Por esto, PHP tiene maneras m s f ciles y c modas de acceder a cheros. a a o 28

6.3. INCLUDE(), REQUIRE()

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.

6.2.2. le get contents(), le put contents()


Muchas veces, lo unico que queremos de un chero es leerlo o escribirlo completamente, para lo cual no hace falta usar el m todo fopen-fwrite-fread. Con le get contents() obtendremos en una variable el contenido completo de un chero, e mientras que con le put contents() volcaremos una variable a chero: <? file_put_contents(/tmp/qwertyuiop,"Hola\nMundo!\n"); // Nombre de fichero, y lo que queremos escribir en l. e $cadena = file_get_contents(/tmp/qwertyuiop); $array = file(/tmp/qwertyuiop); echo $array[1]; echo $array[0]; // Mundo! // Hola

echo $cadena; // Hola Mundo! ?>

6.2.3. fpassthru(), le exists(), nl2br(), is dir(), basename(), etc


Otra funcionalidad interesante que encontramos en el apartado de funciones de manejo de cheros de PHP son: fpassthru() : se le pasa un descriptor de chero, y saca por salida est ndar sus contenidos. Es muy util cuando queremos a pasar a un navegador los contenidos de un chero grande, pero no queremos cargarlo en memoria (en una variable). le exists() : devuelve verdadero si existe un chero con el nombre que se le pasa, falso en caso contrario. Muy util para evitar errores al intentar abrir un chero que no existe. nl2br() : Una funci n de tratamiento de cadenas, que convierte saltos de lnea (\n) a saltos de lnea de HTML (< br >). o Util cuando se quiere mostrar en un navegador el contenido de un chero de texto. V ase tambi n htmlespeciale e chars(). is dir(), is le(), is link() y otras funciones sirven para comprobar si un chero es un chero, o un directorio, o un enlace simb lico, etc. o basename() devuelve el nombre del chero, quitando cualquier directorio que pueda contener. Es decir, quita todo lo que haya antes de la ultima barra. Util cuando nos pasan un nombre de chero desde fuera y queremos asegurarnos de que nuestro programa s lo accede a cheros dentro de un determinado directorio. o

6.3. include(), require()


A la hora de modularizar el c digo, lo normal es repartirlo en varios cheros, y hacer que el programa principal use o ese c digo. En lenguajes compilados, esto se consigue con directivas del preprocesador. En lenguajes interpretados como o PHP, esto se consigue en tiempo de ejecuci n. o Con include() hacemos que se pase el ujo de la ejecuci n a otro chero, conservando todo el estado (variables, o funciones denidas, etc). El efecto nal es equivalente a coger los contenidos del chero que se incluye, y ponerlos en lugar de la lnea que hace el include(). Sin embargo, el chero includo tiene que empezar y terminar por <? y ? > si queremos que sus contenidos se ejecuten y no se saquen por salida est ndar. a

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

6.4. Ficheros especiales


Normalmente, trataremos cheros que est n en el disco duro de la m quina en la que estamos programando. Sin a a embargo, tambi n podemos trabajar con cheros remotos, o con cheros especiales que no tienen soporte fsico. e

6.4.1. Ficheros remotos


PHP soporta wrapperspara acceso a chero. Esto quiere decir podemos abrir un chero cuyo nombre empiece por http:// , o trabajar con un chero que est en un servidor FTP (ftp://...). Por ejemplo: e <? fpassthru(fopen(http://acm.asoc.fi.upm.es)); ?> Actualmente, los wrappers que se pueden utilizar son: http:// y https:// - S lo para leer p ginas web. o a ftp:// y ftps:// - Para leer/escribir cheros desde/a un servidor FTP o FTPS. php:// - Para leer de entrada est ndar (php://stdin), o escribir a salida est ndar o de error (php://stdout, php://stderr). a a Se usan en shell scripting, puesto que son pr cticamente in tiles para programaci n web. a u o zlib:, compress.zlib:// y compress.bzip2:// - Para acceder a los contenidos de un chero comprimido de manera transparente. ssh2.*:// - Para diversas funciones (ejecuci n de comandos, redirecci n de puertos, transferencia de cheros) a o o trav s de SSH2. Este wrapper no est activado por defecto. e a ogg:// - Para acceder de manera transparente a un stream de sonido comprimido en formato Ogg Vorbis. Este warpper no est activado por defecto. a

6.4.2. pipes, fos


Un pipe es una tubera que conecta un descriptor de chero abierto en un programa con otro descriptor abierto en otro programa. Con las funciones de pipes de PHP podemos ejecutar otro programa, y recibir su salida est ndar o enviar a a su entrada est ndar datos como si lo hici ramos a trav s de un descriptor de chero. Las funciones popen() y pclose() a e e permiten un acceso sencillo a esta funcionalidad, y vienen descritas en el apartado de funciones de manejo de cheros en el manual de PHP. Si queremos un control m s no de ejecuci n de programas externos, podemos usar la familia a o proc * (proc open(), proc get status(), proc close(), etc) o las funciones de ejecuci n de programas (Program Execution o Functions ), que tienen su propio apartado en el manual de PHP. Un fo funciona de manera similar a un pipe, s lo que tiene un nombre en el sistema de cheros del ordenador sobre o el que trabajamos, y pueden ser accedidos por programas independientes (no uno que llame o haga un fork al otro). El trabajo con FIFOs es id ntico al trabajo con cheros tradicionales, excepto que un FIFO se crea con posix mkfo(), y se e destruye cuando se deja de usar (tanto por el proceso que lee de el como el proceso que escribe a el). Adem s de esto, a PHP cuenta con diversas funciones directamente relativas al est ndar POSIX. a

6.4. FICHEROS ESPECIALES

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.1.1. Reusabilidad de c digo o


Una de las razones b sicas por las que usar funciones en nuestro c digo es para reutilizar c digo. Si en nuestra a o o aplicaci n vamos a hacer lo mismo una y otra vez, no tenemos porqu escribirlo en el c digo una y otra vez. El reutilizar o e o c digo conlleva de por s otras ventajas, como son la reducci n del n mero de lneas de c digo y un mantenimiento m s o o u o a f cil. a

7.1.2. function foo()


La manera m s b sica de declarar una funci n es la siguiente: a a o <? function foo() { echo Hola mundo!; } foo(); ?> Aqu se observan varias cosas: Las funciones se declaran al estilo C, con la palabra reservada function, seguida de los par metros (en este caso, ninguno) y el c digo que la compone entre llaves. a o Las funciones se declaran en ujo de ejecuci n normal de PHP, al no haber una funci n main . Esto nos lleva al o o curioso concepto de la denici n condicional de funciones, que no podemos encontrar en lenguajes no interpretados: o <? if (date(Y) == 2005) // >Estamos en el ao 2005? n { function foo() { echo Hola 2005!; } } else 32

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.

7.2.2. function foo($bar) { return($foobar); }


Las funciones que devuelvan un valor deben hacerlo sencillamente con el uso de la palabra reservada return, que terminar la ejecuci n de la funci n y devolver la ejecuci n al programa llamante. No hace falta declarar el tipo de a o o a o retorno, ya que sabemos que ser multivariante... a <? function suma_uno( $numero ) { return $numero + 1; } echo suma_uno(5); ?>

7.2.3. Argumentos predenidos


Una funci n puede tener un n mero de argumentos predenidos. Es decir, argumentos que no es necesario que se le o u pasen a la funci n al ser llamados, y cuyos valores tomar de la denici n de la funci n si es necesario: o a o o

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.2.4. Argumentos variables: func get args()


Tambi n podemos declarar funciones que acepten cualquier n mero de par metros. Para acceder a todos los par mee u a a tros que no han sido denidos en la declaraci n de la funci n, usaremos func num args() y func get args(): o o <? function concatena () { $numargs = func_num_args(); if ($numargs ==0) return La funcin necesita al menos un parmetro.; o a $arg_list = func_get_args(); return implode($arg_list); } echo concatena(); echo concatena(Uno,Dos); echo concatena(Adios!); ?>

7.2.5. Referencias: function foo(&amp;$bar)


El paso por referencia sirve para modicar el contenido de las variables que se pasan como argumento, sin tener que declararlas como globales. Se consigue poniendo un & antes del nombre de la variable en la denici n de la funci n: o o <? function suma_uno ( & $a) { $a++; } $a = 5; suma_uno($a); echo $a; ?>

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.3.2. Variables globales, scope global


Cualquier variable que se dena (use) fuera de cualquier funci n, en el cuerpo principal de un chero PHP, se dir que o a est en el scope global, son todas variables globales. Estas variables pueden ser accedidas desde una funci n declar ndoa o a las como globales: <? function imprime_a () { global $a; echo $a; } $a = 5; imprime_a(); ?> Por lo general, es una mala idea acceder a variables globales dentro de una funci n. Siempre ser mucho m s limpio o a a usar paso por referencia (o clases est ticas que se ver n m s adelante) para algoritmos complejos que requieran un punto a a a jo donde acceder a algunos datos, o usar alguna de las superglobales si es necesario. Otra manera de acceder a las variables globales es usando la superglobal $GLOBALS en vez de declarar variables individuales como globales: <? function imprime_a () { echo $GLOBALS[a]; } $a = 5; imprime_a(); ?>

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

7.5. Tic tac!


PHP no es un lenguaje concurrente, pero se puede simular concurrencia hasta cierto punto. Mediante register tick function() o y unregister tick function() podemos hacer que una funci n se ejecute a intervalos regulares (por ejemplo, cada 5 instrucciones) durante la ejecuci n normal de nuestro programa. Un uso de esta funcionalidad es ir comprobando peri dicamente o o el uso de memoria de un script y tomar nota de ello en un log.

7.6. Cierra la puerta al salir


A veces es recomendable ejecutar c digo aunque hayamos cerrado la salida est ndar (es decir, una vez que el naveo a gador web ha recibido todos los resultados). Esto se puede hacer con register shutdown function(), que se encargar de a ejecutar las funciones que deseemos despu s de nalizar la ejecuci n normal del script. Todo c digo que sea ejecutado e o o de esta manera no podr acceder a salida est ndar (puesto que ya se ha cerrado), lo cual puede dicultar la depuraci n. a a o Adem s, esta t cnica puede dar problemas en ciertos servidores web. a e

Captulo 8

Programaci n Orientada a Objetos o


La Programaci n Orientada a Objetos (o Object Oriented Programming , OOP), sin embargo, es capaz de ayudarnos o a producir c digo muy legible, extensible y, gracias a la potencia de PHP5, de manera muy creativa. o

8.1. Objetos por todos lados


8.1.1. M todos y atributos e
Un objeto se puede denir como una entidad que guarda un estado propio, sobre la que se pueden efectuar una serie de operaciones. El estado propio se consigue gracias a las propiedades, variables dentro de un objeto, y los m todos, e funciones dentro del objeto. Lo primero es denir la entidad de manera abstracta; es decir, la clase. Una vez hecho esto, podremos hacer objetos basados en esa clase, con new. Para acceder a los m todos y propiedades de un objeto se usa una echa ( ). Si queremos acceder a las propiedades e o m todos de un objeto dentro de ese mismo objeto, se usa la variable reservada $this. e <? class alumno { // Propiedades (variables) public $nombre; public $dni; // Mtodos (funciones) e 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; $pepe->nombre = Pepito Prez; e $pepe->dni = 123456789; $pepe->aprobar_redes(); ?> No es una buena idea darle a una clase el nombre de una palabra reservada (class while). 37

38

CAPITULO 8. PROGRAMACION ORIENTADA A OBJETOS

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);

8.1. OBJETOS POR TODOS LADOS

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

CAPITULO 8. PROGRAMACION ORIENTADA A OBJETOS

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

8.1.5. Expansi n de propiedades o


Ya vimos c mo una variable sencilla se expande autom ticamente si se introduce dentro de una cadena delimitada con o a comillas dobles, y c mo se pueden expander elementos de arrays poni ndolos entre llaves. De igual manera, poni ndolas o e e entre llaves, las propiedades de un objeto se pueden expandir tambi n: e <? class alumno { 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 } } $pepe = new alumno; $pepe->nombre = Pepito Prez; e $pepe->dni = 123456789; $pepe->aprobar_redes(); echo "{$pepe->dni}";

8.2. MAGIA CON

41

?> Si se omiten las llaves, nos encontraremos con un poco descriptivo Objecten vez de la propiedad que queremos.

8.2. Magia con


a En PHP, todas las funciones que empiezan con (dos guiones bajos) son cosas m gicas, y debe evitarse, en la medida de lo posible, que un programador ponga a sus propias funciones nombres que empiecen por , puesto que en versiones posteriores del lenguaje podran haber m s funciones m gicas, y tendramos problemas. a a

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

CAPITULO 8. PROGRAMACION ORIENTADA A OBJETOS

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.

toString() - s lo con echo() !! o

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

8.2. MAGIA CON

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

CAPITULO 8. PROGRAMACION ORIENTADA A OBJETOS

// 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

8.3. Patrones de diseno


Un patr n de dise o es una soluci n expresada normalmente en forma de una serie de clases programadas de una detero n o minada manera, que resuelven una serie de problemas con los que nos podemos encontrar muy a menudo. A continuaci n o veremos un par de situaciones en las que podemos aplicar patrones de dise o para tener una soluci n elegante. n o

8.3. PATRONES DE DISENO

45

8.3.1. Constantes y cosas est ticas a


Una clase puede tener propiedades constantes o est ticas, y funciones est ticas. Una constante es precisamente eso, a a una propiedad cuyo valor es siempre el mismo en el entorno de una clase, y no puede cambiarse. Una propiedad o m todo e est tico es el mismo para todo el entorno de una clase, pero puede modicarse (propiedad) o llamarse (m todo). a e

8.3.2. Paamayim Nekudotayim


Para acceder al entorno de una clase (y, por tanto, a los m todos o propiedades est ticos o constantes), se usa el e a Paamayim Nekudotayim, m s conocido como dos puntos dos puntoso ::. El porqu de este nombre extra o se debe a e n a que, por un lado, muchos de los creadores de PHP3 provienen de oriente medio y, por otro, son tan cachondos que, en el motor de PHP, le pusieron a ::la traducci n en hebreo de double colon(doble dos puntos). Otro nombre para este o operador es el Scope Resolution Operatoro Operador de Resoluci n de ambito/entorno/alcance. o Usando :: se accede al entorno de una clase. Hay que tener en cuenta que hay dos clases especiales, que son selfy parent. selfse reere al entorno de la clase en la que estoy (cuando se ejecuta un m todo de una clase, obviamente). e parentse reere al entorno de la clase padre, en el caso de que est en un m todo de una clase que ha heredado ed otra e e (como se vi antes). o

8.3.3. Solteros de oro


Un patr n muy com n es el soltero(singleton). Se basa en que el programador no puede hacer instancias de una o u clase, declarando el constructor como privado (si acaso, se puede instanciar un objeto, pero s lo dentro de un m todo o e est tico). Algunos autores consideran que un soltero es un soltero s lo si hay una instancia de s mismo en una propiedad a o est tica. a Los solteros se usan cuando no se necesitan instancias, o cuando se necesita un acceso global sencillo desde cualquier parte (a trav s del ::). Pueden usarse para crear manejadores de bases de datos o conguraciones globales de f cil acceso, e a entre otros usos. Por ejemplo, podemos crear una clase que nos permita acceder a cheros mediante m todos est ticos: e a <? class ficheros_configuracion { private constant $directorio = /etc/; private function __construct() {} static function leer($fichero) { $fichero = basename($fichero); if (file_exists($f = self::directorio . $fichero) && is_readable($f)) return file_get_contents($f); else return false; } static function guardar($fichero,$contenido) { $fichero = basename($fichero); // Por seguridad if (file_exists($f = self::directorio . $fichero) && is_writable($f)) return file_put_contents($f); else return false; } }

ficheros_configuracion::guardar( hosts, ficheros_configuracion::leer(hosts) . "\n127.0.0.1 www.loquesea.com\n" )

46

CAPITULO 8. PROGRAMACION ORIENTADA A OBJETOS

// Aade una entrada al fichero /etc/hosts. n ?>

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; } } }

8.3. PATRONES DE DISENO

47

$mi_coche = concesionario::compra_un_coche_caro(10000); echo $mi_coche->conducir(); ?>

8.3.5. Clases abstractas


En algunos casos (como en el ejemplo de los coches), es mejor evitar que un programador instancie dierta clase. Para ello, podemos denir una clase como abstracta. Dicha clase no se podr instanciar, pero s heredar. Si adem s se declara a a alguno de los m todos de esa clase como abstracto, cualquier clase que herede de ella la tiene que implementar de manera e no abstracta, o convertirse a su vez en una clase abstracta. En otras palabras, cualquier clase que contenga un m todo e abstracto debe ser abstracta. La manera de convertir una clase abstracta en una no abstracta es heredarla y reimplementar todos los m todos abstractos que pudiera tener. e <? abstract class coche { public function conducir() { return Estoy conduciendo un . get_class($this); } } class coche_fiat extends coche { public static $precio = 8900; } ?>

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

CAPITULO 8. PROGRAMACION ORIENTADA A OBJETOS

? $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); ?>

8.3.7. Es mi ultima palabra!


Un m todo declarado como nal(nam function loquesea()) no puede reimplementarse en clases que hereden de e esta. Una clase denida como nal (nal class loquesea) no puede heredarse.

8.3.8. Type hinting (sobrecarga de funciones)


Aunque PHP5 tiene un tipado d bil y din mico, se pueden sobrecargar funciones y m todos, haciendo que una funci n e a e o est denida si y s lo si se los par metros que se le pasan son de una determinada clase. No se pueden sobrecargar e o a funciones para distinguir entre tipos simples, como enteros o cadenas. <? class coche_fiat {} class coche_citroen {} class taller_citroen { static function arreglar(coche_citroen $coche) { echo "Vale, vuelve dentro de una semana y lo tienes listo<br/>"; } } $mi_coche = new coche_fiat;

8.3. PATRONES DE DISENO

49

taller_citroen::arreglar($mi_coche); ?>

Aqu, al intentar arreglar algo que el taller no puede, se devolver un error. a

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

Quien quiera comprar una licencia de Oracle 10 debe dirigirse a http://www.oracle.com/

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.5. Otros competidores


Otras opciones menos populares son: MS SQL Todos adoramos a microsoft y elegiramos su tecnologa (si no fuera porque tenemos m s opciones, claro est ). a a dBase/DB2 Fueron sistemas de BBDD muy usados, pero hace 20 a os. Aun es posible verlos en aplicaciones muy n antiguas. Mini SQL (mSQL) Un sistema ligero pero poco popular. http://www.hughes.com.au/products/msql/ Ovrimos SQL server otro sistema poco conocido.

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

9.3.2. Funciones de SQLite


En SQLite usaremos: sqlite open() para abrir una BDD existente (o crear una vaca), siempre en un chero. sqlite query() para ejecutar queries SQL. sqlite fetch array() y sqlite num rows() para saber el resultado de una query.. sqlite last error() para control de errores. sqlite close() para cerrar la BDD.

52

CAPITULO 9. BBDD

9.3.3. Conexiones persistentes


Recordatorio: el ujo de ejecuci n de una aplicaci n web (v ase Paradigma de la programaci n web) no es contnuo, o o e o sino discreto. A cada p gina que un visitante acceda con su navegador web (o m todo similar), se ejecutar nuestro a e a programa en PHP. Cuando nuestra aplicaci n accede a una BBDD, normalmente se abre una conexi n a la BBDD al o o principio del programa y se cierra la conexi n al nal del programa. o Obviamente, esto no es muy eciente, sobre todo cuando vamos a tener muchas visitas en un tiempo relativamente corto. Para aliviar esto, se usan las conexiones persistentes a BBDD. La diferencia entre abrir una conexi n normal o (sqlite open) y una persistente (sqlite popen) es que la conexi n persistente, al cerrarse, queda abierta en el motor de PHP, o con lo que se acelera sobremanera la siguiente conexi n a la BBDD. La conexi n se cierra a nivel de programa, pero o o queda abierta a nivel de int rprete, lista para posteriores conexiones. e Por desgracia, el dejar abierta la conexi n de BBDD s lo funciona si nuestro int rprete de PHP5 es un m dulo de o o e o apache; si ejecutamos PHP como cgi o desde una consola, no tenemos un proceso a m s bajo nivel capaz de mantener a abierta una conexi n aunque el programa la haya cerrado. o

9.4. Cu ndo? a
Ya basta de teora; empecemos ahora mismo a ver alg n ejemplo. u

9.4.1. Vendiendo pan, primera


Ilustraremos el uso de una BBDD sencilla con una peque a aplicaci n para una supuesta panadera que quiere dar a n o conocer los productos que vende a trav s de su p gina web. Esta aplicaci n consta de las siguientes p ginas: e a o a crear bdd.php Crea las estructuras necesarias para almacenar datos en la BBDD (en este caso, una unica tabla). S lo ha o de ejecutarse una vez, cuando la BBDD todava no ha sido creada. index.php La unica p gina que ver n los visitantes. En ella se muestra un listado de los productos que est n a la venta. a a a admin.php Desde aqu se accede al alta y baja de productos. Esta p gina no modica nada, s lo es un punto de entrada a o a las p ginas que s modican los datos. a alta.php Esta p gina recibe datos desde admin.php, a trav s de un formulario, y procesa el alta de un producto. a e baja.php Esta p gina recibe datos desde admin.php, a trav s de un enlace, y procesa la baja de un producto. a e (El c digo se incluye aparte, al ser de tama o considerable) o n En esta aplicaci n sencilla hay que tener muy claro el ujo de datos entre las p ginas que componen el area de o a administraci n. Mediante admin.php, un empleado de la panadera puede preparar y componer una petici n a la BBDD, o o que se procesar en otra p gina (alta o baja). El proceso es siempre as: a a 1. El servidor le da al usuario una p gina donde, mediante un formulario o una serie de enlaces, se le da la opci n de a o introducir datos para despu s integrarlos en la BBDD o obrar seg n ellos. e u 2. El usuario rellena y enva el formulario, o pulsa un enlace, enviando datos de nuevo al servidor. 3. El sevidor recoge los datos que le ha enviado el usuario, los analiza y valida, y obra en consecuencia (modicando, si cabe, la BBDD).

9.4.2. Vendiendo pan, segunda


Ahora vamos a mejorar la aplicaci n que ya tenamos. A adiremos una nueva columna a la tabla (descripci n), y o n o haremos una peque a capa de abstracci n de BBDD para no tener que arrastrar la conexi n a la BBDD ($bd) durante la n o o ejecuci n. Tambi n a adiremos otra p gina, para que los visitantes puedan ver la descripci n de un producto. o e n a o En el c digo (que est aparte de la documentaci n) veremos c mo se puede usar una clase con m todos est ticos para o a o o e a hacer una abstracci n correcta y accesible desde cualquier punto del c digo. o o

9.5. QUIEN?

53

9.4.3. Con esto basta


Podramos ampliar los ejemplos hasta tener un sistema de gesti n de panaderas completo, incluyendo control de o n minas y facturaci n, con venta a domicilio y pagos con tarjeta de cr dito, pero ese no es el caso. o o e Los ejemplos est n ah para ver c mo funciona una aplicaci n web con base de datos muy sencilla. Para probar a o o los ejemplos, unicamente hace falta copiarlos en un subdirectorio del docroot de nuestro servidor web (normalmente /var/www si usamos linux y apache), y dar permisos para que PHP (m s bien, las libreras de SQLite) pueda escribir el a chero de BBDD en el subdirectorio de la aplicaci n. o

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.1. Inyecci n de SQL o


Una inyecci n de c digo se basa en que la aplicaci n no comprueba correctamente los datos de entrada, y por tanto o o o es posible introducir sentencias SQL enteras a trav s de los datos que se le pasan al servidor web. e Por ejemplo, consideremos el siguiente c digo presente en la aplicaci n de ejemplo: o o <? bdd::query("select * from productos where id={$_GET[id]}"); ?> Esto es una sola sentecia SQL, donde se expande una variable que llega desde el navegador, verdad? o quiz s es a algo m s que eso? a Supongamos que la variable le pasamos una variable al programa usando una URL del estilo de "?id=0;delete * from productos; select * from productos where id="; esto har que, en nuestro c digo se exa o panda este valor dentro de la cadena y se ejecute algo como: <? // Normalmente bdd::query("select * from productos where id=0"); // Con inyeccin de SQL o bdd::query("select * from productos where id=0;delete * from productos; select * from productos where id="); ?> Con lo que nuestra sentencia SQL se convierte en tres, borrando todos los datos. (En realidad, la tercera sencencia est s lo para que la segunda comilla simple, que est despu s de la variable que se a o a e expande, no d error al ser parseada por el motor de SQL.) e C mo protegerse ante esto? F cil: comprobando los datos de entrada. Cualquier dato que est destinado a entrar en o a e una query SQL tiene que ser pasado a num rico (mediante un type casting explcito, si el dato esperado es num rico) o e e bien hay que escapar todos los caracteres maliciososque pueda tener (mediante funciones como sqlite escape string(), si el dato es una cadena de texto).

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.1.2. Leche y galletas


All por los principios de los 90, se di una primera soluci n al problema de arrastrar informaci n entre distintas a o o o p ginas de una misma aplicaci n web: las Cookies. a o Una cookie es un par nombre-valor que conforma una variable, y que el navegador enva a cada p gina que visita en a el servidor que le envi la cookie en primer lugar. Una cookie es la manera de decir cada vez que me visites una p gina, o a envame esta informaci n para que yo sepa qui n eres. o e En PHP, para mandar una cookie al navegador, se utiliza la funci n setcookie() (o setrawcookie() en raras ocasiones). o Y para ver si el cliente nos manda datos de una cookie se mira la variable superglobal $ COOKIE, como veremos en el ejemplo: <? if (!$_COOKIE[primera_visita]) $texto = Vaya vaya, veo que es tu primera visita; else $texto = Bienvenido de nuevo; setcookie(primera_visita,1); // Esto quiere decir "cada vez que me visites, mndame una variable a // primera_visita con valor 1". // Cuando el navegador visite otra pgina dentro del servidor, le enviar a a // esta informacin, que un programa en HPP recoger a travs de la variable o a e // superglobal $_COOKIE. echo $texto; ?> Es importante enviar las cookies antes de hacer ning n echo(), y antes tambi n de cualquier texto fuera de <? ? >. u e Esto quiere decir que si nuestro programa (o alguno de los scripts de los que haga un include()) tiene una lnea o un 54

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

CAPITULO 10. AUTENTIFICACION Y SESIONES

{ $_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 } ?> 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>"; } ?>

10.2.3. Almacenando sesiones


Comentar que por defecto se almacenan autom ticamente en un chero de texto plano. a

58

CAPITULO 10. AUTENTIFICACION Y SESIONES

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

10.3. 403 Forbidden


10.3.1. Cabeceras HTTP
Comentar otras aplicaciones: cacheado, otros tipos de contenido. En la d cada de los 90, adem s de a adir cookies al protocolo HTTP, se dise o la manera de autenticar a un usuario e a n n usando unicamente HTTP, a nivel de servidor web. La manera de hacerlo es que el servidor tome pares usuario/password de alg n sitio (en apache, de la conguraci n o de cheros .htaccess), y devuelva una cabecera HTTP para que el navegau o dor pida usuario/password y vuelva a hacer la petici n. En concreto, podramos tener el siguiente di logo entre navegador o a y servidor web si visitamos www.dondesea.org/loquesea.php. En primer lugar, el navegador dice: 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 Aqu el navegador pide la p gina, y adem s dice qui n es, y qu cosas puede admitir como respuesta (texto plano en a a e e distintos formatos e idiomas preferentemente, y con qu compresi n transparente para el usuario, por ejemplo). e o En caso de que http://www.dondesea.org/loquesea.php necesite autenticaci n HTTP, una respuesta tpica podra ser: o HTTP/1.1 401 Authorization Required Date: Tue, 01 Mar 2005 23:01:14 GMT Server: Apache/2.0.52 (Gentoo/Linux) WWW-Authenticate: Basic realm="Aplicacin de lo que sea" o Content-Length: 492 Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Content-Type: text/html; charset=iso-8859-1

10.3. 403 FORBIDDEN

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

CAPITULO 10. AUTENTIFICACION Y SESIONES

Hola! Bienvenido a www.dondesea.org/loquesea.php ! </body> </html>

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.

10.3. 403 FORBIDDEN

61

10.3.2. Programando con cabeza


Qu m s cosas podemos hacer con cabeceras HTTP? Entre las m s comunes se incluyen: por una parte, el modicar e a a la fecha de creaci n y enviar directivas no-cache para evitar (en la medida de lo posible) que un navegador mantenga o una copia de la p gina cacheada. Por otra, mandar una cabecera Location:para hacer que el navegador se redirija a autoaticamente a otra p gina. Y por otra, mandar una cabecera Content-type:si no queremos devolver una p gina web a a (html o xhtml) sino una imagen, un pdf, u otro tipo de documento. Hay que tener en cuenta que cuando se manda una cabecera, el resto de ellas puede modicarse para adaptarse a ella. Por ejemplo, sin inclumos una cabecera Location:, el servidor no devolver un 200 OKsino un 302 Found. a Si mandamos una cabecera Content-type:, no se mandar la cabecera Content-type:habitual, ni se mandar n dos a a cabeceras de este tipo. Sobre el evitar que el navegador mantenga en cach una p gina, hay que decir que cada navegador (sobre todo IE) tiene e a sus manas y su manera de implementar esa funcionalidad (o incluso evitarla). Con respecto a la cabecera Location:, hay que decir que es una manera est ndar (y mucho, mucho m s limpia que usar <meta>s de HTML o Javascript) de que a a los bots y crawlers se redirijan solos (v anse las funciones de CURL y la opci n CURLOPT FOLLOWLOCATION). e o Pero c mo es que mediante PHP voy a devolver algo que no sea HTML? En dos casos: cuando genere din micamente o a una imagen (v anse las funciones de tratamiento de im genes mediante el uso de la librera gd), un pdf, un ps, un swf e a (ash) o un chero comprimido mediante las funciones a tal efecto; o cuando queremos devolver los contenidos de un chero (el tpico download.php?le=loquesea.zip). Un breve ejemplo para ilustrar c mo devolver cheros sera el siguiente: o <? // Supongamos download.php?file=nombre_de_fichero // Evitamos que podamos devolver algo que est en otro directorio distinto al a // que queremos $fichero = basename($_GET[file]); // con basename() obtenemos el nombre de fichero, a partir de la ltima barra. u // De esta manera nos evitamos muchos problemas. $fichero = "/home/pepe/downloads/".$fichero; // Supongamos que nos podemos bajar lo que est ah (y el servidor web tenga e // permisos para leer) if ( !(file_exists($fichero) && is_readable($fichero)( ) { die(Fichero invlido); a } $mimetype = shell_exec("file -bi $fichero"); // El programa externo "file" en unix me devolver una cadena del tipo a // "image/png" que puedo usar directamente en la cabecera header("Content-type: $mimetype"); // Y ahora enchufo el fichero completo al navegador fpassthru($fichero); ?>

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.

11.2. XML Simple: SimpleXML


Algunas herramientas para manejar XML, aunque potentes, pueden resultar pesadas de cara al programador. Pero con la entrada de PHP5, y la inclusi n de simpleXML, trabajar con XML resulta f cil hasta puntos insospechados. o a SimpleXML consta de una clase, simplexml, que modela un nodo de XML, a cuyos atributos y nodos hijos se puede acceder con suma facilidad.

11.2.1. Lee y parsea

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.2.2. Busca, busca!


Cuando en un nodo de XML hay varios nodos hijos del mismo tipo, podemos recorrerlos como si de un array se tratara. Por ejemplo, si dentro del nodo < ingredients > hay varios nodos < ing >: <? $fichero = Basque_Chicken.xml; $xml = simplexml_load_file($fichero) or die (Unable to load XML file!); $tiene_sal = false; foreach( $xml->recipe->ingredients->ing as $ingredient ) { $num_ingredientes++; if ($ingredient->item == Salt) $tiene_sal = true; } echo "Esta receta tiene $num_ingredientes ingredientes"; if ($tiene_sal) echo "{$xml->recipe->head->title} contiene sal.<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.

11.3.1. Modicando informaci n o


Lo que se puede hacer sin ning n problema es cambiar la informaci n de un nodo de simplexml (asignando un nuevo u o valor) y regenerando un chero en XML a partir del nodo raz. Por ejemplo, vamos a doblar la cantidad de sal en nuestra receta y despu s guardar todo en un nuevo chero XML: e

64

CAPITULO 11. XML

<? $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); ?>

11.3.2. Creando XML


Lo que SimpleXML no permite (todava) es la creaci n de nodos a mano . Sin embargo, gracias a la relativa sim o plicidad del formato XML, podemos generar contenidos directamente. A veces, la utilizaci n de libreras o herramientas o de XML puede resultar m s pesado que la creaci n del propio XML de manera directa. a o

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.

12.1. Tipos de errores


12.1.1. No es tan grave como parece
Los errores se dividen en tres clases principales: notas (notice), avisos (warning) y errores propiamente dichos (error). Las notas, o notices , no son errores, sino eventos totalmente normales, no perjudiciales, que el motor de php capta y procesa para la ejecuci n normal del c digo. El ejemplo m s claro de notice que se puede generar es el acceso de lectura o o a a una variable no declarada anteriormente. Esto, en otros lenguajes, producira un error completo, pero en PHP esto hace que el motor interprete la variable como NULL y que todo prosiga su curso normal. Con la conguraci n predeterminada o de PHP5, los notices no generan ning n mensaje de error por salida est ndar. u a Los avisos o warnings deben tenerse en cuenta, aunque suelen indicar fallos en la programaci n. Un warning nunca o detendr la ejecuci n de un programa, pero generar un mensaje de error por salida est ndar. Algunos ejemplos de warning a o a a incluyen el llamar a una funci n con un n mero de par metros incorrecto, o el intentar abrir un chero inexistente o una o u a conexi n a base de datos err nea. Es una pr ctica m s o menos com n usar el operador de supresi n de errores (la arroba) o o a a u o en aquellas lneas de c digo que sepamos que pueden generar un warning, pero siempre y cuando tratemos el posible o error convenientemente. Por ejemplo: <? $f = @fopen(/tmp/un_fichero_que_no_existe,r); if (!$f) echo No he podido abrir el fichero; ?>

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

CAPITULO 12. TRATAMIENTO DE ERRORES

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.

12.1.2. Ahora te veo, ahora no


De todos los niveles de error posibles, podemos hacer que se muestren mensajes de error para aquellos niveles que deseemos. Esto se hace mediante la funci n error reporting() y las constantes que indican los distintos niveles. Todo esto o se encuentra perfectamente detallado en el manual de PHP, en la secci n de funciones de tratamiento de errores. o <? error_reporting(E_ALL); // Muestra todos los errores, excepto los de sintaxis estricta echo $a; error_reporting(E_ALL | E_STRICT); // Muestra todos los errores y tambin los de sintaxis estricta e class foo { } $bar = new foo(); if (is_a($bar,foo)) echo "s"; // Es el objeto $bar una instancia de la clase foo ?? error_reporting(E_ALL & (E_NOTICE) ); // Muestra todos los errores, excepto los notices. ?> Adem s de poder cambiar en tiempo de ejecuci n los niveles de error que queremos ver, podemos tambi n cambiar la a o e directiva de conguraci n correspondiente (display errors) en el chero de conguraci n php.ini. Es conveniente recordar o o que si ejecutamos PHP como m dulo en apache, ser necesario reiniciarlo. o a

12.1.3. Me tropiezo yo mismo


En osasiones es conveniente causar errores en lugares determinados, ya sea para mantener informaci n en un log o o para ocultar un mensaje de error y mostrar otro distinto. Esto se consigue usando la funci n trigger error(), que permite o lanzar un error de tipo E USER NOTICE, E USER WARNING o E USER ERROR, de la siguiente manera: <? if (is_readable(/tmp/un_fichero_que_no_existe))

12.2. QUIEN ES EL GENERAL FAILURE Y QUE HACE EN MI DISCO DURO?

67

$f = @fopen(/tmp/un_fichero_que_no_existe,r); else trigger_error(No he podido abrir el fichero,E_USER_ERROR); ?>

12.2. Qui n es el general failure y qu hace en mi disco duro? e e


El usuario medio tiene un concepto bastante curioso de los errores de programaci n: o bien se siente aterrorizado ante o un mensaje de error complejo, o bien no entiende lo que pasa (ni tampoco le importa mucho) y se va a otra parte.

12.2.1. Ojos que no ven...


Ojos que no ven, error que no aparenta serlo. Cuando se est desarrollando una aplicaci n web importante, a la vista a o del p blico, convinene mucho ocultar los posibles errores que puedan ocurrir. Pero no basta con ocultar unos pocos y u hacer un tratamiento especial, sino ocultar todos. Esto se puede conseguir, como hemos visto, con error reporting, pero sin embargo...

12.2.2. Ojos que s ven...


Ojos que no ven, bug que toca las narices. Ocultar los errores y ya est puede ser perjudicial para el desarrollador, a que en un momento determinado puede no saber qu est pasando en su aplicaci n, y necesita datos sobre los errores que e a o pudiera haber. En este caso, lo recomendable es hacer nuestra propia funci n de tratamiento de errores, como por ejemplo: o <?php // definimos una funcin de tratamiento de error o 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 habido un error en nuestra aplicacin. Por favor, escriba a nuestro <a href=mailto:webmaster@dondesea.org>webmaster</a> facilitndole la a siguiente informacin, as como las circunstancias en las que se ha o producido este error: <hr><pre> Cdigo de error: $tipo o Mensaje de error: $mensaje Script y lnea: $fichero - $linea<br />"; $variables = array_pop($contexto); echo "ltimo nivel de la pila de ejecucin: "; U o print_r($variables); echo "</pre><hr>"; } ?> Esto cambiar la apariencia con la que se muestran los mensajes de error. Pero si en vez de mostrarlo todo al usuario, a lo enviamos todo a un programador... <?php // definimos una funcin de tratamiento de error o

68

CAPITULO 12. TRATAMIENTO DE ERRORES

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.

13.1. C digo din mico o a


PHP es un lenguaje interpretado y, como tal, puede ejecutar c digo din micamente. Esto quiere decir que puede o a generar c digo que luego ejecuta con eval(), es decir, que un programa puede programarse a s mismo. o

13.2. Aplicaciones no web


PHP tambi n tiene aplicaciones fuera de la programaci n web, principalmente como lenguaje de shell scripting (ejee o cutado en consola directamente) o para generar aplicaciones gr cas con PHP-GKT. a

13.3. Output Buffering


Mediante un mecamnismo denominado Output Buffering, o Control de Salida, podemos capturar y tratar los datos que, de otra manera, se impimiran directamente por salida est ndar. Es decir, podemos capturar todo lo que se imprima a con echo() y similares, y hacer un tratamiento de ello.

13.4. Pruebas automatizadas


Para proyectos grandes, poedmos usar el est ndar TAP para comprobar que partes de la aplicaci n funcionan como es a o esperado.

13.5. Frameworks, sistemas de templates


Los interesados en crear proyectos grandes seguramente estar n interesados en usar sistemas que les permitan ina dependizar el c digo de la visualizaci n, mediante frameworks como PRADO o sistemas de templates como Smarty. o o Hay que tener en cuenta que PEAR (el repositorio de aplicaciones y extensiones de PHP) contiene muchos m culos ya o probados para distintas funciones.

13.6. Im genes, PDFs, Flash, RTF a


PHP es capaz de generar din micamente im genes, y otros tipos de documentos como PDF, SQF y RTF. a a 69

70

CAPITULO 13. MISCELANEA

13.7. Iteradores sobre clases, PHP Standard Library


Mediante el uso de las funciones de la PHP Standard Library podemos ajustar aspectos de nuestras clases e implementar comportamientos unicos.

13.8. C lculo num rico a e


PHP tambi n cuenta con funciones de c lculo num rico de precisi n arbitraria. e a e o

13.9. Servicios web


Mediante diversos m dulos, podemos hacer que nuestra aplicaci n de servicios de manera est ndar mediante SOAP o o a y XML-RPC.

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.

13.11. Extensiones al motor de PHP


Se pueden a adir funcionalidades al motor de PHP, escritas en C. A estas extensiones despu s se podr acceder n e a llamando a funciones dentro de nuestro c digo PHP. o

13.12. Optimizadores y m quinas virtuales a


PHP sufre de los inconvenientes de un lenguaje interpretado, pero para solventar esto ya existen diversos optimizadores de c digo (como el que comercializa Zend), y ya hay un proyecto para crear una m quina virtual y un lenguaje de c digo o a o intermedio al estilo de Java (http://www.parrotcode.org).

13.13. Hasta el innito y m s all a a


En denitiva, PHP es un lenguaje sencillo de aprender pero extremadamente potente, extensible y apto para muchas aplicaciones. Esperamos que todo lo visto en este curso haya sido de inter s, y que PHP os resuelva muchos problemas. e Gracias.

También podría gustarte