tecnologías de la información y la comunicación ii · la segunda forma de delimitar una cadena...

110
Tecnologías de la Información y la Comunicación II Bloque 2: Diseño de páginas Web dinámicas UD 5: El lenguaje PHP Objetivos: Familiarizarse con un lenguaje interpretado. Conocer a fondo el lenguaje PHP desde el punto de vista de la programación estructurada. Utilizar funciones para separar el diseño del código. Usar formularios para la solicitud de información al usuario. Persistir la información del usuario en ficheros. Utilizar sesiones para compartir variables entre scripts PHP. Desarrollar Webs dinámicas. Profesor: Gabriel Merin Cubero Correo: [email protected]

Upload: vucong

Post on 28-Sep-2018

216 views

Category:

Documents


0 download

TRANSCRIPT

Tecnologías de la Información y la Comunicación II

Bloque 2: Diseño de páginas Web dinámicas

UD 5: El lenguaje PHP Objetivos:

� Familiarizarse con un lenguaje interpretado. � Conocer a fondo el lenguaje PHP desde el punto de vista de la programación estructurada.

� Utilizar funciones para separar el diseño del código. � Usar formularios para la solicitud de información al usuario. � Persistir la información del usuario en ficheros. � Utilizar sesiones para compartir variables entre scripts PHP. � Desarrollar Webs dinámicas.

Profesor: Gabriel Merin Cubero Correo: [email protected]

2 / 110

ÍNDICE DE CONTENIDOS 1. Conceptos básicos .................................................................................................4 1.1. Insertar código PHP en HTML....................................................................4 1.2. Múltiples scripts PHP en un mismo documento .........................................5 1.3. Comentar el código PHP ..............................................................................5

2. Tipos de datos y variables ....................................................................................6 2.1. Enteros .........................................................................................................6 2.2. Números en coma flotante ...........................................................................6 2.3. Cadenas........................................................................................................6 2.4. Conversión de cadenas.................................................................................8 2.5. Arrays (vectores) ..........................................................................................9 2.6. Boolean (lógico) .......................................................................................... 15 2.7. Identificadores ........................................................................................... 16 2.8. Variables .................................................................................................... 17

3. Operadores y estructuras de control.................................................................. 26 3.1. Expresiones ................................................................................................ 26 3.2. Operadores ................................................................................................. 26 3.3. Estructuras de Control .............................................................................. 29

4. Funciones............................................................................................................ 38 4.1. ¿Qué es una función? ................................................................................. 38 4.2. Definición e invocación de funciones ......................................................... 38 4.3. Anidamiento de Funciones ........................................................................ 38 4.4. Funciones recursivas ................................................................................. 39 4.5. Parámetros de las funciones...................................................................... 40 4.6. Funciones Variable .................................................................................... 43 4.7. Acceso a variables globales desde funciones ............................................. 44 4.8. Creación De Librerías De Funciones......................................................... 44

5. Vectores .............................................................................................................. 47 5.1. Estructura interna de los vectores en PHP............................................... 47 5.2. Número de elementos dentro de un vector................................................ 48 5.3. Recorrido de vectores ................................................................................. 50 5.4. Búsqueda de elementos dentro de un vector............................................. 58 5.5. Ordenación de vectores .............................................................................. 59 5.6. Adición y eliminación de elementos (pilas y colas).................................... 63 5.7. Otras funciones interesantes..................................................................... 65

6. Ficheros y Entrada/Salida ................................................................................. 70 6.1. Trabajar con Ficheros ................................................................................ 70 6.2. Trabajar con Directorios ............................................................................ 76 6.3. Funciones útiles del Sistema de Ficheros ................................................. 78 6.4. Modificación de las características de un archivo ..................................... 80 6.5. Ejecución externa de programas ............................................................... 80 6.6. Almacenamiento de variables en ficheros ................................................. 80 6.7. Otras funciones interesantes..................................................................... 82

7. Desarrollo dinámico de webs.............................................................................. 84 7.1. Introducción ............................................................................................... 84 7.2. Plantillas .................................................................................................... 84 7.3. Paso de parámetros entre scripts .............................................................. 87 7.4. Redireccionamiento.................................................................................... 89 7.5. Scripts que se llaman a sí mismos............................................................. 90 7.6. Recomendaciones ....................................................................................... 91

3 / 110

8. FORMULARIOS................................................................................................. 92 8.1. Introducción ............................................................................................... 92 8.2. Formularios................................................................................................ 92 8.3. Formularios y PHP .................................................................................... 96 8.4. Creación Dinámica de Formularios......................................................... 102

9. SESIONES ....................................................................................................... 105 9.1. Introducción ............................................................................................. 105 9.2. Manejo de Sesiones .................................................................................. 105

UD5 - El lenguaje PHP 1.- Conceptos básicos

4 / 110

1. Conceptos básicos

1.1. Insertar código PHP en HTML

Para interpretar un archivo, PHP simplemente ignora el contenido del archivo hasta que encuentra una de las etiquetas especiales que delimitan el inicio de código PHP. El intérprete procesa entonces todo el código que encuentra, hasta que se topa con una etiqueta de fin de código que le dice al intérprete que vuelva a ignorar lo que viene después. Este mecanismo permite embeber (insertar) código PHP dentro de HTML: todo lo que está fuera de las etiquetas PHP se deja tal como está, mientras que el resto se procesa como código.

Hay cuatro conjuntos de etiquetas que pueden ser usadas para denotar bloques de código

PHP. De estas cuatro, sólo 2 (<?php. . .?> y <script language="php">. . .</script>) están siempre disponibles; el resto pueden ser configuradas en el fichero de php.ini para ser o no aceptadas por el intérprete. Las etiquetas soportadas por PHP son: 1. <?php echo "si quieres servir documentos XHTML o XML, haz como aquí;\n"; ?> 2. <? echo "Formato Corto de etiquetas \n"; ?> 3. <script language="php"> echo "muchos editores (como FrontPage) no aceptan instrucciones de procesado"; </script> 4. <% echo "Opcionalmente se pueden usar las etiquetas ASP"; %>

El primer método, <?php. . .?>, es el más conveniente, ya que permite el uso de PHP en código XML como XHTML.

El segundo método no siempre está disponible. El formato corto de etiquetas está

disponible activando el parámetro del fichero de configuración de PHP short_open_tag.

El cuarto método sólo está disponible si se han activado las etiquetas ASP en el fichero de configuración: asp_tags. Nota: No se debe usar el formato corto de etiquetas cuando se desarrollen aplicaciones o librerías con intención de redistribuirlas, o cuando se desarrolle para servidores que no están bajo nuestro control, porque puede ser que el formato corto de etiquetas no esté soportado en el servidor. Para generar código portable y redistribuíble, asegúrate de no usar el formato corto de etiquetas. Nota: La etiqueta de fin código php, ?>, lleva implícito el punto y coma y por tanto no es necesario añadirlo al final de la línea anterior. PHP permite estructurar bloques como: <?php if ($expression){ ?> <strong>Esto es verdadero.</strong> <?php } else { ?> <strong>Esto es falso.</strong> <?php } ?>

Este ejemplo realiza lo esperado, ya que cuando PHP encuentra las etiquetas ?> de fin de bloque, empieza a escribir lo que encuentra tal cual hasta que encuentra otra etiqueta de inicio de bloque.

UD5 - El lenguaje PHP 1.- Conceptos básicos

5 / 110

1.2. Múltiples scripts PHP en un mismo documento

Para permitir un mayor grado de flexibilidad a la hora de construir aplicaciones Web dinámicas, se pueden insertar varios scripts PHP dentro de un mismo documento HTML: <html> <head> <title> <? print “Ejemplo de Múltiples scripts”; $var=5; ?> </title> </head> <body> <? $var = $var + $var; // Hacemos 5+5 echo “5 + 5 = $var”; ?> </body> </html>

1.3. Comentar el código PHP

PHP soporta el estilo de comentarios de 'C', 'C++' y de la interfaz de comandos de Unix. Por ejemplo: <?php echo "Esto es una prueba"; // Esto es un comentario de una sola línea tipo C/C++ /* Esto es un comentario de varias líneas */ echo "Esto es otra prueba"; echo "Esta es la última prueba"; # Este es un comentario de tipo línea de comandos (Linux) ?>

Los estilos de comentarios de una línea actualmente sólo comentan hasta el final de la línea o el bloque actual de código PHP, lo primero que ocurra. <h1>Esto es un <?php # echo "simple";?> ejemplo.</h1> <p>La cabecera de arriba imprimirá 'Esto es un ejemplo'.

Hay que tener cuidado con no anidar comentarios de estilo 'C', algo que puede ocurrir al comentar bloques largos de código. <?php /* echo "Esto es una prueba"; /* Este comentario creará un problema*/ */ ?>

UD5 - El lenguaje PHP 2.- Tipos de datos y variables

6 / 110

2. Tipos de datos y variables En PHP, el tipo de una variable normalmente no lo indica el programador; en su lugar, lo

decide PHP en tiempo de ejecución dependiendo del contexto en el que se utilice esa variable. Si se quisiese obligar a que una variable se convierta a un tipo concreto, se podría forzar la variable (type casting) o usar la función settype() para ello. Nótese que una variable se puede comportar de formas diferentes en ciertas situaciones, dependiendo de qué tipo sea en ese momento. Las variables se crean siguiendo este esquema y siempre con el signo de dólar delante: $nombre = valor; Los distintos valores que puede tomar un variable se verán a continuación.

2.1. Enteros

Los enteros se pueden especificar usando una de las siguientes sintaxis: $a = 1234; # número positivo $a = -123; # número negativo

Enteros en base 8 (Octal) y en base 16 (Hexadecimal) también están permitidos. Los valores en octal comienzan con el dígito 0 mientras que los valores en hexadecimal comienzan por 0x ó 0X. $a = 0123; # número octal (equivalente al 83 decimal) $a = 0x12; # número hexadecimal (equivalente al 18 decimal)

2.2. Números en coma flotante

Los números en coma flotante se pueden especificar utilizando la notación estándar o la científica: $a = 1.234; // Notación estándar $a = 1.2e3; // Notación científica

2.3. Cadenas

Las cadenas de caracteres se pueden especificar usando uno de los dos tipos de delimitadores. Si la cadena está encerrada entre comillas dobles (“”), las variables que estén dentro de la cadena serán expandidas (se sustituyen por su valor). Como en C y en Perl, el carácter de barra invertida (\) se puede usar para especificar caracteres especiales: Caracteres protegidos secuencia significado \n Nueva línea \r Retorno de carro \t Tabulación horizontal \\ Barra invertida \$ Signo del dólar \" Comillas dobles \[0-7]{1,3} la secuencia de caracteres que coincida con la expresión regular es un carácter

en notación octal \x[0-9A-Fa-f]{1,2}

la secuencia de caracteres que coincida con la expresión regular es un carácter en notación hexadecimal

UD5 - El lenguaje PHP 2.- Tipos de datos y variables

7 / 110

La segunda forma de delimitar una cadena de caracteres usa el carácter de comilla simple (‘’). Cuando una cadena va encerrada entre comillas simples, los únicos caracteres de escape disponibles son \\ y \'. Esto es por convenio, así se pueden tener comillas simples y barras invertidas en una cadena entre comillas simples. Las variables no se expandirán dentro de una cadena entre comillas simples. $comida=”pizza”; $frase_1=”Mi comida favorita es la $comida.”; $frase_2= ‘Mi comida favorita es la $comida.’; echo $frase_1; // Dará como salida: Mi comida favorita es la pizza. echo $frase_2; // Dará como salida: Mi comida favorita es la $comida.

Otra forma de delimitar cadenas es usando la sintaxis de documento incrustado ("<<<"). Se debe proporcionar un identificador después de <<<, debajo escribimos las cadenas, y en una última línea escribimos el mismo identificador para indicar el final de cadena. $str = <<<CAD Ejemplo de cadena Expandiendo múltiples líneas usando sintaxis de documento incrustado. CAD; // Donde CAD es el nombre del identificador Nota: La sintaxis de documento incrustado fue añadida en PHP 4.

Las cadenas se pueden concatenar usando el operador '.' (punto). Nótese que el operador '+' (suma) no sirve para esto. // Creamos una cadena $str = “Esta es una cadena”; // Le añadimos más texto $str = $str . “con un poco más de texto.”; echo $str; /* Esto dará como salida: Esta es una cadena con un poco más de texto */

Se puede acceder a los caracteres dentro de una cadena tratándola como un array (vector) de caracteres indexado numéricamente, usando una sintaxis similar a la de C. Veamos un ejemplo más abajo. <?php /* Obtener el primer carácter de una cadena */ $str = 'Esto es una prueba.'; $first = $str[0]; /* Obtener el último carácter de una cadena. */ $str = 'Esto es aún una prueba.'; $last = $str[strlen($str)-1]; /* Le restamos 1 porque si la cadena tiene 23 elementos,

UD5 - El lenguaje PHP 2.- Tipos de datos y variables

8 / 110

el vector irá desde la posición 0 a la posición 22 */ echo $first; // Dará como salida: E echo $last // Dará como salida: . ?>

Como se ha visto en el ejemplo anterior, la función strlen() permite calcular la longitud de una cadena.

También puede ser conveniente insertar dentro de una cadena código html que describa el formato de la cadena. Los siguientes ejemplos son equivalentes y darán por pantalla el mismo resultado: <?php /* Ejemplo 1 */ $cadena=”Esta línea debe estar en negrita”; echo “<strong>$cadena</strong>”; /* Ejemplo 2 */ $cadena=”<strong>Esta línea debe estar en negrita</strong>”; echo $cadena; /* Ejemplo 3 */ $cadena=”Esta línea debe estar en negrita”; $format_ini=”<strong>”; $format_fin=”</strong>”; echo “$format_ini$cadena$format_fin”; /* Los tres ejemplos darán la misma salida por pantalla: Esta línea debe estar en negrita */ ?>

2.4. Conversión de cadenas

Cuando una cadena se evalúa como un valor numérico, el valor resultante y el tipo se determinan como sigue:

La cadena se evaluará como un número en coma flotante (conocido como doble) si contiene

cualquiera de los caracteres '.', 'e', o 'E'. En caso contrario, se evaluará como un entero. El valor viene dado por la porción inicial de la cadena. Si la cadena comienza con datos de

valor numérico, este será el valor usado. En caso contrario, el valor será 0 (cero). Los datos numéricos válidos son un signo opcional, seguido por uno o más dígitos (que opcionalmente contengan un punto decimal), seguidos por un exponente opcional. El exponente es una 'e' o una 'E' seguidos por uno o más dígitos.

Cuando la primera expresión es una cadena, el tipo de la variable dependerá de la segunda expresión: $foo = 1 + "10.5"; // $foo es doble (11.5) $foo = 1 + "-1.3e3"; // $foo es doble (-1299) $foo = 1 + "bob-1.3e3"; // $foo es entero (1) $foo = 1 + "bob3"; // $foo es entero (1) $foo = 1 + "10 Cerditos"; // $foo es entero (11) $foo = 1 + "10 Cerditos"; // $foo es entero (11)

UD5 - El lenguaje PHP 2.- Tipos de datos y variables

9 / 110

$foo = "10.0 cerdos " + 1; // $foo es entero (11) $foo = "10.0 cerdos " + 1.0; // $foo es double (11) Si se quisiera probar cualquiera de los ejemplos de esta sección, basta cortar y pegar los ejemplos e insertar la siguiente línea para ver lo que va ocurriendo: echo "\$foo==$foo; el tipo es " . gettype( $foo ) . "<br>\n";

2.5. Arrays (vectores)

a) Arrays unidimensionales

Un vector no es más que una lista de elementos. Existen dos tipos de vectores: aquellos que son accedidos mediante la posición que ocupa el elemento y aquellos que son accedidos mediante una clave asociada al elemento en cuestión. Los primeros se llaman arrays escalares y los segundos arrays asociativos.

Se puede crear una array usando la función array() o bien se puede asignar el valor de cada elemento del array de manera explícita. Escalares

Para acceder al vector utilizamos un número entero que denota la posición del elemento: $nombre_vect[pos]

Un vector unidimensional puede ser creado de forma explícita como sigue:

$comidas[0]=”Tortilla”; $comidas[1]=”Pollo Frito”; $comidas[2]=”Tofu”; De forma alternativa podemos usar la función array() para crear el vector: $comidas=array(”Tortilla”,”Pollo Frito”,”Tofu”); También es conveniente comentar que se pueden añadir elementos al final del vector sin más que asignar un valor al vector pero con los corchetes vacíos: $comidas[]=”Berenjena”; $comidas[]=”Pimientos”; // Berenjena se añadiría en la posición 3 y Pimientos en la 4 Si un vector aún no ha sido creado y usamos la sintaxis anterior no pasa nada, el primer elemento se introducirá en la posición 0, el siguiente en la 1 y así sucesivamente: $grabadoras[]=”Lite-On”; $grabadoras[]=”Sony”; $grabadoras[]=”Plextor”; /* Puesto que grabadoras se acaba de crear y no contenía ningún elemento, Lite-On se añadiría en la posición 0, Sony en la posición 1 y Plextor en la posición 2. Esta sintaxis puede ser muy útil si no conocemos de antemano el número de elementos que vamos a insertar */ Asociativos Los vectores asociativos son particularmente útiles cuando tiene más sentido acceder a un vector usando palabras (claves) en vez de números enteros. $nombre_vect[“clave”]; // ó

UD5 - El lenguaje PHP 2.- Tipos de datos y variables

10 / 110

$nombre_vect[‘clave’]; Por ejemplo, si queremos almacenar información referente a un estudiante (Nombre, dirección, teléfono, dni, número de matrícula, facultad, curso, etc.) puede ser mucho más conveniente usar un vector asociativo que uno escalar pues cuando queramos acceder a un dato en concreto no necesitaremos memorizar la posición dónde está contenido dicho dato. Veamos un ejemplo: $alumno[“nombre”]=”José”; $alumno[“apellidos”]=”Martínez Roca”; $alumno[“telefono”]=”963 616 654”; $alumno[“direccion”]=”C/ Arco del triunfo 13”; $alumno[“dni”]=”22 111 055”; $alumno[“num_matricula”]=”6666”; $alumno[“facultad”]=”Facultad Informática”; $alumno[“curso”]=”5”; /* Si ahora queremos consultar el nombre de dicho alumno y su número de matrícula basta hacer: */ echo $alumno["nombre"]; /* Es importante comentar que si hiciésemos echo $alumno[0] el intérprete no daría error, pero no se imprimiría nada en la pantalla. Es cierto que PHP trata de la misma forma los arrays asociativos y los escalares, pero el usuario debe acceder convenientemente a cada uno de ellos. */ De nuevo podemos hacer uso de la función array() para crear el vector: $alumno=array(

“nombre” => ”José”, “apellidos” => ”Martínez Roca”, “telefono” => “96 361 66 54”, “direccion” => “C/ Arco del triunfo 13”, “dni” => “22 111 055”, “num_matricula” => “6666”, “facultad” => “Facultad Informática”, “curso” => “5” // El último no lleva una coma al final

); Muy importante: Cuando se habló de cadenas de texto se comentó que una de las diferencias entre comillas simples y dobles residía en que la primera no expandía variables mientras que la segunda sí. Pues bien, si queremos meter dentro de una cadena el valor de una posición de un vector, tenemos que meter la referencia al vector entre llaves, tal como se indica en el ejemplo. // Array Escalar $vector[0]=”Australia”; $vector[1]=”España”; echo “El país que más me gusta es {$vector[0]}”; echo “aunque yo he nacido en {$vector[1]}”; // Array Asociativo $alumno[“Nombre”]=”Vender”; $alumno[“Tipo”]=”Robot”; echo “El alumno {$alumno[“Nombre”]} es de tipo {$alumno[“Tipo”]}.” // Si no usásemos llaves recibiríamos un error de interpretación del tipo: Parse error: parse error, expecting `T_STRING' or `T_VARIABLE' or `T_NUM_STRING' in c:\phpdev\www\pruebas\pruebas.php on line 32

UD5 - El lenguaje PHP 2.- Tipos de datos y variables

11 / 110

Sin embargo es totalmente correcto hacer lo siguiente ya que los vectores no están incluidos dentro de una cadena. // Continuando el ejemplo anterior.... echo $vector[1]; echo $alumno[“Nombre”]; Esto afecta a todos los tipos de arrays: escalares y asociativos, ya sean unidimensionales o multidimensionales. b) Arrays multidimensionales

La idea de un vector multidimensional sería la de un vector dónde dentro de cada posición de dicho vector se halla otro vector. Dentro de cada posición del segundo vector pueden hallarse a su vez otro vector, y así sucesivamente. No hay ningún tipo de limitación respecto a la dimensión pero es muy extraño utilizar dimensiones superiores a tres. Un vector de dimensión 2 se suele representar como una matriz. Para acceder a una celda basta con suministrar la fila y la columna.

Un vector de dimensión 3 se suele representar como un cubo dividido en celdas. Para acceder a una celda se le proporciona la fila, la columna y la altura.

A partir de aquí, las representaciones se hacen cada vez más complicadas. Un vector de dimensión 4 podría representarse como un vector dónde cada posición contiene un cubo dividido en celdas. Estructuras tan complejas no se suelen usar debido a lo difícil que puede llegar a ser su manejo. Escalares

Tal y como uno se puede imaginar, la sintaxis general es la siguiente: $nombre_vect[pos_dim_1][pos_dim_2]..[pos_dim_N] Podemos crear un vector escalar multidimensional de forma explícita o usando la función array(): // Vamos a crear una matriz de dimensión 2 de forma explícita: // Fila 0 $verdurita[0][0]=”Patata”; $verdurita[0][1]=”Bonitato”; // Fila 1 $verdurita[1][0]=”Lechuga”; $verdurita[1][1]=”Pimientos”; // La función array() suele ser más útil en estos casos: $verdurita=array( array("Patata", "Boniato"), // Fila 0 array("Pimiento", "Lechuga") // Fila 1 ); // Si queremos ver el contenido de nuestro vector en forma de matriz basta hacer: echo "{$vector[0][0]} | {$vector[0][1]} <br>"; echo "{$vector[1][0]} | {$vector[1][1]} <br>"; Asociativos Funcionan exactamente igual que los escalares salvo que en vez de usar varios índices para acceder a la información deseada, usamos varias palabras. Por ejemplo, si tenemos una

UD5 - El lenguaje PHP 2.- Tipos de datos y variables

12 / 110

tienda de informática y vendemos procesadores y discos duros, es evidente que tendremos varias marcas y a su vez cada marca tendrá varios modelos. Para simplificar, supondremos que sólo tenemos un modelo de cada marca. Procesadores: AMD: K7 XP 1800 PENTIUM: IV 2,5 Ghz Discos duros: SEAGATE: 40GB 10000 rpm SAMSUNG: 40GB 7200 rpm WESTERN DIGITAL: 60GB 7200 rmp 8MB caché Queremos almacenar esta estructura en un array multidimensional para que dado una marca de procesador o de disco duro, podamos consultar el modelo disponible en stock: Tienda de Informática – Ejemplo 1: // Usando la declaración explícita: // 1º los procesadores $productos[“procesador”][“AMD”]=”K7 XP 1800”; $productos[“procesador”][“PENTIUM”]=”IV 2,5 Ghz”; // 2º los discos duros $productos[“disco_duro”][“SEAGATE”]=” 40GB 10000 rpm”; $productos[“disco_duro”][“SAMSUNG”]=” 40GB 7200 rpm”; $productos[“disco_duro”][“WESTERN_DIGITAL”]=” 60GB 7200 rmp 8MB caché”; // Usando la función array(): $productos=array(

“procesador” => array ( “AMD” => ”K7 XP 1800”, “PENTIUM” => “IV 2,5 Ghz”

), “disco_duro” => array(

“SEAGATE” => “40GB 10000 rpm”, “SAMSUNG” => “40GB 7200 rpm”, “WESTERN_DIGITAL” => “60GB 7200 rmp 8MB caché”

) ); // Si alguien nos pregunta qué disco duro SEAGATE tenemos, basta con hacer: echo “Disco duro SEAGATE: {$productos[“disco_duro”][“SEAGATE”]}”; c) Mezclando arrays escalares y asociativos

También es posible mezclar arrays escalares y asociativos siendo una estrategia de lo más útil. Para ver su utilidad ampliaremos el ejemplo anterior. Antes, por simplicidad, se supuso que sólo teníamos un modelo de cada marca. Esto no suele ser cierto, lo normal es tener varios modelos de una misma marca: Procesadores: AMD:

⇒ K7 XP 1900 ⇒ K7 XP 1800 ⇒ K7 XP 1700

PENTIUM: ⇒ IV 2,5 Ghz ⇒ IV 2,4 Ghz ⇒ IV 2,3 Ghz ⇒ IV 2,2 Ghz

UD5 - El lenguaje PHP 2.- Tipos de datos y variables

13 / 110

Discos duros: SEAGATE:

⇒ 40GB 10000 rpm ⇒ 80GB 7200 rpm ⇒ 160GB 7200 rpm

SAMSUNG: ⇒ 40GB 7200 rpm

WESTERN DIGITAL: ⇒ 60GB 7200 rpm 8MB cache ⇒ 80GB 1000 rpm 16MB cache

Veamos cómo implementar ésta estructura de datos en PHP: Tienda de informática – Ejemplo 2: // Por sencillez, en éste caso únicamente veremos la declaración explícita: // 1º los procesadores $productos[“procesador”][“AMD”][0]=”K7 XP 1900”; $productos[“procesador”][“AMD”][1]=”K7 XP 1800”; $productos[“procesador”][“AMD”][2]=”K7 XP 1700”; $productos[“procesador”][“PENTIUM”][0]=”IV 2,5 Ghz”; $productos[“procesador”][“PENTIUM”][1]=”IV 2,4 Ghz”; $productos[“procesador”][“PENTIUM”][2]=”IV 2,3 Ghz”; $productos[“procesador”][“PENTIUM”][3]=”IV 2,2 Ghz”; // 2º los discos duros $productos[“disco_duro”][“SEAGATE”][0]=” 40GB 10000 rpm”; $productos[“disco_duro”][“SEAGATE”][1]=” 80GB 7200 rpm”; $productos[“disco_duro”][“SEAGATE”][2]=” 160GB 7200 rpm”; $productos[“disco_duro”][“SAMSUNG”][0]=” 40GB 7200 rpm”; $productos[“disco_duro”][“WESTERN_DIGITAL”][0]=” 60GB 7200 rpm 8MB cache”; $productos[“disco_duro”][“WESTERN_DIGITAL”][1]=” 80GB 10000 rpm 16MB cache”; // Si adquirimos nuevos productos, modificar la estructura es muy sencillo. // Por ejemplo, supongamos que recibimos un nuevo procesador AMD y queremos añadirlo: $productos[“procesador”][“AMD”][]=”K7 XP 2000”; // Esto añadiría el nuevo procesador al final de los procesadores AMD, es decir, en la posición 3 // En cualquier momento si deseamos añadir una nueva marca (por ej. QUANTUM) basta hacer: $productos[“disco_duro”][“QUANTUM”][0]”40GB 10000 rpm”; /* Es conveniente comentar que no era necesarios indicar los índices. Ya se ha comentado que si se usan los corchetes vacíos, PHP inserta el dato después de la última posición y si el vector no existía metía el dato en la posición 0. Así, se podría haber hecho perfectamente: */ $productos[“procesador”][“AMD”][]=”K7 XP 1900”; $productos[“procesador”][“AMD”][]=”K7 XP 1800”; $productos[“procesador”][“AMD”][]=”K7 XP 1700”; $productos[“procesador”][“PENTIUM”][]=”IV 2,5 Ghz”; . . . // y así sucesivamente

UD5 - El lenguaje PHP 2.- Tipos de datos y variables

14 / 110

d) Notas importantes sobre los arrays asociativos

Es MUY importante que cuando deseemos acceder a una posición de un vector asociativo escribamos CORRECTAMENTE la clave, es decir, que la escribamos exactamente como la definimos al crear el vector. Pensemos que la clave no es más que una cadena de caracteres. Cuando nosotros escribimos una clave, PHP compara el texto de la clave suministrada con las claves que contiene el vector. La comparación se hace carácter a carácter. Eso significa que si ponemos un acento de más (o de menos), o cambiamos una letra mayúscula por una minúscula, PHP no encontrará la clave que estamos buscando. Es también importante saber que PHP NO dará ningún tipo de error si escribimos mal la clave. Si no encuentra la clave, supondrá que no existe y devolverá una cadena vacía. $bebidas[“refrescantes”]=”Coca-Cola”; $bebidas[“alcoholicas”]=”Ron”; // Si hacemos echo $bebidas[“refrescantes”]; // Daría por pantalla: Coca-Cola echo $bebidas[“Refrescantes”]; /* No daría nada por pantalla pues PHP considera que la clave no existe. */ Ya se ha dicho que la clave no es más que una cadena de caracteres. Sabemos que las cadenas de caracteres pueden ir entre comillas simples o comillas dobles. Esto dota de gran flexibilidad a la hora de crear claves pues el valor de una clave puede ser proporcionado por el valor de una variable (para ello tenemos que encerrar la variable entre comillas dobles). Ello permite incluso crear vectores con claves que ni siquiera sabemos a priori. Veamos un ejemplo: $marca=”AMD”; /* Pensemos que el valor de la variable $marca no tenemos por qué conocerlo. */ $usuarios[“$marca”]=”K7 1800”; // o bien $usuarios[$marca]=”K7 1800”; /* la segunda forma tiene más peligro puesto que si no estamos seguros de que la vble $marca es una cadena de caracteres, podemos estar creando un vector escalar en vez de uno asociativo y podemos tener problemas a la hora de acceder a los datos. Por lo tanto, es más recomendable usar la primera forma.*/ echo $usuarios[“AMD”]; // daría por pantalla: K7 1800 e) Notas importantes sobre los arrays en general

PHP permite jugar enormemente con los vectores. Si queremos igualar un vector a otro, lo único que tenemos que hacer es igualar la nueva variable al vector. $piezas[0]=”monitor”; $piezas[1]=”cpu”; $piezas[2]=”placa base”; $piezas[3]=”RAM”; // Si queremos crear un nuevo vector llamado $mi_pc y que sea igual a $piezas basta hacer: $mi_pc=$piezas; // $mi_pc será una copia de $piezas. Si tenemos un vector multidimensional, podemos quedarnos con un trozo de él de la siguiente forma: // Vamos a seguir con el ejemplo2 de la tienda de informática // Imaginemos que queremos un vector dónde sólo tengamos los discos duros:

UD5 - El lenguaje PHP 2.- Tipos de datos y variables

15 / 110

$discos_duros=$productos[“disco_duro”]; // Con esto conseguiríamos un vector bidimensional con los discos duros únicamente. // Podemos acceder a uno de ellos sin más que hacer: echo $discos_duros[“SEAGATE”][0]; // También podríamos quedarnos únicamente con los procesadores AMD $AMD=$productos[“procesadores”][“AMD”]; /* Con esto hemos creado un vector unidimensional con los modelos de procesador que tenemos de AMD. Para acceder a uno de ellos basta hacer: */ echo $AMD[2]; Hay otro punto importante que debe ser tratado. PHP no dará error si se trata de acceder a una posición del vector que no exista (al igual que si tratamos de acceder a una variable que no existe o que aún no ha sido definida). Además, no tenemos por qué comenzar los vectores en la posición 0. Es más, en un vector escalar, podemos ir metiendo datos en las posiciones 3, 5, 9, 12, etc...(es decir, en posiciones totalmente arbitrarias) Pero ojo, las posiciones que se quedan vacías no quedan rellenadas con nada, ni son inicializadas a 0, más bien todo lo contrario. Para PHP esas posiciones no existen y de hecho si usamos la función count() para contar los elementos de un vector sólo nos contará aquellas posiciones dónde hay datos. Un ejemplo seguro que aclara este asunto: /* Nos definimos un vector $prueba pero comenzando por la posición 2 aunque bien podíamos haber comenzado por cualquier otra posición. */ $prueba[2]=”dato1”; $prueba[5]=”dato2”; $prueba[6]=”dato3”; $prueba[1024]=”dato4”; $prueba[2220]=”dato5”; // Si ahora hacemos echo ‘El número de elementos del $prueba es: ’; echo count($prueba); /* ¿Cuál crees que será la salida de este script? El número de elementos del vector $prueba es: 5 Precisamente por esta razón PHP suministra potentes herramientas de recorrido de vectores. De esa forma dado un vector cualquiera, podemos recorrerlo de cabo a rabo sin necesidad de conocer su tamaño, la posición de inicio y fin, si los valores han sido insertados en orden o de forma salteada, etc... */ Hasta aquí hemos visto los diferentes tipos de vectores que hay, su construcción y el acceso a los datos pero no hemos visto ni las estrategias de rellenado ni las formas de recorrer los vectores. Esto se verá más adelante (una vez hallamos visto las estructuras de control) dentro de un tema dedicado únicamente a vectores. Además se verán muchas de las funciones que PHP tiene para realizar ordenaciones, búsquedas, eliminación de elementos, troceado de vectores, contabilidad de los elementos de un vector, etc...

2.6. Boolean (lógico)

El tipo bolean sirve para representar, únicamente, dos estados CIERTO (TRUE) o FALSO (FALSE). Ello permite utilizar variables como flags (indicadores, banderas). De esa forma podemos hacer comprobaciones y dependiendo de si el indicador es cierto o no, hacer una cosa u otra.

UD5 - El lenguaje PHP 2.- Tipos de datos y variables

16 / 110

PHP, al igual que C o Perl, también interpreta como CIERTO cualquier valor entero

distinto de 0 y como FALSO el valor 0. Estas dos formas de representar valores de verdad nos facilita las cosas y nos da más

juego. Veamos algunos ejemplos: // Todos los ejemplos que vamos a ver a continuación son equivalentes: // ----------------------------------------------------------------------------------------- // Ejemplo 1 $flag_euros=TRUE; if ($flag_euros== TRUE) echo “El resultado se mostrará en euros”; else “El resultado se mostrará en pesetas”; // ----------------------------------------------------------------------------------------- // Ejemplo 2 $flag_euros=TRUE; if ($flag_euros) echo “El resultado se mostrará en euros”; else “El resultado se mostrará en pesetas”; // ----------------------------------------------------------------------------------------- // Ejemplo 3 $flag_euros=1; // aunque podríamos poner -56 if ($flag_euros==1) echo “El resultado se mostrará en euros”; else “El resultado se mostrará en pesetas”; // ----------------------------------------------------------------------------------------- // Ejemplo 4 $flag_euros=1; if ($flag_euros) echo “El resultado se mostrará en euros”; else “El resultado se mostrará en pesetas”; // ----------------------------------------------------------------------------------------- // Ejemplo 5 $flag_euros=1; if ($flag_euros==TRUE) echo “El resultado se mostrará en euros”; else “El resultado se mostrará en pesetas”; // ----------------------------------------------------------------------------------------- /* Todos estos ejemplos son correctos y darían como salida: El resultado se mostrará en euros */ /* La sentencia if se explicará en el tema 3 (Operadores y Estructuras de Control)*/

2.7. Identificadores

Un identificador es un término general aplicado a las variables, funciones y objetos definidos por el usuario. Hay diversas propiedades que han de cumplir los identificadores en PHP:

o Un identificador consiste en uno más caracteres y debe comenzar con una letra del abecedario o un carácter de subrayado (“_”). Además, los identificadores sólo pueden estar constituidos por letras, números caracteres de subrayado y otros caracteres ASCII comprendidos del 127 a 255.

UD5 - El lenguaje PHP 2.- Tipos de datos y variables

17 / 110

o Los identificadores son sensibles a mayúsculas y minúsculas. Por lo tanto, una variable llamada $nombre es diferente a otra llamada $Nombre, $nombrE ó $NoMbRe.

o Por último, un identificador no puede ser idéntico a ninguna de las palabras clave

predefinidas en PHP.

Veamos algunos ejemplos: VALIDO INVÁLIDO mi_funcion() $_info $Tamaño cuad_2()

$ruta&precio $!contador 2_a_2_funcion() $func_<_ab

2.8. Variables

Hasta ahora hemos venido jugando con las variables de una forma relativamente sencilla. En realidad no hemos hecho más que asignaciones y acceso a los contenidos de las variables. El propósito de este punto es el de entrar en detalle sobre el maravilloso mundo de la manipulación de variables.

a) Ámbito de las variables

Podríamos definir el ámbito de una variable como el ámbito de disponibilidad de dicha variable dentro del programa. Hay tres tipos de ámbitos:

o Variables Locales o Variables Globales o Variables Estáticas

Variables Locales Una variable declarada dentro de una función es considerada como local, es decir, sólo puede ser referenciada dentro de la función. Cualquier asignación fuera de la función será considerada como la asignación de un valor a una variable totalmente diferente a la contenida dentro de la función (aunque tengan el mismo nombre). Es importante saber que cuando finaliza una función, todas las variables locales contenidas en ella son destruidas. Veamos un pequeño ejemplo: <?php $x=0; function asigna_x() { $x=5; echo “\$x dentro de la función vale: $x <br>”; } echo “\$x fuera de la función vale: $x <br>”; /* ------------------------------------- Esto dará como resultado: $x dentro de la función vale: 5 $x fuera de la función vale: 0 ----------------------------------------- */ ?>

UD5 - El lenguaje PHP 2.- Tipos de datos y variables

18 / 110

Variables Globales A diferencia de las variables locales, una variable Global puede ser accedida y modificada desde cualquier parte del programa. Sin embargo, para llevar esto a efecto, una variable global debe ser explícitamente declarada como tal dentro de la función. Esto se consigue colocando la palabra reservada GLOBAL delante de la variable que debe ser reconocida como tal. Veamos un ejemplo: <?php $var=25; function incrementa_var() { GLOBAL $var; $var++; } incrementa_var(); echo $var; // Esto dará como resultado: 26 ?> La sintaxis anterior puede dar lugar a confusión. En funciones extremadamente largas, puede llegar a ocurrir que olvidemos que la variable $var es global y no local. Para evitar este tipo de problemas, PHP proporciona un tipo de sintaxis alternativa que consiste en usar su vector de variables globales llamado $GLOBALS. La sintaxis es: $GLOBALS[“nombre_var_global”]; o $GLOBALS[‘nombre_var_global’];

La diferencia entre comillas dobles y simples es la ya comentada. Veamos un ejemplo de cómo usar dicho vector: <?php $var=25; function incrementa_var() { $GLOBALS[‘var’]++; } incrementa_var(); echo $var; // Esto dará como resultado: 26 // Dentro del programa principal también podemos acceder a la variable $var usando el vector // $GLOBALS. Es poco útil, pero totalmente válido: echo $GLOBALS[‘var’]; // Volverá a imprimir 26 ?>

UD5 - El lenguaje PHP 2.- Tipos de datos y variables

19 / 110

También podemos crear variables globales dentro de las funciones usando cualquiera de los dos métodos anteriores:

<?php // Ejemplo 1 function crea_global_var() { GLOBAL $var; $var=25; } // Creamos una variable global $var=25 crea_global_var(); // La imprimimos por pantalla echo $var; // Esto imprimirá por pantalla: 25 ?>

<?php // Ejemplo 2: sintaxis alternativa function crea_global_var() { $GLOBALS[‘var’]=25; } // Creamos una variable global $var=25 crea_global_var(); // La imprimimos por pantalla echo $GLOBALS[‘var’ ]; // Esto imprimirá por pantalla: 25 ?>

Es evidente que ambos ejemplos son válidos y darán por salida los mismos resultados. Sólo queda comentar que aunque el uso de variables globales puede ser bastante útil, siempre han sido una fuente de interminables problemas para los programadores. Por lo tanto, se recomienda un uso prudente de las mismas. Variables Estáticas En pocas palabras, una variable estática es una es una especie variable local que no es destruida cuando finaliza la función y que por tanto mantiene su valor. De esa forma si volvemos a llamar a la función, dicha variable tendrá el valor mantenido. Para declarar una variable estática, sólo tenemos que poner la palabra reservada STATIC delante del nombre de la variable e inicializarla al valor que queremos que tenga inicialmente (valga la redundancia). Un ejemplo seguro que aclara su uso: <?php function inc_contador() { STATIC $count = 0; $count++; echo $count; } inc_contador(); // Imprimirá 1 inc_contador(); // Imprimirá 2 inc_contador(); // Imprimirá 3 ?> b) Type juggling (juego de tipos)

PHP no requiere (o soporta) la declaración explícita del tipo en la declaración de variables; el tipo de una variable se determina por el contexto en el que se usa esa variable. Esto quiere decir que si se asigna un valor de cadena a la variable var, var se convierte en una cadena. Si después se asigna un valor entero a la variable var, se convierte en una variable entera.

Un ejemplo de conversión de tipo automática en PHP es el operador suma '+'. Si

cualquiera de los operandos es un doble, entonces todos los operandos se evalúan como dobles, y el

UD5 - El lenguaje PHP 2.- Tipos de datos y variables

20 / 110

resultado será un doble. En caso contrario, los operandos se interpretarán como enteros, y el resultado será también un entero. Nótese que esto NO cambia los tipos de los operandos propiamente dichos, el único cambio está en cómo se evalúan los operandos.

$foo = "0"; // $foo es una cadena (ASCII 48) $foo++; // $foo es la cadena "1" (ASCII 49) $foo += 1; // $foo ahora es un entero (2) $foo = $foo + 1.3; // $foo ahora es un doble (3.3) $foo = 5 + "10 Cerditos Pequeñitos"; // $foo es entero (15) $foo = 5 + "10 Cerditos"; // $foo es entero (15)

Si quisiese probar cualquiera de los ejemplos de esta sección, puede cortar y pegar los ejemplos e insertar la siguiente línea para ver por sí mismo lo que va ocurriendo:

echo "\$foo==$foo; el tipo es " . gettype( $foo ) . "<br>\n";

Si los últimos dos ejemplos anteriores parecen confusos, ver Conversión de cadenas.

Dado que PHP determina los tipos de las variables y los convierte (generalmente) según necesita, no siempre resulta obvio de qué tipo es una variable dada en un momento concreto. PHP incluye varias funciones que descubren de qué tipo es una variable. Son gettype(), is_long(), is_double(), is_string(), is_array(), y is_object().

Si se desea obligar a que una variable sea evaluada con un tipo concreto, hay que hacer un Forzado de tipos (que se verá a continuación). Si se desea cambiar el tipo de una variable, se puede usar la función settype(). Nota: La posibilidad de una conversión automática a array no está definida actualmente. $a = 1; // $a es un entero $a[0] = "f"; // ¿ $a se convierte en un array, en el que $a[0] vale "f" ?

Aunque el ejemplo anterior puede parecer que claramente debería resultar en que $a se convierta en un array donde el primer elemento es 'f', consideremos esto:

$a = "1"; // $a es una cadena $a[0] = "f"; // ¿Qué pasa con los índices de las cadenas?

Dado que PHP soporta indexación en las cadenas mediante desplazamientos usando la misma sintaxis que la indexación de arrays, el ejemplo anterior nos conduce a un problema: ¿debería convertirse $a en un array cuyo primer elemento sea "f", o debería convertirse "f" en el primer carácter de la cadena $a? Por esta razón el resultado de esta conversión automática se considera que no está definido. Las posibles soluciones han sido objeto de discusión. Por lo visto, si se desea reutilizar una variable para estos propósitos, se puede usar la función unset() que se encarga de destruir la variable. Una vez destruida la podemos volver a crear asignándole el valor que mejor nos convenga. c) Type casting (forzado de tipos)

El forzado de tipos en PHP funciona como en C: el nombre del tipo deseado se escribe entre paréntesis antes de la variable a la que se pretende forzar.

$foo = 10; // $foo es un entero $bar = (double) $foo; // $bar es un doble Los forzados de tipo permitidos son:

o (int), (integer) - fuerza a entero (integer)

UD5 - El lenguaje PHP 2.- Tipos de datos y variables

21 / 110

o (real), (double), (float) - fuerza a doble (double) o (string) - fuerza a cadena (string) o (array) - fuerza a array (array) o (object) - fuerza a objeto (object)

Nótese que las tabulaciones y espacios se permiten dentro de los paréntesis, así que los siguientes ejemplos son funcionalmente equivalentes: $foo = (int) $bar; $foo = ( int ) $bar; Es importante saber que cuando un real es forzado a convertirse en un entero, la parte decimal es eliminada (no se redondea en función del valor decimal). $var = 14.7; $var = ( int ) var; // $var ahora valdrá 14

Puede no ser obvio que ocurrirá cuando se fuerce entre ciertos tipos. Por ejemplo, lo siguiente debería ser tenido en cuenta. Cuando se fuerza el cambio de un escalar o una variable de cadena a un array, la variable se convertirá en el primer elemento del array:

$var = 'ciao'; $arr = (array) $var; echo $arr[0]; // produce la salida 'ciao' Cuando se fuerza el tipo de una variable escalar o de una cadena a un objeto, la variable se convertirá en un atributo del objeto; el nombre del atributo será 'scalar': $var = 'ciao'; $obj = (object) $var; echo $obj->scalar; // produce la salida 'ciao' d) Asignación por valor y por referencia

En PHP, las variables siempre se asignan por valor. Esto significa que cuando se asigna una expresión a una variable, el valor íntegro de la expresión original se copia en la variable de destino. Esto quiere decir que, por ejemplo, después e asignar el valor de una variable a otra, los cambios que se efectúen a una de esas variables no afectará a la otra

PHP ofrece, además, otra forma de asignar valores a las variables: asignar por referencia1. Esto significa que la nueva variable simplemente referencia (en otras palabras, "se convierte en un alias de" o "apunta a") la variable original. Los cambios a la nueva variable afectan a la original, y viceversa. Esto también significa que no se produce una copia de valores; por tanto, la asignación ocurre más rápidamente. De todos modos, cualquier incremento de velocidad se notará sólo en los bucles críticos cuando se asignen grandes arrays u objetos. Para asignar por referencia, simplemente se antepone un ampersand (&) al comienzo de la variable cuyo valor se está asignando (la variable fuente). <?php $postre = 'Tárta de arándanos'; // Asigna el valor 'Tárta de arándanos' a $postre $p_postre = &$postre; // $p_postre es un puntero a la variable $postre. echo "Mi postre preferido es: $postre"; // Daría por salida: Mi postre preferido es: Tárta de arándanos $p_postre = ‘Tarta de queso’; // Cambiamos nuestro postre preferido echo "Mi postre preferido es: $postre"; // Ahora la salida será: Mi postre preferido es: Tárta de queso ?>

1 Esta novedad está incluida a partir de la versión 4 de PHP.

UD5 - El lenguaje PHP 2.- Tipos de datos y variables

22 / 110

Algo importante a tener en cuenta es que sólo las variables con nombre pueden ser

asignadas por referencia. <?php $foo = 25; $bar = &$foo; // Esta es una asignación válida. $bar = &(24 * 7); // Inválida; referencia una expresión sin nombre. function test() { return 25; } $bar = &test(); // Inválida. ?> Nota: En las últimas versiones de PHP4 así como en PHP5, el paso de variables por referencia ha sido despreciado y ha quedado en desuso. e) Constantes

Se puede definir una constante usando la función define(). Una vez definida, no puede ser modificada ni eliminada.

Solo se puede definir como constantes valores escalares (boolean, integer, float y string ). Para obtener el valor de una constante solo es necesario especificar su nombre. A diferencia de las variables, no se tiene que especificar el prefijo $. También se puede utilizar la función constant() para obtener el valor de una constante. Podemos usar la función get_defined_constants() parar obtener array asociativo con el nombre de todas las constantes y sus respectivos valores. Nota: Las constantes y las variables (globales) se encuentran en un espacio de nombres distinto. Esto implica que por ejemplo TRUE y $TRUE son diferentes. Aunque se pude definir constantes en cualquier parte del código, es conveniente hacerlo al principio del script para evitar problemas. Para poder usar un constante, previamente tiene que haver sido declarada como tal. Si uno no se da cuenta y define la función más debajo de dónde la usa, el intérprete considerará que la constante referencia no existe pudiendo dar lugar a resultados no deseados. Usar la función defined() para comprobar la existencia de dicha constante. Estas son las diferencias entre constantes y variables:

o Las constantes no son precedidas por un símbolo de dolar ($) o Las constantes solo pueden ser definidas usando la función define() , nunca por simple

asignación o Las constantes pueden ser definidas y accedidas sin tener en cuenta las reglas de alcance

del ámbito. o Las constantes no pueden ser redefinidas o eliminadas después de establecerse, o Las constantes solo puede albergar valores escalares

<?php define("PI", "3.141592"); echo PI; // Da como salida: 3.141592 ?> f) Variables predefinidas

PHP proporciona una gran cantidad de variables predefinidas a cualquier script que se ejecute. De todas formas, muchas de esas variables no pueden estar completamente documentadas ya que dependen de sobre qué servidor se esté ejecutando, la versión y

UD5 - El lenguaje PHP 2.- Tipos de datos y variables

23 / 110

configuración de dicho servidor, y otros factores. Algunas de estas variables no estarán disponibles cuando se ejecute PHP desde la línea de comandos.

Las siguientes variables son creadas por el propio PHP (a partir de PHP 4.1.0). Son denominadas superglobales porque se puede acceder a ellas desde cualquier parte del código del programa, da igual que estemos dentro de una función o dentro del método de un objeto.

$GLOBALS Contiene una referencia a cada variable disponible en el espectro de las variables del script. Las claves de esta matriz son los nombres de las variables globales. $GLOBALS existe desde PHP 3. $_SERVER Variables definidas por el servidor web ó directamente relacionadas con el entorno en donde el script se esta ejecutando. Análoga a la antigua matriz $HTTP_SERVER_VARS (la cual está todavía disponible, aunque no se use). $_GET Variables proporcionadas al script por medio de HTTP GET. Análoga a la antigua matriz $HTTP_GET_VARS (la cual está todavía disponible, aunque no se use). $_POST Variables proporcionadas al script por medio de HTTP POST. Análoga a la antigua matriz $HTTP_POST_VARS (la cual está todavía disponible, aunque no se use). $_COOKIE Variables proporcionadas al script por medio de HTTP cookies. Análoga a la antigua matriz $HTTP_COOKIE_VARS (la cual está todavía disponible, aunque no se use). $_FILES Variables proporcionadas al script por medio de la subida de ficheros via HTTP . Análoga a la antigua matriz $HTTP_POST_FILES (la cual está todavía disponible, aunque no se use). Vea también Subiendo ficheros por método POST para más información. $_ENV Variables proporcionadas al script por medio del entorno. Análoga a la antigua matriz $HTTP_ENV_VARS (la cual está todavía disponible, aunque no se use). $_REQUEST Variables proporcionadas al script por medio de cuaquier mecanismo de entrada del usuario y por lo tanto no se puede confiar en ellas. La presencia y el orden en que aparecen las variables en esta matriz es definido por la directiva de configuración variables_order. Esta matriz no tiene un análogo en versiones anteriores a PHP 4.1.0. Ver también import_request_variables(). Nota: Cuando se utiliza la linea de comandos aparecerán dos nuevas variables globales llamadas $argv y $argc. $_SESSION Variables registradas en la sesión del script. Análoga a la antigua matriz $HTTP_SESSION_VARS (la cual está todavía disponible, aunque no se use).

Las antiguas matrices $HTTP_*_VARS siguen existiendo pero tienen un comportamiento distinto. No son superglobales y por tanto, si se quiere acceder a ellas desde una función o un método, se ha de poner delante la palabra reservada GLOBAL. Aunque inicialmente contienen la misma información, son variables completamente distintas. Actualmente están en desuso y se recomienda usar las primeras. Si register_globals está activado, PHP registrará, además de las matrices anteriores, un gran número de variables adicionales. En esencia, aparecerá una variable por cada elemento contenido en los vectores anteriores. Si se desea ver una lista completa de las variables del servidor, del entorno y de PHP basta hacer:

UD5 - El lenguaje PHP 2.- Tipos de datos y variables

24 / 110

while ( list($var, $valor) = each($GLOBALS)) echo “<br>$var => $valor”; Saldrá algo como esto (Realizado sobre un servidor Apache en Windows XP): ALLUSERSPROFILE => C:\\Documents and Settings\\All Users APPDATA => C:\\Documents and Settings\\Gabi\\Datos de programa CLIENTNAME => Console CommonProgramFiles => C:\\Archivos de programa\\Archivos comunes COMPUTERNAME => ELANDAR ComSpec => C:\\WINDOWS\\system32\\cmd.exe HOMEDRIVE => C: HOMEPATH => \\Documents and Settings\\Gabi LOGONSERVER => \\\\ELANDAR NUMBER_OF_PROCESSORS => 1 OS => Windows_NT Path => C:\\WINDOWS\\system32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem PATHEXT => .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH PROCESSOR_ARCHITECTURE => x86 PROCESSOR_IDENTIFIER => x86 Family 6 Model 5 Stepping 2, GenuineIntel PROCESSOR_LEVEL => 6 PROCESSOR_REVISION => 0502 ProgramFiles => C:\\Archivos de programa PROMPT => $P$G SESSIONNAME => Console SystemDrive => C: SystemRoot => C:\\WINDOWS TEMP => C:\\DOCUME~1\\Gabi\\CONFIG~1\\Temp TMP => C:\\DOCUME~1\\Gabi\\CONFIG~1\\Temp USERDOMAIN => ELANDAR USERNAME => Gabi USERPROFILE => C:\\Documents and Settings\\Gabi windir => C:\\WINDOWS COMSPEC => C:\\WINDOWS\\system32\\cmd.exe DOCUMENT_ROOT => c:/phpdev/www/ HTTP_ACCEPT => image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */* HTTP_ACCEPT_ENCODING => gzip, deflate HTTP_ACCEPT_LANGUAGE => es HTTP_CONNECTION => Keep-Alive HTTP_HOST => localhost HTTP_REFERER => http://localhost/public/pruebas/ HTTP_USER_AGENT => Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) PATH => C:\\WINDOWS\\system32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem REMOTE_ADDR => 127.0.0.1 REMOTE_PORT => 1387 SCRIPT_FILENAME => c:/phpdev/www/public/pruebas/prueba1.php SERVER_ADDR => 127.0.0.1 SERVER_ADMIN => [email protected] SERVER_NAME => localhost SERVER_PORT => 80 SERVER_SIGNATURE => Apache/1.3.27 Server at localhost Port 80 SERVER_SOFTWARE => Apache/1.3.27 (Win32) PHP/4.2.3 WINDIR => C:\\WINDOWS GATEWAY_INTERFACE => CGI/1.1 SERVER_PROTOCOL => HTTP/1.1

UD5 - El lenguaje PHP 2.- Tipos de datos y variables

25 / 110

REQUEST_METHOD => GET QUERY_STRING => REQUEST_URI => /public/pruebas/prueba1.php SCRIPT_NAME => /public/pruebas/prueba1.php PATH_TRANSLATED => c:/phpdev/www/public/pruebas/prueba1.php PHP_SELF => /public/pruebas/prueba1.php argv => Array argc => 0 HTTP_POST_VARS => Array _POST => Array HTTP_GET_VARS => Array _GET => Array HTTP_COOKIE_VARS => Array _COOKIE => Array HTTP_SERVER_VARS => Array _SERVER => Array HTTP_ENV_VARS => Array _ENV => Array HTTP_POST_FILES => Array _FILES => Array _REQUEST => Array GLOBALS => Array valor => Array var => valor Nota: Las variables en negrita, son variables que ha creado el propio script.

UD5 – El lenguaje PHP 3.- Operadores y estructuras de control

26 / 110

3. Operadores y estructuras de control En este capítulo introduciremos aspectos cruciales de cualquier lenguaje de programación: expresiones, operadores y estructuras de control. El conocimiento de dichos aspectos es totalmente imprescindible para poder construir aplicaciones grandes y complejas en PHP puesto que, al fin y al cabo, acabarán siendo gran parte de nuestro código. Si lenguajes tales como C o JAVA te resultan familiares, este capítulo será más bien un repaso a dichos aspectos.

3.1. Expresiones

Una expresión es, básicamente, a un línea de código representando una acción en un programa. Todas las expresiones constan de al menos un operando y uno o más operadores. a) Operandos

Un operando es una de las entidades que es manipulada dentro de una expresión. Un operando válido es cualquiera de los tipos de datos visto en el capítulo 2. $a++; // $a es un operando $sum = $valor1 + $valor2 // $sum, $valor1 y $valor2 son operandos b) Operadores

Un operador es un símbolo que especifica una acción en una expresión. Muchos de los operadores que se verán son sencillos y pueden resultar familiares. Es importante comentar que la conversión automática de tipos que PHP posee, convertirá los tipos de los operandos según el tipo de operador utilizado. $a++; // ++ es un operador $sum = $valor1 + $valor2 // = y + son operadores La precedencia y la asociatividad de operadores es significativa en todo lenguaje de programación y es algo que veremos dentro de este capítulo.

3.2. Operadores

a) Precedencia de operadores

La precedencia de operadores especifica cómo se agrupan las expresiones. Por ejemplo, en la expresión 1 + 5 * 3, la respuesta es 16 y no 18 porque el operador de multiplicación ("*") tiene una mayor precedencia que el de adición ("+"). La siguiente tabla lista la precedencia de operadores, indicándose primero los de menor precedencia. Asociatividad Operadores izquierda , izquierda or izquierda xor izquierda and derecha print izquierda = += -= *= /= .= %= &= |= ^= ~= <<= >>= izquierda ? : izquierda || izquierda && izquierda | izquierda ^ izquierda & no asociativo == != ===

UD5 – El lenguaje PHP 3.- Operadores y estructuras de control

27 / 110

no asociativo < <= > >= izquierda << >> izquierda + - . izquierda * / % derecha ! ~ ++ -- (int) (double) (string) (array) (object) @ derecha [ no asociativo new no asociativo () La asociatividad de un operador indica en qué orden son evaluados las operaciones con el mismo grado de precedencia. La asociatividad puede ser realizada en dos direcciones de izquierda a derecha o de derecha a izquierda. b) Operadores aritméticos

Son los operadores más sencillos y más comunes. Suelen ser usados bastante dentro de cualquier programa. ejemplo nombre resultado $a + $b Adición Suma de $a y $b. $a - $b Substracción Diferencia entre $a y $b. $a * $b Multiplicación Producto de $a and $b. $a / $b División Cociente de $a entre $b. $a % $b Módulo Resto de $a dividido entre $b. Algunas notas importantes:

o El operador Módulo sólo tiene sentido si ambos operandos son números enteros pues, a fin de cuentas, devuelve el resto de la división entera. Por tanto el tipo del resultado también será un entero.

o El operador división puede funcionar de dos formas dependiendo del tipo de los operandos. Si los dos operandos son números enteros, entonces dará por resultado el cociente de la división entera (es decir, sin decimales) y por tanto el resultado también será un número entero. En cambio, si alguno de los dos operandos en un número en coma flotante, el resultado es la división entre números reales y devolverá un real (es decir, un número con decimales).

c) Operadores de asignación

El operador básico de asignación es "=" (distinto al operador de comparación "igual que"). Pero no. Significa, por tanto, que el operando de la izquierda toma el valor de la expresión a la derecha.

El valor de una expresión de asignación es el propio valor asignado. Esto es, el valor de "$a = 3" es 3. Esto permite hacer cosas curiosas como:

$a = ($b = 4) + 5; // ahora $a es igual a 9, y $b vale 4.

Además del operador básico de asignación, existen los "operadores combinados" para todas las operaciones aritméticas y de cadenas que sean binarias. Este operador combinado te permite, de una sola vez, usar una variable en una expresión y luego establecer el valor de esa variable al resultado de la expresión. ejemplo nombre resultado $a = $b Asignación $a toma el valor de $b $a += $b Suma y asignación $a = $a + $b $a *= $b Multiplicación y asignación $a = $a * $b $a /= $b División y asignación $a = $a / $b $a .= $b Concatenación y asignación $a = $a . $b

UD5 – El lenguaje PHP 3.- Operadores y estructuras de control

28 / 110

Veamos algunos ejemplos:

$a = 3; $a += 5; // establece $a a 8, como si hubiésemos escrito: $a = $a + 5; $b = "Hola "; $b .= "Ahí!"; // establece $b a "Hola Ahí!", igual que si hiciésemos $b = $b . "Ahí!";

Fíjate en que la asignación realiza una nueva copia de la variable original (asignación por valor), por lo que cambios a la variable original no afectan a la copia. d) Operadores de incremento/decremento

PHP soporta los operadores de pre/post incremento/decremento al estilo de C. ejemplo nombre efecto ++$a Preincremento Incrementa $a en uno y después devuelve $a. $a++ Postincremento Devuelve $a y después incrementa $a en uno. --$a Predecremento Decrementa $a en uno y después devuelve $a. $a-- Postdecremento Devuelve $a y después decrementa $a en uno. He aquí un listado de ejemplo:

<?php echo "<h3>Postincremento</h3>"; $a = 5; echo "Debería ser 5: " . $a++ . "<br>\n"; echo "Debería ser 6: " . $a . "<br>\n"; echo "<h3>Preincremento</h3>"; $a = 5; echo "Debería ser 6: " . ++$a . "<br>\n"; echo "Debería ser 6: " . $a . "<br>\n"; echo "<h3>Postdecremento</h3>"; $a = 5; echo "Debería ser 5: " . $a-- . "<br>\n"; echo "Debería ser 4: " . $a . "<br>\n"; echo "<h3>Predecremento</h3>"; $a = 5; echo "Debería ser 4: " . --$a . "<br>\n"; echo "Debería ser 4: " . $a . "<br>\n"; ?> e) Operadores lógicos

Al igual que los operadores aritméticos, los operadores lógicos ocupan un gran protagonismo dentro de cualquier aplicación pues proporcionan un método para la toma de decisiones basado en el cumplimiento o no de ciertas condiciones. ejemplo nombre resultado $a and $b Y Cierto si tanto $a como $b son ciertos. $a or $b O Cierto si $a o $b son ciertos. $a xor $b O exclusiva Cierto si $a es cierto o $b es cierto, pero no ambos a la vez. ! $a Negación Cierto si $a no es cierto. $a && $b Y Cierto si tanto $a como $b son ciertos. $a || $b O Cierto si $a o $b son ciertos.

UD5 – El lenguaje PHP 3.- Operadores y estructuras de control

29 / 110

La razón de las dos variaciones de "y" y "o" es que operan con distinta precedencia (ver Precedencia de Operadores.) f) Operadores de comparación

Los operadores de comparación, como su nombre indica, permiten comparar dos valores. Operadores de Comparación ejemplo nombre resultado $a == $b Igualdad Cierto si $a es igual a $b. $a === $b Identidad Cierto si $a es igual a $b y si son del mismo tipo (sólo PHP4) $a != $b Desigualdad Cierto si $a no es igual a $b. $a < $b Menor que Cierto si $a es estrictamente menor que $b. $a > $b Mayor que Cierto si $a es estrictamente mayor que $b. $a <= $b Menor o igual que Cierto si $a es menor o igual que $b. $a >= $b Mayor o igual que Cierto si $a es mayor o igual que $b. Otro operador condicional es el operador "?:" (o ternario), que funciona como en C y otros muchos lenguajes. (expr1) ? (expr2) : (expr3); La expresión toma el valor expr2 si expr1 se evalúa a cierto, y expr3 si expr1 se evalúa a falso. g) Operadores bit a bit

Los operadores bit a bit te permiten activar o desactivar bits individuales de un entero. ejemplo nombre resultado $a & $b Y Se activan los bits que están activos tanto en $a como $b. $a | $b O Se activan los bits que están activos en $a o que lo están en $b. $a ^ $b Xor ("o exclusiva") Se activan los bits que están activos en $a o en $b pero no en

ambos a la vez. ~ $a No Se activan los bits que no están activos en $a. $a << $b Desplazamiento a

la izquierda Desplaza los bits de $a, $b posiciones hacia la izquierda (por aritmética binaria, cada posición desplazada equivale a multiplicar por dos el valor de $a)

$a >> $b Desplazamiento a la derecha

Desplaza los bits de $a, $b posiciones hacia la derecha (por aritmética binaria, cada posición desplazada equivale a dividir entre dos el valor de $a)

Nota: Un bit activo es un bit a 1. h) Operadores de cadenas

Hay dos operadores de cadenas. El primero es el operador de concatenación ('.'), que devuelve el resultado de concatenar sus operandos izquierdo y derecho. El segundo es el operador de concatenación y asignación ('.='), visto ya en los operadores de asignación. $a = "Hola "; $b = $a . "Mundo!"; // ahora $b contiene "Hola Mundo!" $a = "Hola "; $a .= "Mundo!"; // ahora $a contiene "Hola Mundo!"

3.3. Estructuras de Control

Todo archivo de comandos PHP se compone de una serie de sentencias. Una sentencia puede ser una asignación, una llamada a función, un bucle, una sentencia condicional e incluso una sentencia que no haga nada (una sentencia vacía). Las sentencias normalmente acaban con punto y coma. Además, las sentencias se pueden agrupar en grupos de sentencias encapsulando

UD5 – El lenguaje PHP 3.- Operadores y estructuras de control

30 / 110

un grupo de sentencias con llaves. Un grupo de sentencias es también una sentencia. En este capítulo se describen los diferentes tipos de sentencias. if

La construcción if es una de las más importantes características de muchos lenguajes, incluido PHP. Permite la ejecución condicional de fragmentos de código. PHP caracteriza una estructura if que es similar a la de C:

if (expr) sentencia

Como se describe en la sección sobre expresiones, expr se evalúa a su valor condicional. Si expr se evalúa como TRUE, PHP ejecutará la sentencia, y si se evalúa como FALSE la ignorará. El siguiente ejemplo mostraría a es mayor que b si $a fuera mayor que $b: if ($a > $b) print "a es mayor que b";

A menudo, se desea tener más de una sentencia ejecutada de forma condicional. Por supuesto, no hay necesidad de encerrar cada sentencia con una cláusula if. En vez de eso, se pueden agrupar varias sentencias en un grupo de sentencias. Por ejemplo, este código mostraría a es mayor que b si $a fuera mayor que $b, y entonces asignaría el valor de $a a $b:

if ($a > $b) { print "a es mayor que b"; $b = $a; }

Las sentencias if se pueden anidar indefinidamente dentro de otras sentencias if, lo cual proporciona una flexibilidad completa para ejecuciones condicionales en las diferentes partes del programa. else

A menudo queremos ejecutar una sentencia si se cumple una cierta condicion, y una sentencia distinta si la condición no se cumple. Esto es para lo que sirve else. La sentencia else se ejecuta solamente si la expresión if se evalúa como FALSE.. Por ejemplo, el siguiente código mostraría a es mayor que b si $a fuera mayor que $b, y a NO es mayor que b en cualquier otro caso:

if ($a > $b) { print "a es mayor que b"; } else { print "a NO es mayor que b"; } elseif

elseif, como su nombre sugiere, es una combinación de if y else. Como else, extiende una sentencia if para ejecutar una sentencia diferente en caso de que la expresión if original se evalúe como FALSE. No obstante, a diferencia de else, ejecutará esa expresión alternativa solamente si la expresión condicional elseif se evalúa como TRUE. Por ejemplo, el siguiente código mostraría a es mayor que b, a es igual a b o a es menor que b:

if ($a > $b) { print "a es mayor que b"; } elseif ($a == $b) { print "a es igual que b"; }

UD5 – El lenguaje PHP 3.- Operadores y estructuras de control

31 / 110

else { print "a es mayor que b"; }

Pueden haber varios elseif’s dentro de la misma sentencia if. La primera expresión elseif (si hay alguna) que se evalúe como TRUE se ejecutaría. En PHP, también se puede escribir 'else if' (con dos palabras) y el comportamiento sería idéntico al de un 'elseif' (una sola palabra).

En resumen, la sentencia elseif se ejecuta sólo si la expresión if precedente y cualquier expresión elseif precedente se evalúan como FALSE, y la expresión elseif actual se evalúa como TRUE. Nota: Sintaxis alternativa de estructuras de control

PHP ofrece una sintaxis alternativa para alguna de sus estructuras de control; a saber, if, while, for, y switch. En cada caso, la forma básica de la sintaxis alternativa es cambiar abrir-llave por dos puntos (:) y cerrar-llave por endif;, endwhile;, endfor;, or endswitch;, respectivamente.

<?php if ($a==5): ?> A es igual a 5 <?php endif; ?>

En el ejemplo de arriba, el bloque HTML "A = 5" se anida dentro de una sentencia if escrita en la sintaxis alternativa. El bloque HTML se mostraría solamente si $a fuera igual a 5. La sintaxis alternativa se aplica a else y también a elseif. La siguiente es una estructura if con elseif y else en el formato alternativo: if ($a == 5): print "a es igual a 5"; print "..."; elseif ($a == 6): print "a es igual a 6"; print "!!!"; else: print "a no es ni 5 ni 6"; endif; while

Los bucles while son los tipos de bucle más simples en PHP. Se comportan como su como en C. La forma básica de una sentencia while es:

while (expr) sentencia

El significado de una sentencia while es simple. Le dice a PHP que ejecute la(s) sentencia(s) anidada(s) repetidamente, mientras la expresión while se evalúe como TRUE. El valor de la expresión es comprobado cada vez al principio del bucle, así que incluso si este valor cambia durante la ejecución de la(s) sentencia(s) anidada(s), la ejecución no parará hasta el fin de la iteración (cada vez que PHP ejecuta las sentencias en el bucle es una iteración). Puede ocurrir que la expresión while se evalúe como FALSE desde el principio del todo, en ese caso la(s) sentencia(s) anidada(s) no se ejecutarán ni siquiera una vez.

Como con la sentencia if, se pueden agrupar múltiples sentencias dentro del mismo bucle

while encerrando un grupo de sentencias con llaves, o usando la sintaxis alternativa:

while (expr): sentencia ... endwhile; Los siguientes ejemplos son idénticos, y ambos imprimen números del 1 al 10:

UD5 – El lenguaje PHP 3.- Operadores y estructuras de control

32 / 110

/* ejemplo 1 */ $i = 1; while ($i <= 10) { print $i++; /* el valor impreso sería $i antes del incremento (post-incremento) */ } /* ejemplo 2 */ $i = 1; while ($i <= 10): print $i; $i++; endwhile; do..while

Los bucles do..while son muy similares a los bucles while, excepto que las condiciones se comprueban al final de cada iteración en vez de al principio. La principal diferencia frente a los bucles regulares while es que se garantiza la ejecución de la primera iteración de un bucle do..while (la condición se comprueba sólo al final de la iteración), mientras que puede no ser necesariamente ejecutada con un bucle while regular (la condición se comprueba al principio de cada iteración, si esta se evalúa como FALSE desde el principio la ejecución del bucle finalizará inmediatamente). Hay una sola sintaxis para los bucles do..while: $i = 0; do { print $i; } while ($i>0);

El bucle de arriba se ejecutaría exactamente una sola vez, después de la primera iteración, cuando la condición se comprueba, se evalúa como FALSE ($i no es más grande que 0) y la ejecución del bucle finaliza.

Los usuarios avanzados de C pueden estar familiarizados con un uso distinto del bucle do..while, para permitir parar la ejecución en medio de los bloques de código, encapsulándolos con do..while(1), y usando la sentencia break. El siguiente fragmento de código demuestra esto:

do { if ($i < 5) { print "i no es lo suficientemente grande"; break; } $i *= $factor; if ($i < $limite_minimo) { break; } print "i es correcto"; ...procesa i... } while(1); for

Los bucles for son los bucles más complejos en PHP. Se comportan como en C. La sintaxis de un bucle for es:

for (expr1; expr2; expr3) sentencia

UD5 – El lenguaje PHP 3.- Operadores y estructuras de control

33 / 110

La primera expresión (expr1) se evalúa (ejecuta) incondicionalmente una vez al principio

del bucle. Al comienzo de cada iteración, se evalúa expr2. Si se evalúa como TRUE, el bucle continúa y las sentencias anidadas se ejecutan. Si se evalúa como FALSE, la ejecución del bucle finaliza. Al final de cada iteración, se evalúa (ejecuta) expr3. Cada una de las expresiones puede estar vacía. Que expr2 esté vacía significa que el bucle debería correr indefinidamente (PHP implícitamente lo considera como TRUE, al igual que C). Esto puede que no sea tan inútil como se podría pensar, puesto que a menudo se quiere salir de un bucle usando una sentencia break condicional en vez de usar la condición de for. Considera los siguientes ejemplos. Todos ellos muestran números del 1 al 10: /* ejemplo 1 */ for ($i = 1; $i <= 10; $i++) { print $i; } /* ejemplo 2 */ for ($i = 1;;$i++) { if ($i > 10) { break; } print $i; } /* ejemplo 3 */ $i = 1; for (;;) { if ($i > 10) { break; } print $i; $i++; } /* ejemplo 4 */ for ($i = 1; $i <= 10; print $i, $i++) ;

Por supuesto, el primer ejemplo parece ser el mas elegante (o quizás el cuarto), pero uno puede descubrir que ser capaz de usar expresiones vacías en bucles for resulta útil en muchas ocasiones.

PHP también soporta la "sintaxis de dos puntos" alternativa para bucles for. for (expr1; expr2; expr3): sentencia; ...; endfor; foreach

PHP4 (PHP3 no) incluye una construcción foreach, tal como perl y algunos otros lenguajes. Esto simplemente da un modo fácil de iterar sobre arrays. Hay dos sintaxis; la segunda es una extensión menor, pero útil de la primera:

foreach(nombre_array as $value) sentencia foreach(nombre_array as $key => $value) sentencia LA VEREMOS CON MÁS DETALLE EN EL TEMA DE VECTORES JUNTO CON LA FUNCIÓN LIST Y EACH

UD5 – El lenguaje PHP 3.- Operadores y estructuras de control

34 / 110

La primera forma recorre el array dado por nombre_array. En cada iteración, el valor del

elemento actual se asigna a $value y el puntero interno del array se avanza en una unidad (así en el siguiente paso, se estará mirando el elemento siguiente).

La segunda manera hace lo mismo, salvo que la clave del elemento actual será asignada a la variable $key en cada iteración. Nota: Cuando foreach comienza su primera ejecución, el puntero interno a la lista (array) se reinicia automáticamente al primer elemento del array. Esto significa que no se necesita llamar a reset() antes de un bucle foreach. Nota: Hay que tener en cuenta que foreach funciona con una copia de la lista (array) especificada y no la lista en si, por ello el puntero de la lista no es modificado como en la construcción each. Puede haber observado que las siguientes son funcionalidades idénticas: reset( $arr ); while( list(,$value ) = each( $arr ) ) { echo "Valor: $value<br>\n"; } foreach( $arr as $value ) { echo "Valor: $value<br>\n"; } Las siguientes también son funcionalidades idénticas: reset( $arr ); while( list( $key, $value ) = each( $arr ) ) { echo "Key: $key; Valor: $value<br>\n"; } foreach( $arr as $key => $value ) { echo "Key: $key; Valor: $value<br>\n"; } Algunos ejemplos más para demostrar su uso: /* foreach ejemplo 1: sólo valor*/ $a = array(1, 2, 3, 17); foreach($a as $v) { print "Valor actual de \$a: $v.\n"; } /* foreach ejemplo 2: valor (con clave impresa para ilustrar) */ $a = array(1, 2, 3, 17); $i = 0; /* sólo para propósitos demostrativos */ foreach($a as $v) { print "\$a[$i] => $k.\n"; } /* foreach ejemplo 3: clave y valor */ $a = array( "uno" => 1, "dos" => 2,

UD5 – El lenguaje PHP 3.- Operadores y estructuras de control

35 / 110

"tres" => 3, "diecisiete" => 17 ); foreach($a as $k => $v) { print "\$a[$k] => $v.\n"; switch

La sentencia switch es similar a una serie de sentencias if en la misma expresión. En muchas ocasiones, se quiere comparar la misma variable (o expresión) con muchos valores diferentes, y ejecutar una parte de código distinta dependiendo de a qué valor es igual. Para ello sirve la sentencia switch.

Los siguientes dos ejemplos son dos modos distintos de escribir la misma cosa, uno usa una serie de sentencias if, y el otro usa la sentencia switch:

if ($i == 0) { print "i es igual a 0"; } if ($i == 1) { print "i es igual a 1"; } if ($i == 2) { print "i es igual a 2"; } switch ($i) { case 0: print "i es igual a 0"; break; case 1: print "i es igual a 1"; break; case 2: print "i es igual a 2"; break; }

Es importante entender cómo se ejecuta la sentencia switch para evitar errores. La sentencia switch ejecuta línea por línea (realmente, sentencia a sentencia). Al comienzo, no se ejecuta código. Sólo cuando se encuentra una sentencia case con un valor que coincide con el valor de la expresión switch PHP comienza a ejecutar las sentencias. PHP continúa ejecutando las sentencias hasta el final del bloque switch, o la primera vez que vea una sentencia break. Si no se escribe una sentencia break al final de una lista de sentencias case, PHP seguirá ejecutando las sentencias del siguiente case. Por ejemplo:

switch ($i) { case 0: print "i es igual a 0"; case 1: print "i es igual a 1"; case 2: print "i es igual a 2"; }

Aquí, si $i es igual a 0, ¡PHP ejecutaría TODAS las sentecias print! Si $i es igual a 1, PHP ejecutaría las últimas dos sentencias print y sólo si $i es igual a 2, se obtendría la conducta 'esperada' y solamente se mostraría 'i es igual a 2'. Así, es importante no olvidar las sentencias break (incluso aunque pueda querer evitar escribirlas intencionadamente en ciertas circunstancias).

UD5 – El lenguaje PHP 3.- Operadores y estructuras de control

36 / 110

En una sentencia switch, la condición se evalúa sólo una vez y el resultado se compara a

cada sentencia case. En una sentencia elseif, la condición se evalúa otra vez. Si tu condición es más complicada que una comparación simple y/o está en un bucle estrecho, un switch puede ser más rápido.

La lista de sentencias de un case puede también estar vacía, lo cual simplemente pasa el

control a la lista de sentencias del siguiente case. switch ($i) { case 0: case 1: case 2: print "i es menor que 3, pero no negativo"; break; case 3: print "i es 3"; }

Un case especial es el default case. Este case coincide con todo lo que no coincidan los otros case. Por ejemplo:

switch ($i) { case 0: print "i es igual a 0"; break; case 1: print "i es igual a 1"; break; case 2: print "i es igual a 2"; break; default: print "i no es igual a 0, 1 o 2"; }

La expresión case puede ser cualquier expresión que se evalúe a un tipo simple, es decir, números enteros o de punto flotante y cadenas de texto. No se pueden usar aquí ni arrays ni objetos a menos que se conviertan a un tipo simple.

La sintaxis alternativa para las estructuras de control está también soportada con

switch.

switch ($i): case 0: print "i es igual 0"; break; case 1: print "i es igual a 1"; break; case 2: print "i es igual a 2"; break; default: print "i no es igual a 0, 1 o 2"; endswitch;

UD5 – El lenguaje PHP 3.- Operadores y estructuras de control

37 / 110

break break escapa de la estructuras de control iterantes (bucles) actuales: for, while,

do..while, o switch. break accepta un parámetro opcional, el cual determina cuantas estructuras de control hay que escapar. /* Sin usar el argumento opcional. */ $arr = array ('uno', 'dos', 'tres', 'cuatro', 'stop', 'cinco'); while (list (, $val) = each ($arr)) { if ($val == 'stop') { break; /* También hubiera valido poner 'break 1;' */ } echo "$val<br>\n"; } /* Usando el argumento opcional. */ $i = 0; while (++$i) { switch ($i) { case 5: echo "Estamos en \$i=5 <br>\n"; break 1; /* Salir solo del switch. */ case 10: echo "Estamos en \$i=10; saliéndonos <br>\n"; break 2; /* Salir del switch y del while. */ default: break; } } continue

continue se usa dentro de la estructura del bucle para saltar el resto de la iteración actual del bucle y continuar la ejecución al comienzo de la siguiente iteración. continue acepta un parámetro opcional, el cual determina cuantos niveles (bucles) hay que saltar antes de continuar con la ejecución.

$i = 0; while ($i++ < 5) { echo "Fuera<br>\n"; while (1) {

echo "-Medio<br>\n"; while (1)

{ echo "--Dentro<br>\n"; continue 3; } echo "Ésto nunca saldrá.<br>\n"; } echo "Ni tampoco ésto.<br>\n"; }

UD5 – El lenguaje PHP 4.- funciones

38 / 110

4. Funciones

4.1. ¿Qué es una función?

Una función es una sección de código con un propósito específico a la cuál se le asigna un único nombre. Esto permite reutilizar dicha sección de código en varios puntos del programa sin más que llamar a dicha función. Esto es extremadamente útil pues permite que dicha sección de código sea escrita una única vez lo cual facilita el mantenimiento. También incrementa la legibilidad del código y permite la reutilización de código, posteriormente, en otras aplicaciones.

4.2. Definición e invocación de funciones

La creación de funciones en PHP es un proceso bastante sencillo. Se pueden crear funciones desde cualquier punto del código del programa. Sin embargo, por propósitos organizativos, suele resultar conveniente colocar todas las funciones de un script al principio del mismo. Otro método alternativo bastante interesante es el de colocar todas las funciones dentro de un fichero distinto (al que llamaremos librería y que describiremos más adelante). Esto es de lo más conveniente puesto que permite reutilizar funciones en aplicaciones totalmente distintas, sin necesidad de duplicar el código y sin correr el riesgo de que una función esté actualizada en una aplicación y en otra no. Las sintaxis de una función es la que sigue: function foo ($arg_1, $arg_2, ..., $arg_n) { echo "Función de ejemplo.\n"; return $retval; }

El nombre de una función debe seguir las reglas descritas en el capítulo 2 respecto a los identificadores.

Debido a la flexibilidad de PHP respecto a que no es necesario definir los tipos de las

variables, tampoco es necesario especificar el tipo de los argumentos que son pasados a una función. Es cierto que esto tiene sus ventajas, pero hay que tener en cuenta que el motor de PHP no hará comprobaciones para saber si la función podrá manejar los tipos de datos que se le han pasado, pudiendo llevar a resultados inesperados. Algunas notas importantes:

o Cualquier instrucción válida de PHP puede aparecer en el cuerpo de la función, incluso otras funciones y definiciones de clases.

o En PHP3, las funciones deben definirse antes de que se referencien. En PHP4 no existe tal requerimiento.

o PHP no soporta la sobrecarga de funciones, y tampoco es posible redefinir u ocultar funciones previamente declaradas.

o PHP3 no soporta un número variable de parámetros, aunque sí soporta parámetros por defecto. PHP4 soporta ambos y las referencias de las funciones func_num_args(), func_get_arg(), y func_get_args() (Todo esto se verá más adelante).

4.3. Anidamiento de Funciones

PHP permite la declaración de funciones dentro de funciones. Sin embargo esto no produce que éstas últimas estén protegidas, es decir, que sólo puedan ser usadas dentro de la función dónde has sido declarada. PHP nos soporta el concepto de funciones protegidas. Cualquier función, independientemente de dónde haya sido declarada, puede ser llamada desde cualquier parte del programa. De hecho, las funciones anidadas no heredan los parámetros de entrada de la función padre dónde fueron declaradas. De todos modos, el anidamiento de funciones puede ser útil para propósitos de mantenimiento de código y claridad.

UD5 – El lenguaje PHP 4.- funciones

39 / 110

Aunque las funciones anidadas no están protegidas y pueden ser utilizadas desde cualquier punto del programa, no pueden ser llamadas hasta que su función padre haya sido llamada. <?php function pie() { function copyright($nombre,$ano,$correo) { echo "<br><a href='mailto:$correo'>$nombre $ano</a><br>"; } $alineamiento_ini="<center>"; $alineamiento_fin="</center>"; $home="<a href='home.php'>Inicio</a>"; $links="<a href='enlaces.php'>Enlaces</a>"; $contact="<a href='contacta.php'>Contacta con nosotros</a>"; echo <<<HTML $alineamiento_ini\n $home | $links | $contact\n $alineamiento_fin\n HTML; echo "$alineamiento_ini"; copyright("Gabriel Merín","2002","[email protected]"); echo "$alineamiento_fin"; } // Llamada a la función copyright antes de llamar a su función padre copyright("Gabriel Merín","2002","[email protected]"); /* devuelve un error: Fatal error: Call to undefined function: copyright() in c:\phpdev\www\pruebas\fciones_anidadas.php on line 28 */ // Llamada a la función padre pie(); // Ahora ya podemos llamar a la función copyright copyright("Gabriel Merín","2002","[email protected]"); ?>

4.4. Funciones recursivas

El hecho de que una función se llame a sí misma una vez y otra, es lo que se denomina recursividad. Es una poderosa herramienta que, usada convenientemente, permite la resolución de problemas relativamente complejos de una forma rápida y sencilla. Los algoritmos de búsqueda (como la búsqueda binaria/dicotómica), ordenación (Fusión, Quicksort, etc..) y creación de fractales son buenos ejemplos de su utilidad. PHP soporta perfectamente el uso de funciones recursivas. Veamos el típico ejemplo de calcular el factorial de un número de forma recursiva e iterativa: <?php function fact_recur($num)

UD5 – El lenguaje PHP 4.- funciones

40 / 110

{ // Cálculo del factorial de forma recursiva if ($num==0) return 1; else return ($num*fact_recur($num-1)); } function fact_iter($num) { // Cálculo del factorial de forma iterativa $result=1; for($i=$num; $i>0; $i--) $result*=$i; return $result; } // Número del cual queremos calcular el factorial $num=5; // Ambos factoriales deben proporcionar el mismo resultado echo "El factorial de $num es: " , fact_recur($num) , " (forma recursiva)<br>\n"; echo "El factorial de $num es: " , fact_iter($num) , " (forma iterativa)<br>\n"; ?>

Como se puede observar, la forma recursiva suele ser mucho sencilla de implementar. Sólo es necesario fijar un caso base e ir haciendo llamadas recursivas hasta alcanzar el caso base. La forma iterativa (sencilla en este caso) suele ser más complicada de implementar y con bastantes más líneas de código. Pese a que suele ser más deseable usar algoritmos iterativos por un tema de eficiencia computacional, algunos algoritmos requieren una implementación recursiva debido a la alta complejidad que puede resultar la implementación iterativa.

4.5. Parámetros de las funciones

La información puede suministrarse a las funciones mediante la lista de parámetros, una lista de variables y/o constantes separadas por comas. PHP soporta pasar parámetros por valor (el comportamiento por defecto), por referencia, y parámetros por defecto. Además, PHP4 permite una lista de longitud variable de parámetros. Un efecto similar puede conseguirse en PHP3 pasando un array de parámetros a la función: function toma_array($input) { echo "$input[0] + $input[1] = ", $input[0]+$input[1]; } a) Paso de parámetros por referencia

Por defecto, los parámetros de una función se pasan por valor (de manera que si cambias el valor del argumento dentro de la función, no se ve modificado fuera de ella). Si deseas permitir a una función modificar sus parámetros, debes pasarlos por referencia.

Si quieres que un parámetro de una función siempre se pase por referencia, puedes anteponer un ampersand (&) al nombre del parámetro en la definición de la función: function pon_mas_texto(&$string) { $string .= ' y algo más.'; } $str = 'Esto es una cadena, '; pon_mas_texto($str); echo $str; // Saca 'Esto es una cadena, y algo más.'

UD5 – El lenguaje PHP 4.- funciones

41 / 110

Si deseas pasar una variable por referencia a una función que no toma el parámetro por referencia por defecto, puedes anteponer un ampersand al nombre del parámetro en la llamada a la función:

function foo ($bar) { $bar .= ' y algo más.'; } $str = 'Esto es una cadena, '; foo ($str); echo $str; // Saca 'Esto es una cadena, ' foo (&$str); echo $str; // Saca 'Esto es una cadena, y algo más.' b) Parámetros por defecto

Una función puede definir valores por defecto para los parámetros escalares estilo C++: function haz_cafe ($tipo = "cappucino") { return "Hacer una taza de $tipo.\n"; } echo haz_cafe (); echo haz_cafe ("espresso"); La salida del fragmento anterior es: Hacer una taza de cappucino. Hacer una taza de espresso.

El valor por defecto tiene que ser una expresión constante, y no una variable o miembro de una clase.

Destacar que cuando se usan parámetros por defecto, estos tienen que estar a la derecha de cualquier parámetro sin valor por defecto; de otra manera las cosas no funcionarán de la forma esperada. Considera el siguiente fragmento de código: function haz_yogurt ($tipo = "acidophilus", $sabor) { return "Haciendo un bol de $tipo $sabor.\n"; } echo haz_yogurt ("mora"); // No funcionará de la manera esperada La salida del ejemplo anterior es: Warning: Missing argument 2 in call to haz_yogurt() in /usr/local/etc/httpd/htdocs/php3test/functest.html on line 41 Haciendo un bol de mora. Y ahora, compáralo con: function haz_yogurt ($sabor, $tipo = "acidophilus") { return "Haciendo un bol de $tipo $sabor.\n"; } echo haz_yogurt ("mora"); // funciona como se esperaba La salida de este ejemplo es: Haciendo un bol de acidophilus mora.

UD5 – El lenguaje PHP 4.- funciones

42 / 110

c) Lista de longitud variable de parámetros

PHP4 soporta las listas de longitud variable de parámetros en las funciones definidas por el usuario. Es realmente fácil, usando las funciones func_num_args(), func_get_arg(), y func_get_args(). No necesita de ninguna sintaxis especial, y las listas de parámetros pueden ser escritas en la llamada a la función y se comportarán de la manera esperada. func_num_args (PHP 4 ) func_num_args -- Devuelve el número de argumentos pasados a la función. Descripción: int func_num_args ( void ) Devuelve el número de argumentos pasados a la función actual definida por el usuario. func_num_args() generará un aviso si es llamada desde fuera de la definición de la función. func_get_arg (PHP 4 ) func_get_arg -- Devuelve un elemento de la lista de argumentos. Descripción: int func_get_arg ( int arg_num) Devuelve el argumento que está en la posición arg_num en la lista de argumentos de una función definida por el usuario. Los argumentos de la función se cuentan comenzando por la posición cero. func_get_arg() generará un aviso si se llama desde fuera de la definición de la función. Si arg_num es mayor que el número de argumentos pasados realmente, se generará un aviso y func_get_arg() devolverá FALSE. func_get_args (PHP 4 ) func_get_args -- Devuelve un array que contiene la lista de argumentos de una función. Descripción: int func_get_args ( void )

<?php function print_num_args() { $numargs = func_num_args(); echo "Número de argumentos: $numargs\n"; } print_num_args( 1, 2, 3 ); // Saca por pantalla 'Número de argumentos: 3' ?>

<?php function print_args() { $numargs = func_num_args(); for ($i=0; $i<$numargs; $i++) echo “Argumento $I: “,func_get_arg($i),”<br>\n”; } print_args( 1, 2, 3 ); // Saca por pantalla 'Número de argumentos: 3' ?>

UD5 – El lenguaje PHP 4.- funciones

43 / 110

Devuelve un array en el que cada elemento es el miembro correspondiente de la lista de argumentos de la función definida por el usuario actual. func_get_args() generará un aviso si es llamada desde fuera de la definición de la función. d) Devolución de valores

Los valores se retornan usando la instrucción opcional return. Puede devolverse

cualquier tipo de valor, incluyendo listas y objetos. function cuadrado ($num) { return $num * $num; } echo cuadrado (4); // saca '16'.

No puedes devolver múltiples valores desde una función, pero un efecto similar se puede conseguir devolviendo una lista. function numeros() { return array (0, 1, 2); } list ($cero, $uno, $dos) = numeros();

Aunque puede resultar más cómodo quedarnos con el vector (pudiera ser que no supiéramos cuántos elementos nos va a devolver la función): function numeros() { return array (0, 1, 2); } $vect = numeros();

4.6. Funciones Variable

PHP soporta el concepto de funciones variable, esto significa que si una variable tiene unos paréntesis añadidos al final, PHP buscará una función con el mismo nombre que la evaluación de la variable, e intentará ejecutarla. Entre otras cosas, esto te permite implementar retrollamadas (callbacks), tablas de funciones y demás. <?php function nada() { echo "Estamos dentro de la función nada()<br>\n"; } function algo( $arg = ‘’ ) { echo "Estamos dentro de la función algo() a la cual se le ha pasado el parámetro '$arg'.<br>\n"; }

<?php function get_args() { $numargs = func_num_args(); $arg_list = func_get_args(); for ( $i = 0; $i < $numargs; $i++ ) { echo "El argumento $i vale: " . $arg_list[$i] . "<br>\n"; } } foo( 1, 2, 3 );

UD5 – El lenguaje PHP 4.- funciones

44 / 110

$func = 'nada'; $func(); // Esto sacará por pantalla: Estamos dentro de la función nada() $func = 'algo; $func( 'test' ); // Esto sacará por pantalla: // Estamos dentro de la función algo() a la cual se le ha pasado el parámetro 'test'. ?>

4.7. Acceso a variables globales desde funciones

Algo extremadamente importante y dónde uno no suele caer es en el modo de acceder a las variables globales desde funciones. El acceder de forma inapropiada a una variable global dentro de una función llevará a que la función no se comporte de la forma deseada. En el punto 2.9.- VARIABLES – ÁMBITO DE LAS VARIABLES – Variables Globales se explicó el procedimiento para acceder a las variables globales dentro de funciones. Es importante no olvidarlo o de lo contrario nuestras funciones no se comportarán de la forma esperada y no sabremos el por qué.

4.8. Creación De Librerías De Funciones

Las librerías de funciones son una de las maneras más eficientes a la hora de construir aplicaciones.

Por ejemplo, si uno ya ha creado un serie de funciones para obtener y tratar determinados ficheros dentro de un directorio, es probable que esas funciones nos puedan resultar de utilidad en varias aplicaciones o scripts. En vez de estar continuamente copiando y pegando el código de dichas funciones, es mucho más interesante meter todas esas funciones dentro de un fichero aparte. A continuación se le puede dar a ese fichero el nombre lib_manejo_ficheros.php e incluirlo en todos los scripts que requieran el uso de dichas funciones. Ejemplo: <?php // Librería de manejo de ficheros // Última actualización: 20-4-2003 function saca_ficheros($dir) { ... } function saca_directorios($dir) { ... } function saca_todos_fich($dir) { ... } function saca_fich_jpg($dir) { ... } function saca_fich_gif($dir) {

UD5 – El lenguaje PHP 4.- funciones

45 / 110

... } ?> Si ahora queremos incluir la librería anterior dentro nuestro script basta hacer: <?php // Script que muestra todos los ficheros que hay dentro de nuestra web y da trato especial // a los ficheros de imágenes. // Suponiendo que el archivo de librerías estuviera dentro de la carpeta libs, hacemos: include “./libs/lib_manejo_ficheros.php”; // ó require “/libs/lib_manejo_ficheros.php”; .... $vect_fich_jpg=saca_fich_jpg(“./imagenes/”); // sacamos el nombre de nuestras imágenes … … $vect_directories=saca_directorios(“./”) // sacamos los directorios dentro de la carpeta actual ... ?> Tanto include() como require() tienen la misma estructura, aunque su comportamiento no es idéntico. include (path/filename); require (path/filename); ó include “path/filename”; require “path/filename”;

La sentencia require() se sustituye a sí misma con el archivo especificado, tal y como funciona la directiva #include de C (en tiempo de pre-compilación).

La sentencia include() incluye y evalúa el archivo especificado (durante la ejecución del código).

require() no es en realidad una función de PHP; es más una construcción del lenguaje. Está sujeta a algunas reglas distintas de las de funciones. Por ejemplo, require() no esta sujeto a ninguna estructura de control contenedora. Por otro lado, no devuelve ningún valor (con include() sí que es posible, aunque nosotros no lo vamos a ver); intentar leer un valor de retorno de una llamada a un require() resulta en un error del intérprete.

A diferencia de include(), require() siempre leerá el archivo referenciado, incluso si la línea en que está no se ejecuta nunca. Si se quiere incluir condicionalmente un archivo, se usa include(). La sentencia conditional no afecta a require().

De forma similar, las estructuras de bucle no afectan la conducta de require(). Aunque el código contenido en el archivo referenciado está todavía sujeto al bucle, el propio require() sólo ocurre una vez.

Esto significa que no se puede poner una sentencia require() dentro de una estructura de bucle y esperar que incluya el contenido de un archivo distinto en cada iteración. Para hacer esto, usa una sentencia include().

UD5 – El lenguaje PHP 4.- funciones

46 / 110

Debido a que include() es una construcción especial del lenguaje, se debe encerrar dentro de un bloque de sentencias si está dentro de un bloque condicional.

/* Esto es ERRÓNEO y no funcionará como se desea. */ if ($condicion) include($archivo); else include($otro); /* Esto es CORRECTO. */ if ($condicion) { include($archivo); } else { include($otro); }

Un punto importante sobre su funcionamiento es que tanto si un archivo se incluye con include() o se requiere con require(), el intérprete sale del modo PHP y entra en modo HTML al principio del archivo referenciado, y vuelve de nuevo al modo PHP al final. Por esta razón, cualquier código dentro del archivo referenciado que debiera ser ejecutado como código PHP debe ser encerrado dentro de etiquetas válidas de comienzo y fin de PHP.

PHP no soporta la sobrecarga de funciones y eso significa que dos funciones no pueden

estar declaradas con el mismo nombre. Por lo tanto, si una librería con funciones es incluida o requerida varias veces, el parseador dará error alegando a que no se puede redeclarar una función (y dará el error con la primer función que encuentre declarada dos veces). Por tanto, hay que tener mucho cuidado de no incluir o requerir una librería de funciones varias veces dentro de un script, o incluir o requerir dos librerías diferentes pero que compartan el nombre de algunas funciones.

Para hacer la vida del programador un poco más fácil, PHP permite usar require_once()

e include_once() que funcionan igual que las anteriores salvo que antes de requerir o incluir el archivo, primero comprueban si ya se ha requerido o incluido con anterioridad. Si este es el caso, no se requiere o incluye de nuevo.

UD5 – El lenguaje PHP 5.- vectores

47 / 110

5. Vectores En el capítulo 2 se explicó los tipos de vectores existentes en PHP, así como la forma de crearlos, pero no se vieron las posibles formas de recorrerlos. Tampoco se describió la estructura interna de los vectores en PHP. Además de lo anterior, este capítulo pretende introducir algunas de las funciones más interesantes y comúnmente usadas de las que PHP dispone con respecto al tema de vectores.

5.1. Estructura interna de los vectores en PHP

Los vectores en PHP son bastante más complejos que en el resto de lenguajes. Puesto que en PHP el usuario no dispone de herramientas para el manejo dinámico de la memoria, los vectores (y los objetos) tienen que suplir esta carencia. Así, un vector puede funcionar como tal o como lista enlazada, pila, cola, estructura (el struct de C), etc.. Esta flexibilidad que, en principio, puede parecer extremadamente interesante, puede convertirse en un quebradero de cabeza si no se entiende muy bien cómo está montado un vector internamente. El gran problema reside en que no existe demasiada información al respecto y uno tiene que sacarla de entrelíneas, por experiencia propia, foros, etc.. Acostumbrados a trabajar en C o PASCAL, cuando uno define un vector, lo hace de un tamaño determinado. Incluso suponiendo que uno se defina un vector dinámicamente, el tamaño del vector queda fijado. Así si uno hace en C: int vect[25]; // Hemos creado un vector de enteros de 25 elementos int *vect = malloc(sizeof(int)*25); // Hemos creado un vector de enteros, dinámicamente, de 25

// elementos

Pero en ambos casos, la longitud del vector queda fija. Si queremos vectores de longitud variable donde podamos crear y borrar elementos a nuestras anchas, tendremos que acudir a listas enlazadas. En ambos casos vect apunta al inicio del vector. Dicho de otra manera, vect contiene la dirección de memoria dónde está contenido el primer elemento del vector. Además, cuando en C queremos acceder a la posición 5 de dicho vector hacemos: vect[5];

Internamente lo que se hace es multiplicar 5 x los bytes que ocupa un entero y hacer ese desplazamiento a partir de la posición de memoria dónde vect apunta. Toda esta gestión se puede realizar gracias a que se sabe lo que ocupa (en bytes) cada elemento del vector. En PHP, las variables no tienen un tipo fijo. Así, una variable que líneas anteriores se había considerado como un entero, ahora puede estar funcionando como un carácter. Ello conlleva a que no haya ningún tipo de restricción con respecto al tipo de los elementos de un vector. De hecho en la posición 0 puede estar almacenado un número mientras que en la posición 3 puede estar almacenado un vector o una cadena de caracteres. Todo esto implica que el funcionamiento de los vectores en PHP sea mucho más sofisticado que el funcionamiento visto en C. Un vector en PHP no sólo almacena los valores que le damos, también almacena la clave que hace referencia a dicho valor. Veámoslo con un ejemplo: $vect[0]=25; $vect[1]=”hola”;

UD5 – El lenguaje PHP 5.- vectores

48 / 110

$vect[7]=2.25;

o En la posición 0 almacenamos un elemento de tipo entero cuyo valor es 25 y cuya clave es 0.

o En la posición 1 almacenamos un elemento de tipo cadena cuyo valor es hola y cuya clave es 1.

o En la posición 2 almacenamos un elemento de tipo float cuyo valor es 2.25 y cuya clave es 7.

Luego en resumen, lo que se pone entre los corchetes, es la clave que identifica al valor. Lo

elementos se van poniendo en el mismo orden en que se insertan en el vector, independientemente del valor de la clave. $nom_vect[$key]=$value;

Ahora ya se puede entender por qué en PHP existen los llamados vectores asociativos. La

clave no tiene por qué se únicamente numérica, puede ser una cadena de texto. PHP los trata igual. Todo esto permite una flexibilidad enorme. PHP incorpora funciones tanto para ordenar los elementos por valor como para ordenarlos por clave. Incluso incorpora funciones para intercambiar cada valor por su respectiva clave (es decir, las claves pasan a ser valores y los valores pasan a ser claves).

Aunque este sistema puede parecer de lo más extraño, optimiza mucho la implementación

interna de los vectores. Imagina que un programador crea un vector de 10 elementos e introduce los datos de la siguiente manera: $vect[2000]=”Oscar”; $vect[1]=”Margarita”; $vect[50]=”Roberto”; $vect[100]=”David”; $vect[0]=”José”; ¿Qué crees que debe hacer PHP? ¿definir un vector de 2000 elementos? ¿y de qué tamaño? cada elemento puede tener tipos distintos y de tamaños diferentes.

La mejor solución es ir añadiendo elemento a elemento de forma continua tal y cómo se puede ver en la tabla: $vect Posición 0 1 2 3 4 Clave 2000 1 50 100 0 Valor Oscar Margarita Roberto David José De esta forma siempre se le permite al programador acceder por la clave que desee o también se le da la alternativa de recorrer el vector por el orden en que los elementos se insertaron. Esto se verá en detalle dentro del apartado RECORRIDO DE VECTORES. Además de todo lo anterior, es conveniente comentar que cada vector dispone de un puntero interno que apunta al elemento actual. Dicho puntero sólo puede ser manipulado con funciones que PHP suministra. Más adelante veremos la utilidad de dicho puntero.

5.2. Número de elementos dentro de un vector

El conocimiento del tamaño de un vector suele ser muy interesante sobre todo para tema de recorrido de vectores aunque no es imprescindible (PHP suministra métodos para recorrer vectores sin necesidad de conocer el tamaño del vector). Para conocer el número de elementos dentro de un vector, PHP suministra 3 funciones: sizeof(), count() y array_count_values();

UD5 – El lenguaje PHP 5.- vectores

49 / 110

sizeof int sizeof ( array matriz) Devuelve el número de elementos contenidos dentro del vector matriz. Lo que se le pasa a sizeof no tiene por qué ser un vector unidimensional, se le puede pasar una matriz (vector bidimensional) o un vector k-dimensional. Eso sí, sizeof sólo devuelve el número de elementos de la primera dimensión. Veamos un ejemplo: <?php // Vamos a crear un vector unidimensional $vect_uni = array (‘X-men’,’Matrix’,’Simpsons’); sizeof($vect_uni); // Devolverá 3 // Ahora uno bidimensional $vect_bi[‘X-men’][0]=’Lobezno’; $vect_bi[‘X-men’][1]=’Rondador Nocturno’; $vect_bi[‘X-men’][2]=’Coloso’; $vect_bi[‘X-men’][3]=’Tormenta’; $vect_bi[‘X-men’][4]=’Cíclope;’ $vect_bi[‘Matrix’][0]=’Trinity’; $vect_bi[‘Matrix’][1]=’Neo’; $vect_bi[‘Matrix’][2]=’Morpheus’; $vect_bi[‘Simpons’][0]=’Homer’; $vect_bi[‘Simpons’][1]=’Lisa’; $vect_bi[‘Simpons’][2]=’Bart’; $vect_bi[‘Simpons’][3]=’Maggie’; sizeof($vect_bi); // También devolverá 3, pues devuelve el número de elementos de la primera dimensión. // Pero gracias a la flexibilidad de PHP, si dentro de una posición de un vector se encuentra otro // vector, sizeof devuelve el tamaño de ese vector. Veámoslo con el caso anterior: sizeof($vect_bi[‘X-men’]); /* Puesto que en la posición identificada por ‘X-men’ hay un vector y no un valor, sizeof devolverá el número de elementos de ese vector, esto es 5 */ sizeof($vect_bi[‘Matrix’]); /* Ocurrirá lo mismo que en el caso anterior, sólo que ahora con el vector ‘Matrix’. Devolverá, por tanto 3 */ // Si tuviéramos más dimensiones dentro de $vect_bi, podríamos hacer lo mismo sobre cada una // de ellas. ?> count int count ( array matriz) Funciona exactamente igual que sizeof() aunque, a diferencia de la anterior, devuelve un poco más de información:

o Si la variable existe y es un vector (no tiene por qué ser de una dimensión!), count() devolverá el número de elementos contenidos dentro del vector.

o Si la variable existe pero no es un vector, se devolverá el valor 1. o Si la variable no existe, se devolverá el valor 0.

UD5 – El lenguaje PHP 5.- vectores

50 / 110

IMPORTANTE: count() puede devolver 0 para una variable no definida, pero también puede devolver 0 para una variable ya inicializada pero con un vector vacío. Habría que utilizar isset() para comprobar si una variable está definida o no. NOTA: A isset() se le pasa un variable. Si la variable existe devuelve TRUE en caso contrario devuelve FALSE. Si se quisiera destruir una variable, se puede usar la función unset(). array_count_values array array_count_values ( array vector_uni) Esta función es una variante de las dos anteriores. En vez de devolver el número de elementos, cuenta la frecuencia con que se da cada elemento. Para que esta función no de un error, se le ha de pasar un vector unidimensional. Veamos un ejemplo: <?php $notas = array(4,5,4,5,6,8,7,8,9,7,10,4,7,3,2,7,5,6); $c_notas = array_count_values($notas); // Si ahora hacemos: print_r($c_notas); /* En pantalla se nos muestra: Array ( [4] => 3 [5] => 3 [6] => 2 [8] => 2 [7] => 4 [9] => 1 [10] => 1 [3] => 1 [2] => 1 ) Y que significa que el valor 4 está repetido 3 veces, el valor 5 está repetido 3 y así sucesivamente */ // También lo podemos usar para cadenas de texto: $nombres = array(‘Jose’,’Gabriel’,’Paco’,’Jose’,’Manuel’,’Angel’,’Jose’,’Angel’,’Aitana’,’María’); $c_nombres = array_count_values($nombres); print_r($c_nombres); /* En pantalla se nos mostrará: Array ( [Jose] => 3 [Gabriel] => 1 [Paco] => 1 [Manuel] => 1 [Angel] => 2 [Aitana] => 1 [María] => 1 ) La interpretación es que Jose aparece 3 veces, Gabriel aparece 1 vez, y así sucesivamente. */ ?> IMPORTANTE: array_count_values solo funciona con vectores de números enteros o cadenas de caracteres. Si se trata de utilizar con cualquier otra cosa dará el siguiente error: Warning: Can only count STRING and INTEGER values! in c:\phpdev\www\pruebas\sizeof_y_count.php on line 39

5.3. Recorrido de vectores

Hasta el momento, la única forma de recorrer vectores es mediante el uso de bucles (while o for). El único requisito es conocer el número de elementos. Veamos un ejemplo: <?php $vect=array(1,2,3,4,5,6,7,8,9,10); /* Recordemos que cuando creamos un array como está descrito arriba, PHP genera las claves

UD5 – El lenguaje PHP 5.- vectores

51 / 110

automáticamente y es equivalente a hacer: $vect[0] = 1; $vect[1] = 2; … $vect[9] = 10; */ $num_elements = count($vect); for ($i=0; $i<$num_elements; $i++) { // Vamos a mostrar el vector de la siguiente forma: [1, 2, 5, 8, …., N] switch ($i) { case 0: echo “[$i, ”; break; case ($num_elements-1): echo “$i]”; break; default: echo “$i, ”; break; } } // Dará la siguiente salida: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] ?> Este sistema es el más conocido y usado pero debido a la flexibilidad de PHP este sistema tiene algunas pegas. En PHP los vectores NO tienen por qué comenzar en 0. Podríamos crear un vector cuyos índices (recordemos que en PHP se llaman claves) fueran 1, 3, 5, 100, 1000 y 777. Al intentar recorrer el vector de la manera anterior tendríamos un problema: count($vect) devolverá 6 (hay 6 elementos en el vector) y trataríamos de acceder a los elementos 0, 1, 2, 3, 4 y 5. Cómo sólo existen 3 de esos elementos PHP sólo mostraría los elementos cuyas claves existen, en el resto no haría nada.

Si se trata de acceder a un elemento mediante una clave que no existe en el vector, PHP no dará error. Si se trata de imprimir tampoco dará error, simplemente no se mostrará nada. NOTA: Si se trata de acceder a una variable que no está definida (es decir, que no existe), al igual que en el caso de los vectores, PHP no dará ningún error. Lo mismo pasa a la hora de imprimirla por pantalla: PHP no mostrará nada. Además de lo anterior, tenemos un problema adicional: ¿cómo recorremos vectores cuya clave no sea numérica? En el capítulo 2 vimos que en PHP existen vectores asociativos (aquellos cuya clave no es numérica, si no una cadena de texto). En el capítulo 3, cuando se vieron las estructuras de control, se vio de pasada la construcción foreach() que se usa precisamente en estos casos. Además de dicha construcción PHP suministra una larga lista de funciones para jugar y recorrer los vectores. En PHP existen dos formas adicionales a la ya vista. Además son válidas para cualquier tipo de vectores, tanto asociativos como escalares. FOREACH Recordemos su uso mediante un ejemplo: foreach(nombre_array as $value) sentencia foreach(nombre_array as $key => $value) sentencia <?php // Jugamos con el mismo vector que antes $vect=array(1,2,3,4,5,6,7,8,9,10);

UD5 – El lenguaje PHP 5.- vectores

52 / 110

$i=0; foreach($vect as $value) { switch ($i) { case 0: echo "[$value"; break; default: echo ", $value"; break; } $i++; } // Falta cerrar el último corchete echo "]"; ?>

El ejemplo anterior producirá el mismo resultado que cuándo hemos usado el bucle for() pero con una gran diferencia VALE PARA CUALQUIER TIPO DE VECTOR, independientemente de si el vector es asociativo, no asociativo, mixto o no asociativo pero con las claves puestas arbitrariamente. Además, se garantiza el acceder a los datos exactamente en el mismo orden en que fueron insertados en el vector (lo cual puede ser MUY interesante para determinadas tareas). Foreach permite, además, conocer la clave del valor actual. Veamos otro ejemplo; <?php $regiones_dvd = array( 1 => 'USA, Canada, territorios USA ', 2 => 'Japón, Europa, Sur África, Medio Este (incluyendo Egipto)', 3 => 'Sureste de Asia y Este de Asia (incluye Hong Kong)', 4 => 'Australia, Nueva Zelanda, Islas de Pacifico, América Central, Sudamérica, Caribe.', 5 => 'Europa del Este (Unión Soviética), subcontinente Indio, África, Corea del Norte, Mongolia', 6 => 'China', 7 => 'Reservado', 8 => 'Especial para usos internacionales (aviones, cruceros, etc...)' ); foreach($regiones_dvd as $cod_reg => $zona) { // Vamos a mostrar los códigos regionales y su/s respectiva/s zona/s geográfica/s echo "Región $cod_reg: $zona <br>\n"; } ?> Como se puede observar, foreach() simplifica mucho el recorrido de los vectores y permite crear funciones que recorran o jueguen con los vectores independientemente de cómo estén construidos. Es importante comentar que foreach() también funciona bien si cada elemento del vector es, a su vez, un nuevo vector. Veamos un ejemplo: <?php // Cine // Ejemplo con un vector multidimensional que en la primera dimensión guarda los géneros y cada // género almacena un vector asociativo dónde la clave es el nombre de la película y el valor es su // puntuación: $pelis['Terror']=array(

UD5 – El lenguaje PHP 5.- vectores

53 / 110

'The Eye' => 7.5, 'Dark Water' => 8.5, 'DeathWatch' => '?', 'Dreamcatcher' => 7, 'Dog Soldiers' => '?', 'Darkness' => 9 ); $pelis['Comedia']=array( 'Yo yo mismo e Irene' => 8, 'La máscara' => 8.5, 'Colega, Dónde está mi coche?' => 7.5 ); $pelis['Fantasia']=array( 'El señor de los anillos' => 9.8, 'Matrix' => 10, 'Final Fantasy' => 8.75, 'Hero' => 9, 'Legend of Zu' => 8.5 ); // Ahora recorremos el vector foreach($pelis as $nom_genero => $vect_pelis) { // Mostramos primero el género y las películas en él contenidas echo "Género: $nom_genero <br>\n"; // Puesto que cada elemento es un vector, usamos otro foreach foreach($vect_pelis as $nom_peli => $puntuacion) { echo "- $nom_peli | Puntuación: $puntuacion<br>\n"; } // Dejamos otro espacio entre géneros para más claridad echo "<br>\n"; } ?> LIST Y EACH Cuando se habló de la construcción interna de los vectores, se comentó de pasada que cada vector en PHP disponía de un puntero interno. Hasta el momento no hemos visto la utilidad que tiene esto ni cómo manejar dicho puntero. Pues bien, ahora veremos cómo recorrer un vector haciendo uso de dicho puntero. Veamos primero las funciones each() y list() : each (PHP 3, PHP 4 ) each -- Devuelve el par clave/valor actual de una matriz y avanza el puntero de la misma. Descripción: array each ( array matriz) Devuelve el par clave/valor actual para la matriz y avanza el puntero de la misma. Esta pareja se devuele en una matriz de 4 elementos, con las claves 0, 1, key, y value. Los elementos 0 y key contienen el nombre de clave del elemento de la matriz, y 1 y value contienen los datos. Si el puntero interno para la matriz apunta pasado el final del contenido de la matriz, each() devuelve FALSE.

UD5 – El lenguaje PHP 5.- vectores

54 / 110

$tonteria contiene ahora los siguientes pares clave/valor: 0 => 0 1 => 'bob' key => 0 value => 'bob' list (PHP 3, PHP 4 ) list -- Asigna valores a variables que se le pasan, a partir de los elementos de un vector. Descripción: void list ( mixed ...) Como array(), esta no es realmente una función, sino una construcción del lenguaje. list() se usa para asignar una lista de variables en una sola operación. Lo que realmente se hace es dada N variables y un vector, coge los N primeros elementos del vector y los asigna en orden a las N variables.

IMPORTANTE: list() sólo funciona con vectores no asociativos (es decir, cuyas claves son puramente numéricas) o vectores mixtos (con claves numéricas y de texto, aunque se saltará los elementos con clave no numérica). Si se le pasa un vector puramente asociativo, no dará error pero no les asignará nada a las variables pasadas. Como se puede apreciar, list() y each() se complementan perfectamente para recorrer un vector: mientras que each saca la clave y el valor de un elemento, list se lo asigna a las variables que queramos. Veamos un ejemplo:

<?php // Animación Japonesa // Al igual que en el ejemplo de cine, almacenamos en la primera dimensión los géneros // y dentro de cada género metemos un vector asociativo dónde la clave de cada elemento // es el nombre de la película y el valor es la puntuación. $anime=array( 'Accion' => array('Spriggan' => 8, 'X' => 8, 'Akira' => 9, 'Ghost in The Shell' => 10, 'Berserk' => 8.5), 'Comedia' => array('Golden Boy' => 10, 'Ranma 1/2' => 9.5, 'Chobits' => 10), 'Aventuras' => array('Escaflowne' => 9.8, 'Evangelion' => 8, 'Fushigi Yugi' => 7.5) ); echo ".: Películas de Animación Japonesa :.<br><br>\n"; // Ahora lo recorrermos y presentamos adecuadamente los resultados

$chorrada = array ("bob", "fred", "jussi", "jouni", "egon", "marliese"); $tonteria = each ($chorrada);

// Nos definimos un vector con una fecha $fecha = array('2003','Abril',25,12,16,30); // Sólo nos queremos quedar con el año, mes y día pero en variables separadas // para poder trabajar con ellas más comodamente list($ano,$mes,$dia) = $fecha; echo "$dia de $mes de $ano"; // Devolverá: 25 de Abril de 2003

UD5 – El lenguaje PHP 5.- vectores

55 / 110

// A la clave la llamaremos $genero pues es lo que representa // Al valor lo llamaremos $vect_pelis pues, a fin de cuentas, no es un valor, es un vector de pelis reset($anime); // Colocamos el puntero al principio while (list($genero, $vect_pelis) = each($anime)) { echo $genero,"<br>\n"; reset($vect_pelis); // Colocamos el puntero al principio while (list($nom_peli, $puntuacion) = each($vect_pelis)) { echo "::: $nom_peli => $puntuacion<br>\n"; } // Dejamos un espacio más entre género y género echo "<br>\n"; } ?>

Aunque este método de recorrer vectores es muy similar al realizado con foreach(), hay algunas diferencias significativas que hay que comentar:

⇒ foreach usa una copia del vector y por tanto no modifica la posición interna del puntero del vector. Además, nada más hacer la copia, hace un reset() para colocar el puntero al principio del vector.

⇒ each va modificando el puntero interno del vector y, por lo tanto, cuando acaba de recorrer el vector, el puntero apunta al último elemento. Además, si cortamos la ejecución del bucle a mitad del while, el puntero se quedará apuntando al elemento siguiente del último elemento accedido. Siempre que comencemos a recorrer un vector con each y list hay que hacer un reset del vector puesto que nadie nos garantiza que el puntero interno apunte al primer elemento.

A parte de reset, existen otras funciones que permiten mover el puntero interno hacia la

posición que más nos convenga: reset (PHP 3, PHP 4 ) reset -- Coloca el puntero interno de una matriz a su primer elemento y devuelve el valor de éste. Descripción: mixed reset ( array matriz) reset() retrocede el puntero interno de la matriz a su primer elemento y devuelve el valor del primer elemento de la matriz (sólo el valor, no su clave). end (PHP 3, PHP 4 ) end -- Mueve el puntero interno de una tabla al último elemento Descripción: mixed end ( array matriz) end() avanza el puntero interno de la matriz al último elemento y devuelve el valor del último elemento. current (PHP 3, PHP 4 )

UD5 – El lenguaje PHP 5.- vectores

56 / 110

current -- Devuelve el valor del elemento actual de una matriz apuntado por el vector interno Descripción: mixed current ( array matriz) current() devuelve el elemento de la tabla al que apunta el puntero interno. No mueve el puntero de ninguna manera. Si el puntero interno apunta fuera del final de la lista de elementos, current() devuelve FALSE. AVISO: Si la matriz contiene elementos vacíos (0 ó "", la cadena vacía) esta función devolverá FALSE para dichos elementos. Esto hace imposible determinar si se está realmente al final de la lista en tales matrices usando current(). Para recorrer adecuadamente una matriz que pueda contener elementos vacíos, utilice la función each(). next (PHP 3, PHP 4 ) next -- Avanza el puntero interno de una matriz al siguiente elemento y devuelve su valor Descripción: mixed next ( array matriz) Devuelve el elemento de la matriz que ocupa el lugar siguiente al apuntado por el puntero interno, o FALSE si no hay más elementos. next() se comporta como current(), con una diferencia. Avanza el puntero interno de la matriz en una posición antes de devolver el elemento. Eso significa que devuelve el siguiente elemento de la matriz y que avanza el puntero interno en uno. Si al avanzar se pasa del final de la lista de elementos, next() devuelve FALSE. AVISO: Si la matriz contiene elementos vacíos (0 ó "", la cadena vacía) esta función devolverá FALSE para dichos elementos. Esto hace imposible determinar si se está realmente al final de la lista en tales matrices usando current(). Para recorrer adecuadamente una matriz que pueda contener elementos vacíos, utilice la función each(). prev (PHP 3, PHP 4 ) prev -- Retrocede el puntero interno de una matriz al elemento anterior y devuelve su valor Descripción: mixed prev ( array matriz) Retrocede el puntero interno al elemento anterior al que previamente apuntaba y devuelve su valor. Si no hay más elementos devuelve FALSE. AVISO: Si la matriz contiene elementos vacíos (0 ó "", la cadena vacía) esta función devolverá FALSE para dichos elementos. Esto hace imposible determinar si se está realmente al final de la lista en tales matrices usando current(). Para recorrer adecuadamente una matriz que pueda contener elementos vacíos, utilice la función each(). key (PHP 3, PHP 4 ) key – Devuelve el valor de la clave del elemento actual apuntado por el vector interno Descripción:

UD5 – El lenguaje PHP 5.- vectores

57 / 110

mixed key ( array matriz) key() devuelve el valor de la clave del elemento apuntado por el vector interno. No modifica la posición del puntero interno. Si el puntero interno apunta fuera del final de la lista de elementos, current() devuelve FALSE. A diferencia de current(), si el elemento actual apuntado tiene un valor vacío (0 ó "", la cadena vacía) la clave se devuelve correctamente. A parte de estas funciones, existe una última llamada array_walk() que permite aplicar una función a cada elemento del vector. Esto puede ser extremadamente útil si, por ejemplo, tenemos que elevar al cuadrado todos los elementos, pasar todos los elementos a mayúsculas/minúsculas, o eliminar elementos que no cumplan alguna condición. array_walk (PHP 3>= 3.0.3, PHP 4 ) array_walk -- Aplica una función del usuario a cada elemento de una matriz. Descripción: int array_walk ( array vector, string func, mixed datosvarios) Aplica la función llamada func a cada elemento del vector. La función func recibirá el valor del elemento actual como primer parámetro y la clave como segundo. Si se proporciona el parámetro datosvarios será pasado como tercer parámetro a la función de usuario. Si func necesita más de dos o 3 argumentos, dependiendo de datosvarios, se generará un aviso cada vez que array_walk() llama a func. Estos avisos pueden suprimirse si se pone '@' antes de la llamada a array_walk(), o usando la función error_reporting(). Nota: Si func precisa trabajar con los valores reales del vector, especifique que el valor del primer parámetro de func debe pasarse por referencia. Desde ese instante, los cambios realizados sobre dichos elementos también serán realizados en el propio vector. Nota: El pasar la clave y los datos de usuario a func fue una característica añadida en PHP 4.0. En PHP 4 se debe llamar reset() las veces necesarias, pues array_walk() no coloca el puntero interno al principio del vector al inicio de ejecución.

<?php function test_alterar (&$item1, $clave, $prefix) { $item1 = "$prefix: $item1"; } function test_ver ($item2, $clave) { echo "$clave. $item2<br>\n"; } $frutas = array ("l"=>"limón", "n"=>"naranja", "p"=>"plátano", "m"=>"manzana"); reset ($frutas); // Este reset no haría falta pues siempre que un vector es creado, el puntero interno // apunta a la primer elemento. array_walk ($frutas, 'test_ver'); reset ($frutas); array_walk ($frutas, 'test_alterar', 'fruta'); // Dejamos un línea de espacio echo "<br>\n"; reset ($frutas); array_walk ($frutas, 'test_ver');

UD5 – El lenguaje PHP 5.- vectores

58 / 110

5.4. Búsqueda de elementos dentro de un vector

Existen, fundamentalmente, dos funciones que permiten buscar un elemento dentro de un vector. Estas dos funciones son array_search() y in_array(). Aunque devuelven cosas distintas, su misión es, dado un valor, buscar si algún elemento dentro del vector tiene ese mismo valor. Puesto que también puede ser interesante buscar una clave en vez de un valor, PHP suministra la siguiente función: array_key_exists() que realiza una función similar a la anterior sólo que con las claves del vector. in_array (PHP 4 ) in_array -- Devuelve TRUE si un valor está en una vector Descripción: bool in_array ( mixed aguja, array pajar) Busca la aguja en el pajar, y devuelve TRUE si se encuentra y FALSE en caso contrario. NOTA: Se busca EXACTAMENTE la aguja. Eso significa que si es una cadena de caracteres, las cadenas deben ser idénticas (sensible a mayúsculas y minúsculas). Las expresiones regulares2 no están permitidas. array_search (PHP 4 >= 4.0.5) array_search -- Busca dentro de un vector un determinado valor y devuelve la clave si se encuentra Descripción: mixed array_search ( mixed aguja, array pajar [, bool strict]) Busca la aguja en el pajar y devuelve el valor de la clave si se encuentra, si no se devuelve FALSE. NOTA: En versiones anteriores a PHP 4.2.0, array_search() devuelve NULL en vez de FALSE. Si el tercer parámetro opcional strict se pone a TRUE entonces array_search() comprobará también los tipos de la aguja y los elementos del pajar. Es decir, para que la búsqueda acabe con éxito no sólo se ha de encontrar la aguja, los elementos deben coincidir también en el tipo. Tampoco se permite el uso de expresiones regulares. array_key_exists (PHP 4 >= 4.1.0) array_key_exists -- Comprueba si la clave dada existe en el vector Descripción: bool array_key_exists ( mixed clave, array vector) array_key_exists() devuelve TRUE si la clave dada se encuentra en el vector. La clave buscada puede ser tanto numérica como de texto. NOTA: Tampoco están permitidas las expresiones regulares.

2 Las expresiones regulares permiten comprobar si un string cumple un determinado patrón. Por ejemplo que la primera letra comience por “a”, que acabe en “ia” o que contenga el trozo “orden”.

UD5 – El lenguaje PHP 5.- vectores

59 / 110

5.5. Ordenación de vectores

Puesto que en la gran mayoría de los casos usaremos vectores para albergar cantidades grandes información (nombres de usuarios, de ficheros etc...), el poder realizar ordenaciones es una necesidad importante (sobre todo a la hora de mostrar los datos al usuario). Siempre podemos implementar nuestras propias funciones de ordenación: quicksort, mergesort, etc... Pero, para simplificarnos la vida, PHP ya lleva implementadas unas cuantas funciones que realizan estas tareas. sort y rsort Son las funciones más básicas de ordenación. Las dos funciones son idénticas salvo que una ordena en sentido ascendente (sort) y la otra en sentido descendente (rsort – reverse sort). void sort ( array vector) void rsort ( array vector)

Es muy importante comentar al realizar la ordenación NO se mantiene la relación clave/valor. Veámoslo con un ejemplo: <?php // Con vector no asociativo $vect = array ('banana', 'pera', 'manzana', 'kiwi', 'uva', 'mango', 'paraguaya'); // Imprimimos el vector antes de ordenarlo print_r($vect); /* Dará por pantalla: Array ( [0] => banana [1] => pera [2] => manzana [3] => kiwi [4] => uva [5] => mango [6] => paraguaya ) */ // Ordenamos el vector sort($vect); // Dejamos algo de espacio echo "<br><br>\n"; // Ahora imprimimos el vector ya ordenado print_r($vect); /* Dará por pantalla: Array ( [0] => banana [1] => kiwi [2] => mango [3] => manzana [4] => paraguaya [5] => pera [6] => uva ) */ ?> Como se puede observar en el ejemplo, la relación clave = 2 | valor = manzana se pierde al hacer la ordenación. Ahora manzana tiene por clave 3 y ocupa la posición 3. Si tratamos de hacer lo mismo pero con un vector asociativo, nos encontramos con lo siguiente: <?php // Con un vector asociativo $vect = array ("Spriggan" => 7.5, "Akira" => 9, "3x3 Ojos" => 8, "Shadow Skill" => '?'); // Imprimimos el vector antes de ordenarlo print_r($vect); /* Dará por pantalla:

UD5 – El lenguaje PHP 5.- vectores

60 / 110

Array ( [Spriggan] => 7.5 [Akira] => 9 [3x3 Ojos] => 8 [Shadow Skill] => ? ) */ // Ordenamos el vector sort($vect); // Dejamos algo de espacio echo "<br><br>\n"; // Ahora imprimimos el vector ya ordenado print_r($vect); /* Dará por pantalla: Array ( [0] => ? [1] => 7.5 [2] => 8 [3] => 9 ) */ ?> Todas las claves de texto se pierden y se sustituyen por claves numéricas. Ahora cada clave coincide con la posición que cada elemento ocupa dentro del vector ordenado. IMPORTANTE: El vector que se le pase a sort() debe ser un vector unidimensional, si no PHP dará un error (sólo se ordena la primera dimensión). asort y arsort Funcionan de forma similar a las dos anteriores: asort ordena ascendentemente y arsort descendentemente. La diferencia estriba en que aquí SÍ que se mantiene la relación clave/valor. void asort ( array vector) void arsort ( array vector) Veamos un ejemplo de su funcionamiento: <?php // Con vector no asociativo $vect = array ('banana', 'pera', 'manzana', 'kiwi', 'uva', 'mango', 'paraguaya'); // Imprimimos el vector antes de ordenarlo print_r($vect); /* Dará por pantalla: Array ( [0] => banana [1] => pera [2] => manzana [3] => kiwi [4] => uva [5] => mango [6] => paraguaya ) */ // Ordenamos el vector asort($vect); // Dejamos algo de espacio echo "<br><br>\n"; // Ahora imprimimos el vector ya ordenado print_r($vect); /* Dará por pantalla: Array ( [0] => banana [3] => kiwi [5] => mango [2] => manzana [6] => paraguaya [1] => pera [4] => uva ) */ ?>

UD5 – El lenguaje PHP 5.- vectores

61 / 110

Ahora las claves sí que se mantienen asociadas a su valor. Veamos un último ejemplo con un vector asociativo: <?php // Con un vector asociativo $vect = array ("Spriggan" => 7.5, "Akira" => 9, "3x3 Ojos" => 8, "Shadow Skill" => '?'); // Imprimimos el vector antes de ordenarlo print_r($vect); /* Dará por pantalla: Array ( [Spriggan] => 7.5 [Akira] => 9 [3x3 Ojos] => 8 [Shadow Skill] => ? ) */ // Ordenamos el vector asort($vect); // Dejamos algo de espacio echo "<br><br>\n"; // Ahora imprimimos el vector ya ordenado print_r($vect); /* Dará por pantalla: Array ( [Shadow Skill] => ? [Spriggan] => 7.5 [3x3 Ojos] => 8 [Akira] => 9 ) */ ?> ksort y rksort Hasta ahora venimos ordenando valores pero más importante que ordenar por valores puede serlo ordenar por claves. En el último ejemplo visto estábamos ordenando un vector que contenía películas de animación (clave) y la puntuación respectiva (valor). Puede ser igual de interesante hacer la ordenación por puntuación que por el nombre de las películas. Pensemos que si el usuario quiere buscar una película en particular le resultará más sencillo encontrarla si las películas se muestran ordenadas por nombre que por la puntuación. Como de costumbre, ksort ordena el vector por claves ascendentemente mientras que rksort lo hace descendentemente. void ksort ( array vector) void krsort ( array vector)

Por descontado que aquí SE MANTIENE la relación clave/valor, si no esto no tendría sentido. Veamos un ejemplo: <?php // Vector asociativo de películas $pelis = array( 'Memento' => 9.5, 'El viaje de Chihiro' => 8.5, 'El paciente inglés' => 8, 'El cazador de Sueños' => 7, 'Star Wars: El ataque de los clones' => 7.7 ); // Mostramos el vector antes de ordenarlo print_r($pelis);

UD5 – El lenguaje PHP 5.- vectores

62 / 110

/* Salida por pantalla: Array ( [Memento] => 9.5 [El viaje de Chihiro] => 8.5 [El paciente inglés] => 8 [El cazador de Sueños] => 7 [Star Wars: El ataque de los clones] => 7.7 ) */ // Ordenamos ascendentemente por clave ksort($pelis); // Dejamos un poco de espacio echo "<br><br>\n"; // Imprimimos el vector ya ordenado print_r($pelis); /* Salida por pantalla Array ( [El cazador de Sueños] => 7 [El paciente inglés] => 8 [El viaje de Chihiro] => 8.5 [Memento] => 9.5 [Star Wars: El ataque de los clones] => 7.7 ) */ ?> usort, uasort y uksort

A parte de las funciones ya vistas, existen otras tres que permiten realizar ordenaciones según nuestro propio criterio. void usort ( array vector, function func_comparar) void uasort ( array vector, function func_comparar) void uksort ( array vector, function func_comparar) La diferencia entre las tres es sencilla:

o usort ordena por valores SIN mantener la relación clave/valor. o uasort ordena por valores MANTENIENDO la relación clave/valor. o uksort ordena por claves MANTENIENDO la relación clave/valor.

Estas funciones ordenaran un vector utilizando una función suministrada por el usuario.

La función de comparación deberá devolver un entero menor, igual, o mayor que cero, si el primer argumento se considera respectivamente menor que, igual que, o mayor que el segundo. Si dos miembros resultan ser iguales, su orden en la matriz ordenada será cualquiera.

Resumiendo, la idea es suministrarle una función que indique como quedarían un par de

valores ordenados (llamémosles $a y $b):

o Si la función de usuario devuelve 0 ⇒ da igual el orden de $a y $b o Si devuelve un nº > 0 ⇒ primero $a y luego $b o Si devuelve un nº < 0 ⇒ primero $b y luego $a

Por ejemplo, nos puede interesar ordenar un vector en función del tamaño de la cadena de

texto. Es decir, lo que queremos es que las cadenas más cortas estén al principio y las más largas al final del vector. Luego en nuestro caso:

o Si la longitud de la cadena $a es menor que la longitud de la cadena $b, $a irá antes que $b

o Si la longitud es idéntica, nos da igual el orden o Si la longitud de la cadena $a es mayor que la longitud de la cadena $b, $b irá antes que

$a Después de desmenuzar al completo este ejemplo, veamos su implementación: <?php

UD5 – El lenguaje PHP 5.- vectores

63 / 110

// Función que imprime el vector dado function imprime_vector($vect) { foreach($vect as $valor) echo $valor, " | ", strlen($valor), " letras. <br>\n"; } function ord_tam_cad($a, $b) { // Primero sacamos el tamaño de cada cadena. // Para ello usaremos la función strlen que devuelve el tamaño de una cadena de caracteres. $tam_a = strlen($a); $tam_b = strlen($b); // Si las cadenas tienen el mismo tamaño, nos da igual el orden if ($tam_a == $tam_b) return 0; // Si $a es más grande que $b, entonces primero $a y luego $b if ($tam_a > $tam_b) return 1; // en caso contrario, primero $b y luego $a else return -1; } // Nos definimos un vector de nombres $vect_nombres = array ('Ana', 'Jose', 'Paco', 'Rafael', 'Miguel', 'Roberto', 'Vicente', 'María', 'Laura', 'Rosa', 'Gabriel'); // Imprimimos antes de ordenar imprime_vector($vect_nombres); // Vamos a hacer una ordenación por el tamaño de los nombres. // Primero irán los cortos y luego los largos: usort($vect_nombres, "ord_tam_cad"); // Dejamos un par de líneas en blanco echo "<br><br>\n"; // Imprimimos el vector ordenado imprime_vector($vect_nombres); ?>

5.6. Adición y eliminación de elementos (pilas y colas)

En lenguajes como el C, uno no puede “eliminar” elementos de un vector. Una vez que uno crea el vector (estática o dinámicamente), el vector es una unidad. Si el vector es de 10 elementos, no podemos hacer que ahora su tamaño sea 6 (bueno, no al menos de forma directa). El caso es distinto cuando trabajamos con listas enlazadas. Puesto que cada elemento es una entidad diferente, basta con colocarse sobre el nodo a eliminar, actualizar los punteros y luego proceder a su borrado. Puesto que en PHP los vectores son ya de por sí elementos dinámicos y que pueden funcionar de muchas formas diferentes, el borrado de elementos es posible. Podemos borrar elementos de la forma más sencilla posible: usando la función unset(). Unset destruye cualquier tipo de variable, incluso elementos de un vector. PHP ya se encarga de reestructurar el vector por dentro. Veamos un ejemplo: <?php // Definimos un sencillo vector de enteros

UD5 – El lenguaje PHP 5.- vectores

64 / 110

$vect = array (5, 7, 7, 8, 9, 0, 6, 1); // Lo imprimimos por pantalla print_r($vect); // Array ( [0] => 5 [1] => 7 [2] => 7 [3] => 8 [4] => 9 [5] => 0 [6] => 6 [7] => 1 ) // Borramos la posición 0 unset($vect[0]); // Dejamo una línea en blanco echo "<br>\n"; // Volvemos a imprimir el vector print_r($vect); // Array ( [1] => 7 [2] => 7 [3] => 8 [4] => 9 [5] => 0 [6] => 6 [7] => 1 ) ?> En el siguiente ejemplo vamos a borrar todos aquellos elementos que sean múltiplos de 2: <?php // Creamos un vector de números enteros $vect_nums = array (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12); // Lo mostramos por pantalla print_r($vect_nums); /* Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 4 [4] => 5 [5] => 6 [6] => 7 [7] => 8 [8] => 9 [9] => 10 [10] => 11 [11] => 12 ) */ // Eliminamos todos los elementos que sean múltiplos de 2 foreach ($vect_nums as $clave => $valor) if ($valor % 2 == 0) unset($vect_nums[$clave]); // Dejamos una línea en blanco echo "<br>\n"; // Lo volvemos a mostrar por pantalla print_r($vect_nums); /* Array ( [0] => 1 [2] => 3 [4] => 5 [6] => 7 [8] => 9 [10] => 11 ) */ ?> PHP suministra, además, otras funciones que facilitan el uso de un vector como si de una pila o cola se tratase. array_push y array_pop int array_push ( array vector, mixed var [, mixed var2, ...]) mixed array_pop ( array vector) array_push() considera vector como una pila, e inserta las variables que se le pasan al final de éste. La longitud de la vector se incrementa en el número de variables insertadas. Tiene el mismo efecto que ejecutar: $matriz[] = $var; Devuelve el nuevo número de elementos de la matriz. array_pop() realiza el procedimiento inverso: extrae y devuelve el último valor del vector, acortando el vector en un elemento. Ejemplo:

UD5 – El lenguaje PHP 5.- vectores

65 / 110

$pila = array ("naranja", "manzana", "frambuesa"); $fruta = array_pop ($pila); Tras esto, $pila contiene sólo 2 elementos: "naranja" y "manzana", y $fruta contiene "frambuesa". array_unshift y array_shift int array_unshift ( array vector, mixed var [, mixed var2, ...]) mixed array_shift ( array vector) Estas dos funciones son exactamente iguales a las ya vistas, excepto que las de arriba insertan los elementos al final y éstas al principio. array_pad array array_pad ( array vector, int tam_relleno, mixed valor_relleno) array_pad() Devuelve una copia del vector rellenada hasta el tamaño tam_relleno con el valor valor_relleno. Si tam_relleno es positivo, entonces la matriz es rellenada por la derecha, y si es negativo, por la izquierda. Si el valor absoluto de tam_relleno es menor o igual que el tamaño del vector no se produce relleno alguno. Ejemplo: $entrada = array (12, 10, 9); $resultado = array_pad ($entrada, 5, 0); // el resultado es array (12, 10, 9, 0, 0) $resultado = array_pad ($entrada, -7, -1); // el resultado es array (-1, -1, -1, -1, 12, 10, 9) $resultado = array_pad ($entrada, 2, "no"); // no rellenado

5.7. Otras funciones interesantes

Aunque existen gran cantidad de funciones para manipular vectores, aquí se comentarán brevemente aquellas que pueden considerarse de mayor utilidad:

o range()

o array_keys() | array_values()

o array_reverse() | array_flip()

o array_merge | array_slice | array_splice

o shuffle() range (PHP 3>= 3.0.8, PHP 4 ) range -- Crea un vector que contiene un rango de elementos Descripcion: array range ( int inferior, int superior [, int paso]) range() devuelve un vector de elementos desde inferior hasta superior, ambos incluidos. Si inferior > superior, la secuencia se generará descendentemente. Si inferior < superior, la secuencia se generará ascendentemente.

UD5 – El lenguaje PHP 5.- vectores

66 / 110

Nuevo Parámetro: El parámetro opcional paso fué añadido en la versión 5.0.0. Si se le proporciona el valor paso, será usado como el incremento entre elementos de la secuencia. Su valor ha de ser positivo. Si no se especifica ningún valor, paso valdrá 1.

Nota: Con anterioridad a la versión 4.1.0, la función range() sólo generaba vectores ascendentes de enteros. El soporte para generar vectores descendentes y vectores de caracteres fue añadido en la versión 4.1.0. array_keys (PHP 4 ) array_keys -- Devuelve todas las claves de una matriz Descripción: array array_keys ( array entrada [, mixed val_a_buscar]) array_keys() devuelve las claves, numéricas y de cadena, de la matriz entrada. Si se especifica el parámetro opcional val_a_buscar, sólo se devuelven las claves para dicho valor. De otro modo, se devuelven todas las claves de la entrada.

array_values (PHP 4 ) array_values -- Devuelve todos los valores de una matriz Descripción: array array_values ( array entrada) array_values() devuelve todos los valores de la matriz entrada.

<?php // array(0,1,2,3,4,5,6,7,8,9) foreach(range(0, 9) as $number) { echo $number; } // El parámetro paso fue introducido en PHP 5.0.0 // array(0,10,20,30,40,50,60,70,80,90,100) foreach(range(0, 100, 10) as $number) { echo $number; } // array('a','b','c','d','e','f','g','h','i'); foreach(range('a', 'i') as $letter) { echo $letter; } // array('c','b','a'); foreach(range('c', 'a') as $letter) { echo $letter; } ?>

$matriz = array(0 => 100, "color" => "rojo"); array_keys ($matriz); // devuelve array (0, "color") $matriz = array(1, 100, 2, 100); array_keys ($matriz, 100); // devuelve array (0, 2)

UD5 – El lenguaje PHP 5.- vectores

67 / 110

array_reverse (PHP 4 ) array_reverse -- Devuelve una matriz con los elementos en orden inverso Descripción: array array_reverse ( array matriz) array_reverse() toma la matriz de entrada y devuelve una nueva matriz con los elementos en orden inverso.

Esto hace que $resultado contenga array (array ("verde", "rojo"), 4.0, "php"). array_flip (PHP 4 ) array_flip -- Intercambia el par clave/valor de una matriz. Descripción: array array_flip ( array trans) array_flip() intercambia las claves por los valores y viceversa.

array_merge (PHP 4 ) array_merge -- Combina dos o más matrices Descripción: array array_merge ( array matriz1, array matriz2 [, ...]) array_merge() combina los elementos de dos o más matrices conjuntamente de modo que los valores de una son agregados al final de los valores de la anterior. Devuelve la matriz resultante. Si las matrices de entrada tienen las mismas claves de cadena, el último valor para cada clave reemplazará el valor previo de la misma. Si, por el contrario, las matrices tienen la misma clave numérica, esto no pasa y los valores son simplemente agregados.

$matriz = array("talla" => "XL", "color" => "dorado"); array_values($matriz); // devuelve array("XL", "dorado")

$entrada = array ("php", 4.0, array ("verde", "rojo")); $resultado = array_reverse ($entrada);

<?php // Vector original $original = array('A' => 'a', 'B' => 'b', 'C' => 'c'); // Lo imprimimos por pantalla print_r($original); echo "<br>"; // Array ( [A] => a [B] => b [C] => c ) // Ahora lo transponemos $trans = array_flip ($trans); // Imprimimos por pantalla la transposición print_r($trans); echo "<br>"; // Array ( [a] => A [b] => B [c] => C )

$matriz1 = array ("color" => "rojo", 2, 4); $matriz2 = array ("a", "b", "color" => "verde", "forma" => "trapezoide"); array_merge ($matriz1, $matriz2);

UD5 – El lenguaje PHP 5.- vectores

68 / 110

array_slice (PHP 4 ) array_slice -- Extrae una porción de la matriz Descripción: array array_slice ( array matriz, int desplazamiento [, int tamano]) array_slice() devuelve una secuencia de elementos de la matriz especificada por los parámetros desplazamiento y tamano. Si el desplazamiento es positivo, la secuencia comenzará en dicha posición de la matriz. Si el desplazamiento es negativo, la secuencia comenzará en esa posición desde el final de la matriz. Si se especifica el tamano y éste es positivo, la secuencia contendrá tantos elementos como se diga en él. Si fuese negativo, la secuencia se detendrá a tantos elementos del final de la matriz. Si se omite, la secuencia contendrá todos los elementos desde el desplazamiento hasta el final de la matriz.

array_splice (PHP 4 ) array_splice -- Suprime una porción de la matriz y la sustituye por otra cosa Descripción: array array_splice ( array entrada, int desplazamiento [, int tamano [, array sustitucion]]) array_splice() suprime los elementos designados por el desplazamiento y el tamano de la matriz entrada, y los sustituye con los elementos de la matriz de sustitucion si se especifica. Si el desplazamiento es positivo, el comienzo de la parte suprimida sería en esa posición desde el comienzo de la matriz de entrada. Si el desplazamiento es negativo, se cuenta la posición desde el final de la matriz de entrada. Si se omite tamano, se suprime todo desde el desplazamiento hasta el final de la matriz. Si se especifica el tamano y es positivo, se suprimirán tantos elementos como se especifica. Si fuera negativo, el final de la porción eliminada estará a tantos elementos del final de la matriz. Truco: para eliminar todo desde el desplazamiento hasta el final de la matriz cuando también se especifica sustitucion, utilice count($entrada) como tamano. Si se especifia la matriz de sustitucion, entonces los elementos suprimidos son reemplazados con los elementos de dicha matriz. Si los valores de desplazamiento y tamano son tales que nada es borrado, los elementos de la matriz sustitucion se insertarán en la posición indicada por el desplazamiento. Truco: si sólo se va a sustituir algo por un elemento nada más, no hace falta poner array() alrededor del mismo, salvo que dicho elemento sea una matriz en sí mismo. Las siguientes funciones son equivalentes:

$entrada = array ("a", "b", "c", "d", "e"); $salida = array_slice ($entrada, 2); // devuelve "c", "d", y "e" $salida = array_slice ($entrada, 2, -1); // devuelve "c", "d" $salida = array_slice ($entrada, -2, 1); // devuelve "d" $salida = array_slice ($entrada, 0, 3); // devuelve "a", "b", y "c"

UD5 – El lenguaje PHP 5.- vectores

69 / 110

Devuelve una matriz que tiene los elementos eliminados:

shuffle (PHP 3>= 3.0.8, PHP 4 ) shuffle -- Mezcla una matriz Descripción: void shuffle ( array matriz) Esta función mezcla (cambia aleatoriamente el orden de los elementos de) una matriz.

Nota: srand() inicializa el generador de números aleatorios con la semilla pasada. Siempre es mejor trabajar con una semilla aleatoria que con una por defecto.

array_push($entrada, $x, $y) ≡ array_splice($entrada, count($entrada), 0, array($x, $y)) array_pop($entrada) ≡ array_splice($entrada, -1) array_shift($entrada) ≡ array_splice($entrada, 0, 1) array_unshift($entrada, $x, $y) ≡ array_splice($entrada, 0, 0, array($x, $y)) $a[$x] = $y ≡ array_splice($entrada, $x, 1, $y)

$entrada = array("rojo", "verde", "azul", "amarillo"); array_splice($entrada, 2); // $entrada vale ahora array("rojo", "verde") array_splice($entrada, 1, -1); // $entrada vale ahora array("rojo", "amarillo") array_splice($entrada, 1, count($entrada), "naranja"); // $entrada vale ahora array("rojo", "naranja") array_splice($entrada, -1, 1, array("negro", "marrón")); // $entrada vale ahora array("rojo", "verde", // "azul", "negro", "marrón")

$numeros = range (1,20); srand (time()); shuffle ($numeros); while (list(, $numero) = each ($numeros)) { echo "$numero "; }

UD5 – El lenguaje PHP 6.- Ficheros y Entrada/Salida

70 / 110

6. Ficheros y Entrada/Salida PHP suministra gran cantidad de funciones para poder trabajar con el sistema de ficheros. De hecho, incluso suministra funciones para abrir procesos y realizar conexiones a sockets. Nosotros sólo veremos cómo trabajar con el sistema de ficheros.

6.1. Trabajar con Ficheros

a) Existencia y tamaño de ficheros

Antes de trabajar con un fichero, lo más normal es comprobar su existencia. Esto lo podemos hacer con la función file_exists(). El único inconveniente que tiene ésta función, es que no distingue entre ficheros y directorios. Eso significa que si en lugar de pasarle un fichero se le pasa un directorio, file_exists devolverá cierto si el directorio existe. Cuando deseamos comprobar si el fichero que se nos pasa es realmente un fichero y no un directorio, tendremos que usar la función is_file(). Si el fichero que se nos pasa existe, es realmente un fichero y se puede leer y escribir, entonces is_file devolverá cierto. Esto es extremadamente útil cuando recorremos el contenido de un directorio. De esta forma podemos reconocer aquellos elementos que son ficheros y los que no lo son (existe una función homóloga para reconocer directorios). Si además necesitamos conocer el tamaño de un fichero, basta con hacer una llamada a la función filesize(). Ésta se encarga de devolver el tamaño del fichero en bytes. Veamos en detalle el funcionamiento de cada una de éstas funciones: file_exists (PHP 3, PHP 4 ) file_exists -- Verifica si un fichero existe Descripción: int file_exists ( string filename) Devuelve TRUE si el fichero especificado por filename existe; y FALSE en otro caso. El resultado de esta función es cacheado. NOTA: Las funciones que sacan información sobre el estado de un fichero suelen ser muy costosas. Para ahorrar algo de tiempo, PHP “cachea” (almacena) el resultado. Eso significa que si se vuelve a preguntar por el mismo archivo, no se vuelve ha realizar la comprobación, se usa el resultado anterior. Si se desea forzar un nuevo chequeo del estado del fichero (por si el fichero puede cambiar o desaparecer) hay que usar la función clearstatcache(). is_file (PHP 3, PHP 4 ) is_file -- Dice si el fichero nombrado es un fichero regular Descripción: bool is_file ( string filename) Devuelve TRUE si el fichero nombrado existe y es un fichero regular. Los resultados de esta función son cacheados. Ver clearstatcache() para más detalles. IMPORTANTE: Aunque no se indique por ninguna parte, esta función no se comporta de la forma esperada. Cuando se la pasa el nombre de un fichero, sólo se mira si ese fichero existe en el directorio actual de trabajo. No vale pasarle el path completo del archivo. Eso significa que si se desea comprobar la existencia del fichero “./docs/quijote.txt”, primero habrá que hacer un cambio

UD5 – El lenguaje PHP 6.- Ficheros y Entrada/Salida

71 / 110

de directorio al directorio docs chdir(“./docs”) y luego hacer is_file(“quijote.txt”). Si se hace de cualquier otra forma, is_file no se comportará de la manera esperada. Se puede consultar más sobre esto en la página www.php.net. Basta con buscar la función is_file y luego leer las notas colgadas por otros programadores. Es posible que el resto de funciones de la familia is_xxx tengan el mismo problema (De hecho is_dir también lo tiene). filesize (PHP 3, PHP 4 ) filesize -- Obtiene el tamaño del fichero Descripción: int filesize ( string filename) Devuelve el tamaño del fichero (en bytes), o FALSE en caso de error. Los resultados de esta función son cacheados. Ver clearstatcache() para más detalles. NOTA: Puesto que al preguntar el tamaño de archivos grandes pueden aparecer cifras grandes, lo que se puede hacer es poner las unidades. Eso se puede conseguir dividiendo el tamaño del archivo entre: 210 (1024) para obtener los KBytes 220 (1048576) para obtener los Mbytes 230 (1073741824) para obtener los GBytes b) Abrir y Cerrar Ficheros

Siempre que se desea leer o escribir sobre un archivo, hay que abrirlo antes. Una vez abierto, y dependiendo de las propiedades al abrir el fichero, podremos escribir o leer de él. Una vez que hayamos acabado de trabajar con él, es importante que lo volvamos a cerrar. Como se puede suponer, fopen() abre un fichero y fclose() lo cierra. fopen (PHP 3, PHP 4 ) fopen -- Abre un fichero o una URL Descripción: int fopen ( string filename, string mode [, int use_include_path]) Si filename comienza con "http://" (no es sensible a mayúsculas), se abre una conexión HTTP 1.0 hacia el servidor especificado y se devuelve un apuntador de fichero al comienzo del texto de respuesta. No maneja redirecciones HTTP, por eso se debe incluir una barra final cuando se trata de directorios. Si filename comienza con "ftp://" (no es sensible a mayúsculas), se abre una conexión ftp hacia el servidor especificado y se devuelve un apuntador al fichero requerido. Si el servidor no soporta ftp en modo pasivo, esto fallará. Se pueden abrir fichero via ftp para leer o para escribir (pero no ambas cosas simultáneamente). Si filename no comienza con nada de lo anterior, el fichero se abre del sistema de ficheros, y se devuelve un apuntador al fichero abierto. Si el abrir el fichero falla, la función devuelve FALSE. mode puede ser cualquiera de lo siguiente: 'r' - Abre para sólo lectura; sitúa el apuntador del fichero al comienzo del mismo. 'r+' - Abre para lectura y escritura; situa el apuntador del fichero al comienzo del fichero. 'w' - Abre para sólo escritura; sitúa el apuntador del fichero al comienzo del fichero y trunca el fichero con longitud cero. Si el fichero no existe, trata de crearlo.

UD5 – El lenguaje PHP 6.- Ficheros y Entrada/Salida

72 / 110

'w+' - Abre el fichero para lectura y escritura; sitúa el apuntador del fichero al comienzo del fichero y trunca el fichero con longitud cero. Si el fichero no existe, trata de crearlo. 'a' - Abre sólo para escribir (añadir); sitúa el apuntador del fichero al final del mismo. Si el fichero no existe, trata de crearlo. 'a+' - Abre para lectura y escritura (añadiendo); sitúa el apuntador del fichero al final del mismo. Si el fichero no existe, trata de crearlo. Además, mode puede contener la letra 'b'. Esto es útil para sistemas que diferencian entre ficheros binarios y de texto (ej. es inútil en Unix). Si no se necesita, será ignorado. Puede usarse el tercer parámetro opcional y fijarlo a "1", si también se quiere buscar el fichero en el include_path.

Si experimentas problemas a la hora de leer y escribir a ficheros y estas usando la versión de PHP como módulo para el servidor, recuerda que debes asegurar que los ficheros y directorios que estas usando son accesibles al proceso servidor. fclose (PHP 3, PHP 4 ) fclose -- Cierra el apuntador a un fichero abierto Description: int fclose ( int fp) Se cierra el fichero apuntado por fp. Devuelve TRUE en caso de éxito y FALSE en caso de fallo. El apuntador al fichero debe ser válido y debe apuntarse a un fichero abierto con éxito con fopen() o con fsockopen(). c) Escritura de Ficheros

Antes de abrir un archivo, puede ser interesante saber si podemos escribir sobre él. Ya hemos visto que la función is_file, a parte de comprobar si el elemento pasado es realmente un fichero, también comprueba si sobre el fichero destino se puede leer y escribir. Como pudiera darse el caso que tuviéramos permisos de escritura y no de lectura, la función anterior no nos valdría. La función is_writeable() nos dice, exclusivamente, si el fichero existe y se puede escribir sobre él. Una vez que el fichero ha sido abierto con éxito usaremos la función fwrite() para escribir sobre él. is_writeable (PHP 3, PHP 4 ) is_writeable -- Dice si se puede escribir en el fichero indicado Descripción: bool is_writeable ( string filename) Devuelve TRUE si el fichero indicado existe y se puede escribir en él. El argumento filename puede ser el nombre de un directorio, lo que permite verificar si un directorio tiene permiso de escritura. Recuerda que PHP puede acceder al fichero con el identificador de usuario con el que el servidor web se ejecuta (a menudo 'nobody'). No se tienen en cuenta las limitaciones de modos seguros. Los resultados de esta función son cacheados. Ver clearstatcache() para más detalles. fwrite

$fp = fopen("/home/rasmus/file.txt", "r"); $fp = fopen("http://www.php.net/", "r"); $fp = fopen("ftp://user:[email protected]/", "w");

UD5 – El lenguaje PHP 6.- Ficheros y Entrada/Salida

73 / 110

(PHP 3, PHP 4 ) fwrite -- Escribe ficheros en plan binario Descripción: int fwrite ( int fp, string string [, int length]) fwrite() escribe el contenido de string al fichero apuntado por fp. Si se da el argumento length, la escritura acaba antes de que length bytes sean escritos o se alcance el final de string, lo que ocurra primero. d) Lectura de Ficheros

Al igual que en el caso anterior, antes de abrir un fichero para leer datos, puede ser interesante comprobar si podemos leer de él. is_readable() comprueba si un fichero existe y podemos leer de él. Una vez que el fichero se ha abierto correctamente, disponemos de bastantes maneras para leer de él:

o fread() lee tantos bytes como le digamos o fgetc() lee un único carácter o fgets() permite leer una línea completa o fgetss() funciona igual que fgets salvo que ésta última se encarga de borrar todas las

etiquetas PHP y HTML que encuentre en la línea.

A parte de estas funciones, existen otras que pueden resultar igual de interesantes. file() lee un fichero y lo almacena en un vector dónde cada fila del vector es una línea del fichero. Por otro lado, si lo que queremos es que un archivo se lea y se muestre directamente por pantalla, readfile() nos soluciona la papeleta. is_readable (PHP 3, PHP 4 ) is_readable -- Dice si el fichero indicado se puede leer Descripción: bool is_readable ( string filename) Devuelve TRUE si el fichero indicado existe y se puede leer. Recuerda que PHP puede acceder al fichero con el identificador de usuario con el que el servidor web se ejecuta (a menudo 'nobody'). No se tienen en cuenta las limitaciones de modos seguros. Los resultados de esta función son cacheados. Ver clearstatcache() para más detalles. fread (PHP 3, PHP 4 ) fread -- Lee ficheros en plan binario Descripción: string fread ( int fp, int length) fread() lee hasta length bytes del apuntador de fichero referenciado por fp. La lectura acaba cuando length bytes se han leido o se alcanza EOF, lo que ocurra primero.

UD5 – El lenguaje PHP 6.- Ficheros y Entrada/Salida

74 / 110

fgetc (PHP 3, PHP 4 ) fgetc -- Obtiene un caracter del fichero apuntado Descripción: string fgetc ( int fp) Devuelve una cadena (string) conteniendo un simple caracter leido del fichero apuntado por fp. Devuelve FALSE para EOF (como hace feof()). El apuntador al fichero debe ser valido, y debe apuntar a un fichero abierto con éxito por fopen(), popen(), o fsockopen(). fgets (PHP 3, PHP 4 ) fgets -- Obtiene una línea del fichero apuntado Descripción: string fgets ( int fp, int length) Devuelve una cadena de como mucho length - 1 bytes leidos del fichero apuntado por fp. La lectura acaba cuando son leidos length - 1 bytes, cuando se llega a una nueva línea (el caracter de nueva línea se incluye en el valor devuelto), o cuando se llega a un EOF (lo que ocurra primero). Si ocurre un error, devuelve FALSE. Fallos Comunes: Los que hayan usado la semantica de 'C' de la función fgets deben darse cuenta de la diferencia que hay en como el EOF es devuelto por esta función. El apuntador al fichero debe ser válido, y debe apuntar a un fichero abierto con éxito con fopen(), popen(), o fsockopen(). A continuación un ejemplo sencillo:

fgetss (PHP 3, PHP 4 ) fgetss -- Obtiene una línea del fichero apuntado y quita las etiquetas HTML Descripción; string fgetss ( int fp, int length [, string allowable_tags]) Idéntica a fgets(), excepto que fgetss trata de quitar cualquier etiqueta HTML y PHP del texto que lee. Se puede utilizar el tercer parámetro opcional para especificar etiquetas que no deben de quitarse. Nota: allowable_tags fue añadido en PHP 3.0.13.

// Mete el contenido de un fichero en una cadena $filename = "/usr/local/something.txt"; $fd = fopen ($filename, "r"); $contents = fread ($fd, filesize ($filename)); fclose ($fd);

$fd = fopen ("/tmp/inputfile.txt", "r"); while (!feof($fd)) { $buffer = fgets($fd, 4096); echo $buffer; } fclose ($fd);

UD5 – El lenguaje PHP 6.- Ficheros y Entrada/Salida

75 / 110

file (PHP 3, PHP 4 ) file -- lee un fichero completo hacia un array Descripción: array file ( string filename [, int use_include_path]) Idéntica a readfile(), excepto que file() devuelve el fichero en un array. Cada elemento del array corresponde a una línea del fichero, con el caracter de nueva línea incluido. Se puede utilizar el segundo parámetro opcional y ponerle el valor "1", si también se quiere buscar el fichero en el include_path. readfile (PHP 3, PHP 4 ) readfile -- Muestra el contenido de un fichero Descripción: int readfile ( string filename [, int use_include_path]) Lee un fichero y lo escribe a la salida estándar. Devuelve el número de bytes leidos del fichero. Si ocurre un error, se devuelve FALSE y a menos que la función fuera llamada como @readfile, se imprime un mensaje de error Si filename comienzo por "http://" (no es sensible a mayúsculas), se abre una conexión HTTP 1.0 al servidor especificado y el texto de la respuesta se escribe a la salida estándar. No maneja redirecciones HTTP, por eso se debe incluir una barra final cuando se trata de directorios. Si filename comienza con "ftp://" (no es sensible a mayúsculas), se abre una conexión ftp al servidor especificado y el fichero que se pide se escribe en la salida estándar. Si el servidor no soporta ftp en modo pasivo, la función fallará. Si filename no comienza con ninguna de las cadenas anteriores, el fichero será abierto del sistema de ficheros y su contenido escrito en la salida estándar. Se puede usar el segundo parámetro opcional y fijarlo a "1", si si quieres que también se busque el fichero en el include_path. e) Copiar, Renombrar y Borrar Ficheros

PHP permite copiar, renombrar y borrar archivos, todo de forma dinámica y según las necesidades de nuestra web. Cuando necesitamos crear archivos temporales para mostrar datos o queremos recibir ficheros de usuarios, este tipo de funciones se vuelven totalmente imprescindibles. copy (PHP 3, PHP 4 ) copy -- Copia un fichero Descripción: int copy ( string source, string dest) Hace una copia de un fichero. Devuelve TRUE si la copia tiene éxito, y FALSE en otro caso. rename (PHP 3, PHP 4 ) rename -- Renombra un fichero

UD5 – El lenguaje PHP 6.- Ficheros y Entrada/Salida

76 / 110

Descripción: int rename ( string oldname, string newname) Trata de renombrar oldname como newname. Devuelve TRUE en caso de éxito y FALSE en caso de fallo. unlink (PHP 3, PHP 4 ) unlink -- Borra un fichero Descripción: int unlink ( string filename) Borra el fichero filename. Es similar a la función unlink() del Unix C. Devuelve 0 o FALSE en caso de error.

6.2. Trabajar con Directorios

a) Existencia de un directorio

Al igual que nos ocurría con los ficheros, cuando estamos recorriendo el contenido de un directorio, suele ser interesante saber si el elemento actual es un fichero o un directorio. is_dir() devuelve cierto si el fichero que se le pasa es un directorio. is_dir (PHP 3, PHP 4 ) is_dir -- Dice si el fichero nombrado es un directorio Descripción: bool is_dir ( string filename) Devuelve TRUE si el nombre del fichero existe y es un directorio. Los resultados de esta función son cacheados. Ver clearstatcache() para más detalles. b) Creación y borrado de directorios

mkdir (PHP 3, PHP 4 ) mkdir -- Crea un directorio Descripción: int mkdir ( string pathname, int mode) Trata de crear el directorio especificado por pathname. Ten en cuenta que debes especifiar el modo como un número octal, lo que significa que debes anteponerle un 0 al número. mkdir ("/path/to/my/dir", 0700); Devuelve TRUE en caso de éxito y FALSE en caso de fallo. NOTA: Evidentemente mode sólo es valido en sistemas donde los ficheros tengan permisos tipo Unix. Si se trabaja sobre Windows, esto no tiene sentido. NOTA: Para aclararse con el tema de los permisos, haremos un poco de memoria. Ya hemos dicho que el primer carácter (el 0) es el que indica el número octal, los siguientes siguen esta estructura U G O (User Group Others, es decir Usuario Grupo Otros). Luego en el ejemplo anterior U=7,

UD5 – El lenguaje PHP 6.- Ficheros y Entrada/Salida

77 / 110

G=0 y O=0. Ese 7 (o 0) es la representación en octal del conjunto de permiso que U tiene. Recordemos que cada uno puede tener los siguientes permisos r w x (Read Write eXecute, es decir lectura escritura ejecución). La idea es poner un 1 dónde se le quiera dar permiso y un 0 dónde no. Esa ristra de tres dígitos binarios se traduce a octal y ese es el conjunto de permisos que se le ha otorgado (7octal = 111 en binario. Luego el usuario U tiene todos los permisos: lectura, escritura y ejecución). Veamos una tabla aclaratoria rmdir (PHP 3, PHP 4 ) rmdir -- Elimina un directorio Descripción: int rmdir ( string dirname) Trata de eliminar el directorio indicado por pathname. El directorio debe estar vacio, y los permisos relevantes deben permitir esto. Si ocurre un error, devuelve 0. c) Apertura y cerrado de directorios

opendir (PHP 3, PHP 4 ) opendir -- abre el manejador de directorios Descripcion: int opendir ( string path) Devuelve un manejador de directorio para ser usado con las llamadas closedir(), readdir() y rewinddir(). closedir (PHP 3, PHP 4 ) closedir -- cierra el manejador de directorios Descripcion: void closedir ( int dir_handle) Cierra la secuencia de directorio determinada por dir_handle. La secuencia debe de haber sido abierta previamente con opendir().

r w x = Octal Significado 0 0 0 0 Sin permisos 0 0 1 1 Sólo permiso de ejecución 0 1 0 2 Sólo permiso de escritura 0 1 1 3 Permiso de escritura y ejecución 1 0 0 4 Sólo permiso de lectura 1 0 1 5 Permiso de lectura y ejecución 1 1 0 6 Permiso de lectura y escritura 1 1 1 7 Todos los permisos: lectura, escritura y ejecución

UD5 – El lenguaje PHP 6.- Ficheros y Entrada/Salida

78 / 110

d) Lectura del contenido de un directorio

readdir (PHP 3, PHP 4 ) readdir -- lee las entradas del manejador de directorios Descripcion: string readdir ( int dir_handle) Devuelve el nombre del siguiente fichero en el directorio. Los nombres de ficheros no son devueltos en ningún orden especial. Hay que tener en cuenta que readdir() devolverá también las entradas . y .. Si no se quieren estas entradas, hay que borrarlas manualmente. rewinddir (PHP 3, PHP 4 ) rewinddir -- rebobinar el manejador de directorios Descripcion: void rewinddir ( int dir_handle) Inicializa la secuencia de directorio determinada por dir_handle al principio del directorio. chdir (PHP 3, PHP 4 ) chdir -- cambia de directorio Description: int chdir ( string directory) Cambia el directorio PHP actual a directory. Devuelve FALSE si no puede cambiar al directorio, TRUE si todo va bien.

6.3. Funciones útiles del Sistema de Ficheros

basename (PHP 3, PHP 4 ) basename -- Devuelve la parte del path correspondiente al nombre del fichero Descripción:

<?php // Con entradas . y .. $handle=opendir('.'); echo "Manejador del directorio: $handle\n"; echo "Archivos:\n"; while ($file = readdir($handle)) { echo "$file\n"; } closedir($handle); ?>

<?php // Sin entradas . y .. $handle=opendir('.'); echo "Manejador del directorio: $handle\n"; echo "Archivos:\n"; while ($file = readdir($handle)) { if ( ($file != “.”) && ($file != “..”)) echo "$file\n"; } closedir($handle); ?>

UD5 – El lenguaje PHP 6.- Ficheros y Entrada/Salida

79 / 110

string basename ( string path) Dada una cadena (string) que contiene el path de un fichero, esta función devuelve el nombre base del fichero. En Windows, tanto la barra (/) como la barra inversa (\) pueden usarse como caracter separador en el path. En otros entornos, se usa la barra directa (/).

dirname (PHP 3, PHP 4 ) dirname -- Devuelve la parte del path correspondiente al directorio Descripción: string dirname ( string path) Dada una cadena (string) conteniendo el path a un fichero, esta función devolverá el nombre del directorio. En Windows, tanto la barra (/) como la barra inversa (\) son usadas como separadores de caracteres. En otros entornos, debe usarse la barra directa (/).

stat (PHP 3, PHP 4 ) stat -- Da información sobre un fichero Descripción: array stat ( string filename) Recoge los datos sobre el fichero indicado por filename. Devuelve un array conteniendo los datos del fichero con los siguientes elementos: 1. dispositivo (device) 2. inode 3. modo de protección del inode 4. número de enlaces 5. id de usuario del propietario 6. id de grupo del propietario 7. tipo de dispositivo si es un inode device * 8. tamaño en bytes 9. fecha del último acceso access 10. fecha de la última modificación 11. fecha del último cambio 12. tamaño del bloque para el sistema I/O * 13. número de bloques ocupados * - sólo válido en sistemas que soportan el tipo st_blksize --otros sistemas (Windows) devuelven -1 Los resultados de esta función son cacheados. Ver clearstatcache() para más detalles.

$path = "/home/httpd/html/index.php3"; $file = basename($path); // $file toma el valor "index.php3"

$path = "/home/httpd/html/index.php3"; $file = basename($path); // $file toma el valor "/home/httpd/html"

UD5 – El lenguaje PHP 6.- Ficheros y Entrada/Salida

80 / 110

6.4. Modificación de las características de un archivo

(Consultar la ayuda de PHP para más información) chgrp -- Cambia el grupo de un fichero filegroup -- Obtiene el grupo de un fichero chmod -- Cambia permisos de un fichero fileperms -- Obtiene los permisos del fichero chown -- Cambia el propietario de un fichero fileowner -- Obtiene el propietario del fichero

6.5. Ejecución externa de programas

(Consultar la ayuda de PHP para más información) exec -- Ejecuta un programa externo backtickts (comillas simples invertidas) passthru -- Ejecuta un programa externo y muestra su salida literal system -- Ejecuta un programa externo y muestra su salida

6.6. Almacenamiento de variables en ficheros

Permite la conversión de una variable en una cadena de caracteres. Esto puede resultar extremadamente útil si lo que deseamos es almacenar en un fichero o base de datos variables con una estructura compleja (arrays n-dimensionales, objetos, etc...) de forma directa.

Por ejemplo, imaginemos que tenemos montada una tienda electrónica. Lo normal es que

vayamos almacenando en algún tipo de estructura todos lo objetos que el usuario quiera comprar. Si nuestro usuario cierra la sesión sin comprar, puede resultar interesante almacenar los objetos que iba a comprar y recordárselo la próxima vez que inicie sesión. La función serialize agiliza mucho el proceso pues podemos guardar la estructura tal y como está pero en formato texto. Cuando queramos recuperar los datos, leemos la cadena y usamos unserialize que nos reconstruye la estructura tal y como estaba inicialmente. serialize (PHP 3>= 3.0.5, PHP 4 ) serialize -- Genera una representación almacenable de una variable Description: string serialize ( mixed var) serialize() devuelve una cadena de caracteres que representa a la variable var y que puede ser almacenado en cualquier lugar. Esto resulta muy útil para almacenar variables PHP sin que pierdan su tipo y estructura. Para volver a convertir la cadena serializada en una variable PHP basta con usar la función unserialize().

<?php $stat=stat("./errors.txt"); print_r($stat); /* Y la salida es: Array ( [0] => 2 [1] => 0 [2] => 33206 [3] => 1 [4] => 0 [5] => 0 [6] => 2 [7] => 254 [8] => 1062870622 [9] => 1062857346 [10] => 1062857056 [11] => -1 [12] => -1 [dev] => 2 [ino] => 0 [mode] => 33206 [nlink] => 1 [uid] => 0 [gid] => 0 [rdev] => 2 [size] => 254 [atime] => 1062870622 [mtime] => 1062857346 [ctime] => 1062857056 [blksize] => -1 [blocks] => -1 ) */ ?>

UD5 – El lenguaje PHP 6.- Ficheros y Entrada/Salida

81 / 110

serialize() maneja cualquier tipo (excepto si son recursos). Se pueden serializar incluso vectores/objetos que contengan referencias a sí mismos, las referencias también serán almacenadas. Nota: En PHP 3, las propiedades de los objetos eran serializadas, pero se perdían los métodos. PHP 4 elimina dicha restricción. Conviene consultar la sección Serializando Objetos (Serializing Objects) del punto Clases y Objetos (Classes and Objects) para más información. unserialize (PHP 3>= 3.0.5, PHP 4 ) unserialize -- Crea una variable PHP a partir de una representación serializada anteriormente Description: mixed unserialize ( string str) Se le pasa una cadena de caracteres (correspondiente a la serialización de una variable) y la convierte en una variable PHP. La variable devuelta corresponderá a uno de los siguientes tipos: integer, float, string, array o object. En caso que la cadena pasada no se puede deserializar, se devuelve FALSE. Ejemplo:

<?php // $v es un vector $v[]="A"; $v[]="B"; $v[]="C"; $v[]="D"; $v[]="E"; $v[]="F"; // Imprimimos el vector print_r($v); // SALIDA: Array ( [0] => A [1] => B [2] => C [3] => D [4] => E [5] => F ) // Serializamos el vector $v=serialize($v); // Ahora $v es una cadena de caracteres // Imprimimos el vector serializado echo "<br><br>".$v."<br><br>"; // SALIDA: a:6:{i:0;s:1:"A";i:1;s:1:"B";i:2;s:1:"C";i:3;s:1:"D";i:4;s:1:"E";i:5;s:1:"F";} // Realizamos el proceso inverso $v=unserialize($v); // $v vuelve a ser un vector print_r($v); // SALIDA: Array ( [0] => A [1] => B [2] => C [3] => D [4] => E [5] => F ) ?>

UD5 – El lenguaje PHP 6.- Ficheros y Entrada/Salida

82 / 110

6.7. Otras funciones interesantes

tempnam (PHP 3, PHP 4 ) tempnam -- Crea un fichero de nombre único Descripción: string tempnam ( string dir, string prefix) Crea un fichero temporal de nombre único en el directorio especificado. Si el directorio no existe tempnam() puede generar un fichero en el directorio temporal del sistema. Devuelve el nombre del nuevo fichero temporal, o una cadena nula en caso de fallo.

tmpfile (PHP 3>= 3.0.13, PHP 4 ) tmpfile – Crea un fichero temporal Description: int tmpfile ( void) Crea un fichero temporal de nombre único en modo escritura y devuelve un manejador de fichero similar al que se devuelve con fopen(). Si el fichero no es renombrado o movido, es automáticamente borrado cuando se cierre el fichero (fclose) o finalice el script.

parse_ini_file (PHP 4 ) parse_ini_file – Parsea un fichero de configuración del tipo “ini”. Description: array parse_ini_file ( string filename [, bool process_sections]) parse_ini_file() carga el archive ini especificado en filename, y devuelve los datos en un array asociativo. Si el último parámetro process_sections (procesar secciones) se pone a TRUE, se devuelve un array multidimensional con el nombre de las secciones incluido. Si no se indica nada, process_sections está por defecto a FALSE. Nota: Esta función no tiene nada que ver con el archivo de configuración de php “php.ini”. Dicho archivo es cargado de forma automática cuando se ejecuta el servidor. Esta función sólo tiene utilidad para cargar nuestros propios archivos de configuración en nuestros scripts. IMPORTANTE: Cualquier valor en el archivo de configuración que contenga caracteres que no sean alfanuméricos ha de estar entre comillas dobles (“”). Nota: A partir de la versión 4.2.1 de PHP, esta función es afectada por safe_mode and open_basedir. (Para más información consultar el archivo la ayuda de PHP) Archivo ejemplo.ini

$tmpfname = tempnam ("/tmp", "tmp_");

$temp = tmpfile(); fwrite($temp, "Escribiendo en un archivo temporal."); fclose($temp); // al cerrar se borra el archivo temporal

UD5 – El lenguaje PHP 6.- Ficheros y Entrada/Salida

83 / 110

Archivo encargado de parsear el archivo ini:

Tendrá la siguiente salida por pantalla:

; <?php die(); ?> ; La primera línea sirve para que nadie pueda acceder a nuestro archivo ini desde fuera del server ; Este es un ejemplo de un archive de configuración ; Las secciones van entre corchetes y los comentarios comienzan con ; [first_section] one = 1 five = 5 animal = BIRD [second_section] path = /usr/local/bin URL = "http://www.example.com/~username"

<?php // Parsear sin secciones $ini_array = parse_ini_file("sample.ini"); print_r($ini_array); // Parsear con secciones $ini_array = parse_ini_file("sample.ini", TRUE); print_r($ini_array); ?>

Array ( [one] => 1 [five] => 5 [animal] => Dodo bird [path] => /usr/local/bin [URL] => http://www.example.com/~username ) Array ( [first_section] => Array ( [one] => 1 [five] => 5 [animal] = Dodo bird ) [second_section] => Array ( [path] => /usr/local/bin [URL] => http://www.example.com/~username ) )

UD5 – El lenguaje PHP 7.- Desarrollo dinámico de webs

84 / 110

7. Desarrollo dinámico de webs

7.1. Introducción

Hasta el momento no hemos visto más que los pilares del lenguaje PHP, y aunque ya se pueden intuir las aplicaciones, no hemos visto ningún ejemplo de utilidad real. Una de las capacidades más interesantes de PHP es la capacidad de crear las páginas que el internauta verá “al vuelo”. Una de las primeras ventajas con la que nos encontramos es la capacidad de separar el diseño de la página de su contenido (mediante Plantillas), evitándonos el costoso trabajo de hacer copia/pega del código HTML común de cada página. Con este método conseguimos que retocar el diseño no implique ir archivo por archivo modificando su código. Además, hasta el propio diseño de la página puede ser dinámico e ir cambiando dependiendo de las fechas o días, según nos pueda interesar. Lo segundo es la capacidad para crear contenidos totalmente dinámicos y personalizables. Así, si el usuario quiere hacer una consulta a una base de datos, o mostrar el contenido de un determinado fichero, lo que se muestre es algo que nuestro script no sabrá a priori. Incluso puede que dos usuarios distintos, solicitando la misma información, visualicen cosas diferentes dependiendo de los permisos que tengan. Todo esto se puede realizar gracias a que los archivos HTML que nuestro internauta verá son los que genere nuestro código PHP.

7.2. Plantillas

Es la base para separar diseño y contenido. Una vez encontrado un diseño Web que nos guste, no tenemos más que trocearlo en partes (secciones) y meter cada parte en una función PHP. Las partes de un diseño Web suelen ser del tipo: INICIO, TÍTULO, MENU, CONTENIDO, PIE y FIN. Veamos un ejemplo que aclare lo anterior: Página HTML dividida en secciones <!-- Inicio del documento HTML --> <!doctype html public "-//W3C//DTD HTML 4.0 //ES"> <html> <!-- Título --> <head> <title>Mi primera Plantilla</title> </head> <body> <!-- Menu --> <p align="center"><a href="http://www.php.net">PHP</a> | <a href="http://www.mysql.com">MySQL</a> | <a href="http://www.apache.org"> Apache</a> | <a href="http://www.hotscripts.com">Scripts</a></p> <!-- Contenido --> <p>&nbsp;</p> <p align="center"><b><font face="Arial">Ésta es una sencilla página<br> Con un contenido sencillo</font></b></p> <p align="center">&nbsp;</p> <!-- Pie de Página --> <p align="center"><b><font face="Arial" size="1">Mi pie de página</font></b></p> </body> <!-- Fin del documento HTML --> </html>

UD5 – El lenguaje PHP 7.- Desarrollo dinámico de webs

85 / 110

Ahora vamos a crear una función por cada sección, excepto la del contenido: Archivo “lib_design.php”:

<?php // Librería de Diseño function ini_HTML(){ echo <<<ini_HTML <!-- Inicio del documento HTML --> <!doctype html public "-//W3C//DTD HTML 4.0 //ES"> <html> ini_HTML; } function titulo($titulo){ echo <<<TITULO <!-- Título --> <head> <title>$titulo</title> </head> <body> TITULO; } function menu(){ echo <<<MENU <p align="center"><a href="http://www.php.net">PHP</a> | <a href="http://www.mysql.com">MySQL</a> | <a href="http://www.apache.org"> Apache</a> | <a href="http://www.hotscripts.com">Scripts</a></p> MENU; } function pie(){ echo <<<PIE <!-- Pie de Página --> <p align="center"><b><font face="Arial" size="1">Mi pie de página</font></b></p> </body> PIE; } function fin_HTML(){ echo <<<fin_HTML <!-- Fin del documento HTML --> </html> fin_HTML; } ?>

UD5 – El lenguaje PHP 7.- Desarrollo dinámico de webs

86 / 110

Ahora veamos la estructura de la plantilla “plantilla.php”:

Ahora, para ir creando los scripts de nuestra web basta con abrir el fichero anterior, añadirle el contenido deseado y guardarlo con el nombre que nos interese.

Añadiremos el contenido de la página HTML inicial a nuestra plantilla para ver qué tal queda: “index.php”:

Como se puede observar a simple vista, las ventajas son múltiples. La primera es que el código queda mucho más claro. En nuestro ejemplo, no se procesa información ni se realizan grandes tareas, pero si éste fuera el caso, el código quedaría mucho más sencillo de entender. Por ejemplo, si tuviéramos que acceder a un fichero, procesar los datos y luego mostrarlos por pantalla, el esquema de nuestro archivo PHP quedaría muy limpio:

1. Se adquieren los datos 2. Se procesan 3. Usamos nuestra plantilla para mostrar los resultados

La segunda es la independencia de cada parte: retocar el diseño, el contenido o el código

que genera nuestro contenido es extremadamente sencillo.

<?php // Plantilla. Es decir, todos nuestros scripts tendrán la siguente estructura: // Includes y requires include("./lib_design.php"); ini_HTML(); titulo($título); menú(); // Contenido o cuerpo del script /* ... */ pie(); fin_HTML(); ?>

<?php // Includes y requires include("./lib_design.php"); menú(); ini_HTML(); titulo($título); // Contenido o cuerpo del script echo <<<HTML <!-- Contenido --> <p>&nbsp;</p> <p align="center"><b><font face="Arial">Ésta es una sencilla página<br> Con un contenido sencillo</font></b></p> <p align="center">&nbsp;</p> HTML; pie(); fin_HTML(); ?>

UD5 – El lenguaje PHP 7.- Desarrollo dinámico de webs

87 / 110

7.3. Paso de parámetros entre scripts

a) Introducción

Cada script es independiente del resto. Es decir, cuando un script acaba, todas las variables que habían sido definidas son destruidas. De hecho, si había archivos abiertos que se habían dejado sin cerrar, también se cierran. Igual ocurre con los enlaces abiertos a bases de datos y similares (a no ser que se hubieran abierto enlaces persistentes, algo implica cierto riesgo).

Normalmente un sitio web está compuesto por diversos scripts que van procesando las peticiones del usuario. Es importante tener en cuenta que un script no tiene por qué devolver una página html. Es habitual encontrarse scripts que no muestren salida por pantalla y sólo procesan datos o que muestren 3 o 4 páginas diferentes según las elecciones del usuario. Si las variables se crean y se destruyen con cada script, es evidente que deben existir métodos de intercambio de información entre ellos.

PHP suministra tres métodos: GET (mediante la URL), POST (mediante formularios) y

SESSION_VARS (mediante variables de sesión). El primer método lo veremos en este tema, el resto en los temas 8 y 9 respectivamente. b) El Método GET

La idea es mandar la información a través de la URL. El método es muy sencillo y resulta extremadamente útil aunque tiene como inconveniente que el usuario puede ver los datos que se envían e incluso podría modificarlos. Una URL tiene una estructura similar a ésta: http://www.mipagina.com Si queremos abrir el archivo links.php basta escribir: http://www.mipagina.com/links.php Si queremos mandarle al archivo links algunas variables basta hacer lo siguiente: http://www.mipagina.com/links.php?var1=valor1&var2=valor2& …. & varN=valorN Por ejemplo, queremos mandarle al archivo links dos variables: SO de valor WIN y proc de valor AMD. Para ello haríamos: http://www.mipagina.com/links.php?SO=WIN&proc=AMD

Cuando el archivo links se abra, las variables $SO y $proc estarán ya definidas y con valor WIN y AMD respectivamente (¡OJO! PHP sí que hace distinción entre mayúsculas y minúsculas tanto en el nombre de las variables como en sus valores). Para mostrar estas dos variables desde el archivo links simplemente usaríamos el vector global $_GET: echo “Sistema Operativo: {$_GET[‘SO’]}<br>\nProcesador del Tipo: $_GET[‘proc’]”; Si en el archivo php.ini la opción register_globlals está a On, también se podrían llamar sin más: echo “Sistema Operativo: $SO<br>\nProcesador del Tipo: $proc”; Problemas El hecho que el usuario pueda ver las variables no es importante a no ser que se envíe información que haga peligrar la seguridad del usuario o del mismo sitio web. Si éste es el caso, se debería utilizar un método más seguro como el método POST o haciendo uso de variables de sesión. El principal problema reside en que los caracteres ? y & son caracteres protegidos y no deben estar contenidos dentro de ninguna variable (Es decir ..?tienda=Marks&Spencer es erróneo pues crearía dos variables: tienda de valor Marks y Spencer de valor nulo). Incluso un

UD5 – El lenguaje PHP 7.- Desarrollo dinámico de webs

88 / 110

simple espacio en blanco nos podría dar problemas. Para evitar lo anterior, PHP dispone de dos funciones: urlencode() y urldecode(). La primera se encarga en codificar cualquier carácter que no sea “-”, “_” y “.” Por un símbolo de porcentaje y dos dígitos hexadecimales. La segunda función realiza la tarea inversa. Veámoslo con el ejemplo anterior: $tienda=“Marks & Spencer”; $tienda_urlcod=urlencode($tienda); echo “<a href=’./tiendas.php?tienda=$tienda_urlcod’>Ver: $tienda</a>”; $tienda_urlcod valdrá Marks+%26+Spencer Los espacios en blanco se han sustituidos por signos + y el ampersand por %26. NOTA: Si no se desea que el usuario visualice o modifique lo que se envía, la información se puede cifrar o codificar. NOTA: Los formularios también admiten el método GET. NOTA: Aunque es poco habitual, si no conociéramos a priori el número de argumentos que se le van a pasar a nuestro script, o si no conocemos ni siquiera los nombres de las variables que se nos pasarán, tenemos varias alternativas aunque la más sencilla e interesante sería hacer un recorrido del vector $_GET mediante un foreach() sacando el par clave-valor. NOTA: El vector global $_SERVER almacena una variable interesante llamada QUERY_STRING que se encarga de almacenar toda la cadena que hay después del ?. Es decir, si tenemos: www.mipagina.com/listar_usuario.php?nombre=Gabi&[email protected] $_SERVER[‘QUERY_STRING’] = nombre=Gabi&[email protected] Las utilidades son varias. Nos puede servir por si queremos mandar la información codificada o cifrada a través de la URL. La cadena cuando llega se decodifica o desencripta y luego se trata convenientemente con funciones como split() o explode() para sacar los pares clave-valor. Veamos un ejemplo que aclaratorio: script1.php

<?php // Script 1: Codificamos la información para el envío $nombre='Gabi'; $mail='[email protected]'; // Vamos a codificar la información en formato mime64 por sencillez. // Si lo que se desea es seguridad, habría que usar alguna función de encriptación. $string_query=base64_encode("nombre=$nombre&mail=$mail"); echo <<<HTML <a href='script2.php?$string_query'>Mandar datos codificados</a> HTML; ?>

UD5 – El lenguaje PHP 7.- Desarrollo dinámico de webs

89 / 110

script2.php

7.4. Redireccionamiento

Como ya se ha comentado con anterioridad, es frecuente encontrarse con scripts que sólo procesan información o que realizan determinadas tareas y al finalizar llaman a otros scripts. Para poder realizar el redireccionamiento hay que hacer uso de la función headers().

La función header() se utiliza para mandar el texto de la cabecera HTTP al comienzo de un fichero HTML. Aunque no nos interesa profundizar sobre los tipos de cabecera existentes, es necesario comentar la cabecera de redireccionamiento: Location. header("Location: http://www.php.net"); exit;

La primera línea realiza la redirección y la segunda evita que se sigan ejecutando el resto de instrucciones del script.

IMPORTANTÍSIMO: La función header() debe llamarse antes de que se genere salida alguna3, bien con etiquetas HTML normales o con PHP. Un error muy frecuente consiste en leer código con include() que inserta código html y luego se trata de hacer uso de la función header. Si éste es el caso, PHP da un error al interpretar el código indicando que las cabeceras ya han sido enviadas antes de llamar a la función header() (El hecho de mostrar código HTML genera de forma automática un tipo de cabecera que indica al navegador que va a recibir código HTML).

3 es decir, usando funciones como echo , printf o cualquier otra función que genere salida (código HTML) por pantalla.

<?php // Script 2: Nos llega la información, la decodificamos y la mostramos por pantalla // Mostramos la cadena codificada echo "Cadena codificada: ", $_SERVER['QUERY_STRING'],"<br>\n"; // La decodificamos $query_string=base64_decode($_SERVER['QUERY_STRING']); // $query_string contendrá "nombre=Gabi&[email protected]" // Gracias a la función split, almacenamos el par vble-valor en una componente de un vector $var_vect=split('&', $query_string); // $var_vect[0] contendrá "nombre=Gabi" y $var_vect[1] contendrá "[email protected]" // Recorremos el vector anterior foreach($var_vect as $par_vble_valor) { list($vble, $valor)=split('=', $par_vble_valor); echo "Variable <b>$vble</b> tiene el valor <b>$valor</b><br>\n"; } /* Mostrará por pantalla: Cadena codificada: bm9tYnJlPUdhYmkmbWFpbD1nYWJtZWN1QGluZi51cHYuZXM= Variable nombre tiene el valor Gabi Variable mail tiene el valor [email protected] */ ?>

UD5 – El lenguaje PHP 7.- Desarrollo dinámico de webs

90 / 110

Los scripts de PHP a menudo generan HTML dinámico que no debe almacenarse en la caché del navegador cliente o en la caché de cualquier proxy situado entre el servidor y el navegador cliente (información confidencial o privada). Se puede obligar a muchos proxies y clientes a que deshabiliten el almacenamiento en caché. Para ello podemos hacer uso de cualquiera de las siguientes cabeceras: header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Fecha pasada header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); // Siempre se modifica header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1 header("Pragma: no-cache"); // HTTP/1.0

7.5. Scripts que se llaman a sí mismos

Hay que evitar pensar que un script PHP equivale a una página HTML. Dependiendo de nuestras preferencias, puede resultarnos útil tener varias páginas contenidas en un mismo script. Veamos un sencillo ejemplo que muestra un menú y dependiendo de las elecciones del usuario, muestra una información u otra:

<?php // La variable que indica la elección del usuario se llamará $opc // Si la variable opc no está definida, es porque el usuario no ha elegido ninguna opción. if (!isset($_GET['opc'])) { // El usuario no ha elegido ninguna opción. Mostramos el menú: echo <<<MENU <a href="{$_SERVER['PHP_SELF']}?opc=1">CONTENIDO 1</a> <a href="{$_SERVER['PHP_SELF']}?opc=2">CONTENIDO 2</a> <a href="{$_SERVER['PHP_SELF']}?opc=3">CONTENIDO 3</a> MENU; } else { // El usuario ha elegido una opción switch($_GET['opc']) { case 1: // CONTENIDO 1 echo "Aquí iría el contenido de la opción 1"; break; case 2: // CONTENIDO 2 echo "Aquí iría el contenido de la opción 2"; break; case 3: // CONTENIDO 3 echo "Aquí iría el contenido de la opción 3"; break; default: // Si vale cualquier otra cosa, volvemos a mostra el menu header("Location: {$_SERVER['PHP_SELF']}"); exit; break; } } ?>

UD5 – El lenguaje PHP 7.- Desarrollo dinámico de webs

91 / 110

7.6. Recomendaciones

En el método GET se comentó que en el script destino se podía acceder a las variables enviadas de dos formas: una mediante el vector global $_GET y otra poniendo register_globals a On y accediendo a las variables como si fueran simples variables locales. Este último método es el menos recomendable pues es el más peligroso. Lleva a fallos de seguridad (que pueden consultarse en http://www.php.net/manual/en/security.registerglobals.php ) y a partir de la versión 4.2.0 de PHP, register_globals viene a off por defecto.

La opción no es insegura de por sí, el problema reside en posibles despistes del

programador. Por ejemplo, podría darse el caso que nuestro script usara una variable del mismo nombre que una de las variables que puede llegar. Si algún usuario malintencionado ha visto nuestro código y ha encontrado algún fallo, podría intentar colarse en alguna sección protegida. Veamos un ejemplo: autorizar.php

Como se puede observar, debido a un fallo nuestro (no hemos inicializado la variable $autorizado=FALSE al principio del script), nos podemos encontrar con que gente no autorizada acceda a información privilegiada.

Si se desea acceder a cualquier variable mandada por el método GET, POST o cookies se puede usar el vector global $_REQUEST, aunque siempre es recomendable usar su vector específico: $_GET, $_POST, $_COOKIE o $_FILES. Los métodos GET y POST también pueden utilizar los vectores $HTTP_GET_VARS y $HTTP_POST_VARS. Consultar la ayuda de PHP para más información.

<?php if (usuario_autorizado($nombre, $password)) { $autorizado = true; } // Como NO hemos inicializado la variable $autorizado a FALSE al inicio del script, // gracias a register_globals, alguien podría llamar a este archivo de la siguiente forma: // autorizar.php?autorizado=1 if ($autorizado) { include "/info/privilegiada/data.php"; } ?>

UD5 – El lenguaje PHP 8.- Formularios

92 / 110

8. FORMULARIOS

8.1. Introducción

Hasta el momento hemos visto las estructuras para tratar y almacenar los datos del usuario, pero aún no hemos visto la forma de recogerlos.

La obtención de datos está ampliamente desarrollada mediante los formularios HTML. Todos estamos acostumbrado a los cajetines, áreas de texto y listas desplegables existentes en casi todas las Webs y que permiten identificarnos, almacenar datos personales, escribir en foros, firmar libros de visita, etc..

Debido a que éste método es ampliamente conocido y extremadamente sencillo de utilizar, PHP hace uso de él, recogiendo los datos y suministrándoselos al programador de forma sencilla, para que éste los pueda tratar fácilmente.

8.2. Formularios

Aunque los formularios no forman parte de PHP si no de HTML, haremos un breve repaso a los formularios y a sus entidades. a) Creación Formularios

Un formulario se crea mediante las siguientes etiquetas HTML: <form action=”script.php” method=”metodo” {enctype="multipart/form-data"}> .. Entidades del formulario .. </form> Aunque existen más atributos, los más importantes y los que utilizaremos nosotros son dos:

o action: Indica el nombre del script que procesará los datos del formulario. También es válido poner action=”malito: [email protected]“ para que los datos sean enviados directamente a una dirección de correo, aunque no todos los navegadores lo soportan. Aquí es dónde nosotros pondremos el nombre del archivo PHP que se encargará de procesar los datos.

o method: Método de envío de datos entre el formulario y el servidor. Puede tener dos

valores: GET y POST. El método GET (que ya hemos visto) envía los datos a través de la URL mientras que el método POST envía los datos del formulario en el cuerpo de una petición HTTP POST. El método GET tiene un gran inconveniente: la cantidad de información que puede ser enviada está limitada al tamaño máximo de la URL que navegador y servidor pueden manejar. Además, el método GET no soporta el envío de caracteres que no sean ASCII (cómo "é" y"©"). El método POST siempre es más seguro y más cómodo. Si se va a trabajar con URL’s de más de 100 caracteres o que contengan caracteres no ASCII el uso del método POST es imperativo para evitar posibles problemas.

o enctype: Indica el tipo de contenido que va a ser enviado por el formulario. A no ser

que se vayan a enviar ficheros, este atributo es innecesario. Si este fuera el caso, es IMPRESCINDIBLE añadir este atributo y con el valor de arriba. Si no existe el atributo, o si su valor es diferente a "multipart/form-data", los datos no serán enviados correctamente.

Falta por añadir que dentro de una misma página podemos tener todos los formularios

que necesitemos.

UD5 – El lenguaje PHP 8.- Formularios

93 / 110

b) Entidades

ENTIDADES ORIENTADAS AL TECLADO

Para la inserción de texto por parte del usuario disponemos de dos tipos de entidades: Text Box (Cajetín de texto) y el Text area box (Cajetín con área de texto). TEXT BOX Sirve para entradas de texto cortas y de una sola línea. Su sintaxis es: <input type=”text” name=”nombre” size=”tam_caja” maxlength=”max_car” value=”val_por_defecto”> Descripción de los atributos:

o type: Indica la forma en que debe mostrarse el texto. Si se pone “text”, las letras serán visibles por el usuario. En cambio, si se pone “password”, cada carácter será sustituido por un asterisco (o un punto, dependiendo del SO).

o name: Nombre del cajetín. Es importante ponerle un nombre significativo ya se verá más adelante el por qué.

o size: Tamaño del cajetín en caracteres. Es decir, si size=”7”, el explorador mostrará un cajetín dónde sólo serán visibles los 7 primeros caracteres que el usuario escriba.

o maxlength: Número máximo de caracteres que se podrán insertar en el cajetín. No ha de coincidir con size.

o value: Valor por defecto. En otras palabras, cuál es el texto inicial que queremos que aparezca en el cajetín.

TEXT AREA BOX Útil cuando tenemos entradas de texto largas. Su sintaxis es: <textarea name=”nombre” rows=”num_filas” cols=”num_columnas” >Texto Inicial</textarea> Descripción de los atributos:

o name: Nombre del área de texto. Al igual que antes, debe tener un valor significativo. o rows: Número de filas visibles por el usuario. o cols: Número de columnas visibles por el usuario. o Texto Inicial: Valor inicial que se mostrará en el área de texto.

ENTIDADES ORIENTADAS AL RATÓN Para la selección de opciones mediante el uso del ratón disponemos de tres entidades: Checkbox (Confirmación de una opción), Radio Button (Botones de Opción) y los Pull-Down Menu (Listas desplegables). CHECKBOX Permite la confirmación de una determinada opción que se le muestra al usuario. Su sintaxis es: <input type=”checkbox” name=”nombre_1” value=”valor_1” {checked}>Texto Cuadro Conf. 1 <input type=”checkbox” name=”nombre_2” value=”valor_2” {checked}> Texto Cuadro Conf. 2 ... <input type=”checkbox” name=”nombre”_N value=”valor_N” {checked}> Texto Cuadro Conf. N Descripción de los atributos:

o type: En este caso, type sólo puede valer “checkbox”. o name: Nombre de cuadro de confirmación. Debe ser significativo. o value: Único valor posible que tomará este cuadro de confirmación. Si el cuadro de

confirmación ES marcado, entonces su valor será el que indique value. En caso contrario su valor es nulo.

UD5 – El lenguaje PHP 8.- Formularios

94 / 110

o {checked}: Es un parámetro opcional. Si se pone, el cuadro de confirmación viene marcado inicialmente.

RADIO BUTTON Permite la selección de una opción entre un grupo de opciones que son mostradas al usuario. Su sintaxis es: <input type=”radio” name=”nombre_grupo1” value=”valor_1” {checked}>Texto de la Opción 1 <input type=”radio” name=”nombre_grupo1” value=”valor_2”>Texto de la Opción 2 … <input type=”radio” name=”nombre_grupo1” value=”valor_N”>Texto de la Opción N Descripción de los atributos:

o type: En este caso, type sólo puede valer “radio”. o name: Nombre del grupo de opciones. Debe ser significativo. o value: Valor que tomará el conjunto de opciones si se selecciona esta opción. o {checked}: Es un parámetro opcional. Indica cual de las opciones de grupo viene

seleccionada por defecto. Puesto que con los botones de selección el objetivo es que el usuario marque (de forma obligada) una de las opciones mostradas, suele ser imperativo (si no conveniente) que alguna de las opciones venga seleccionada por defecto.

IMPORTANTE: Si nos fijamos, la diferencia fundamental entre los cuadros de confirmación y los botones de radio reside en que en el primero cada opción es independiente del resto y TODAS podrían estar marcadas (cada cuadro de confirmación debe tener un nombre diferente con respecto al resto de cuadros de confirmación), de ahí que todas puedan llevar el atributo checked.

En cambio, en la selección por opción, sólo se puede seleccionar UNA de las opciones mostradas (todas las opciones del mismo grupo deben tener el mismo nombre), de ahí que sólo una de las opciones del grupo pueda llevar el atributo checked. PULL-DOWN MENU Genera una lista desplegable de opciones. Su sintaxis es: <select name=”nombre” {multiple} {size=”num_opciones_a_mostrar”}> <option {selected} value=”Valor_opción_1”>Texto Opción 1 <option value=”Valor_opción_2”>Texto Opción 2 … <option value=”Valor_opción_N”>Texto Opción N </select> Descripción de los atributos:

o name: Nombre de la lista desplegable. o value: Valor de la opción actual. No tiene por qué coincidir con el texto de la opción. Es el

valor que tomará la lista si se selecciona dicha opción. o {selected}: Es un parámetro opcional. Indica qué opción de la lista vendrá seleccionada

por defecto. Los atributos opcionales {multiple} y {size} modifican el comportamiento de la lista desplegable.

Si multiple existe, la lista deja de ser desplegable y se convierte en un cuadro de selección dónde el usuario puede seleccionar múltiples elementos. Para que multiple funcione correctamente, hemos de cambiar “nombre” por “nombre[]”. Esto es así porque vamos a asignar varios valores a una misma entidad (variable a efectos de PHP). La única forma de hacer ésto es indicándole a PHP que almacene los diversos valores de la entidad en forma de vector. Si no se hace así, PHP sólo se quedará con el último elemento seleccionado ya que todos los elementos tendrán el mismo nombre y por tanto se irán sobrescribiendo los valores.

UD5 – El lenguaje PHP 8.- Formularios

95 / 110

Si size existe, la lista deja de ser desplegable y se convierte en un cuadro de selección de tamaño fijo donde num_opciones_a_mostrar indica el número de opciones a mostrar. A no ser que multiple también exista, el usuario sólo podrá seleccionar una opción. NOTA: Si el número de opciones a mostrar es menor que el número total de opciones, al cuadro de selección le aparecerá una barra de desplazamiento vertical. ENTIDAD ORIENTADA AL ENVÍO DE ARCHIVOS Más adelante veremos cómo PHP gestiona el envío de ficheros, de momento veremos qué entidad suministra HTML para tal fin. <input type="file" name="fichero" size="tam_cajetín"> Descripción de los atributos:

o type: En este caso type sólo puede valer “file”. o name: Nombre de la entidad. o size: Tamaño del cajetín (en caracteres) que indica la ubicación del fichero seleccionado

por el usuario. ENTIDAD ORIENTADA A LA PERSISTENCIA DE DATOS Si a un formulario le queremos añadir datos adicionales ocultos al usuario, también disponemos de una entidad para tal fin: Hidden Values (Valores Ocultos) HIDDEN VALUES La idea es poder mandar información, obtenida previamente, de un script a otro. Su sintaxis es: <input type=”hidden” name=”nombre” value=”valor”> Descripción de los atributos:

o type: En este caso type sólo puede valer “hidden”. o name: Nombre de la entidad oculta. o value: Valor de la entidad oculta.

Podemos añadir todas las entidades ocultas que nos interesen. Basta con poner nombres distintos a cada entidad oculta.

Aunque la información es aparentemente oculta, si el usuario se interesa por ver el código fuente, podrá ver toda la información oculta que se va a enviar. El uso de estas entidades suele tener como finalidad la de enviar datos poco importantes que o bien han sido recopilados previamente mediante otros formularios o mediante algún algoritmo o función concreta.

Siempre que necesitemos enviar información poco importante entre scripts, podemos

recurrir al uso de estas entidades. Proporcionan un sencillo mecanismo para la persistencia de datos sin tener que recurrir a cookies o variables de sesión. ENTIDADES GENERALES Para terminar, veremos dos entidades que permiten enviar los datos o reestablece el valor de todas las entidades a sus valores por defecto: Submit (Envío de Datos) y Reset (Reestablecer valores). SUBMIT Envía los datos de todas las entidades del formulario al script indicado en action. Su sintaxis es: <input type=”submit” value=”texto_del_boton”>

UD5 – El lenguaje PHP 8.- Formularios

96 / 110

Descripción de los atributos:

o type: En este caso type sólo puede valer “submit”. o Value: Texto del botón. Típicamente “Enviar”.

RESET Restaura el valor de todas las entidades a su valor por defecto. Su sintaxis es: <input type=”reset” value=”texto_del_boton”> Descripción de los atributos:

o type: En este caso type sólo puede valer “reset”. o Value: Texto del botón. Típicamente “Reestablecer”

A parte de los atributos ya vistos, existe una atributo opcional común a TODAS las entidades vistas: tabindex=”num_orden”.

Aunque no suele ser habitual que el usuario se desplace a través de la página mediante el

teclado (usando el tabulador), si este fuera el caso, cuando llegase al formulario el orden en el que se recorrerán las entidades puede no ser el esperado.

Para evitar esto, podemos añadir a cada entidad el atributo tabindex. El número al que se

iguala este atributo indica el orden en que se recorrerá dentro del formulario.

NOTA: Así como el botón de envío es imprescindible si queremos que los datos se envíen, el botón

de reestablecer es totalmente opcional.

8.3. Formularios y PHP

PHP trata de una forma muy sencilla la información que llega a un script a través de un formulario. Crea una variable por cada entidad, de nombre name y de valor value (el valor de la entidad), dentro del vector correspondiente ($_GET si el método de envío es get y $_POST si el método es post). Por ello es importante darle un nombre significativo a cada entidad, a fin de cuentas, el nombre de la entidad será el nombre de la variable que representará a dicha entidad. Si en el fichero de configuración php.ini register_globlals está a on, también se podrá acceder a las variables como si fueran variables locales (con el riesgo que ello conlleva). Veamos un sencillo ejemplo:

UD5 – El lenguaje PHP 8.- Formularios

97 / 110

ejemplo_sencillo.php

<?php // Sencillo ejemplo que muestra la interacción de PHP con HTML if (isset($_POST["seenform"])) { echo "Nombre: ".$_POST["nombre"]."<br>\n"; echo "Apellidos: ".$_POST["apellido_1"]."&nbsp;".$_POST["apellido_2"]."<br>\n"; echo "<a href='{$_SERVER['PHP_SELF']}'>Volver al formulario</a>"; } else { echo <<<FORM <html> <head> <title>Formulario Simple</title> </head> <body> <form method="POST" action="{$_SERVER["PHP_SELF"]}"> Nombre: <input type="text" name="nombre" size="20"><br> Apellido 1: <input type="text" name="apellido_1" size="20"> Apellido 2: <input type="text" name="apellido_2" size="20"></p> <input type="hidden" name="seenform" value="TRUE"> <p> <input type="submit" value="Enviar"> <input type="reset" value="Restablecer"> </p> </form> </body> </html> FORM; } ?>

UD5 – El lenguaje PHP 8.- Formularios

98 / 110

Envío de archivos mediante el método POST Antes de explicar cómo gestiona PHP el envío de ficheros, es conveniente saber cómo habilitar esta opción. Para poder enviar ficheros al servidor (file uploads), tenemos que configurar el archivo php.ini Si hacemos BUSCAR → FILE UPLOADS encontraremos las siguientes líneas:

1. ;;;;;;;;;;;;;;;; 2. ; File Uploads ; 3. ;;;;;;;;;;;;;;;;

4. ; Whether to allow HTTP file uploads 5. file_uploads = On

6. ; Temporary directory for HTTP uploaded files (will use system default if not specified) 7. upload_tmp_dir = “C:\phpdev\www\public\temp”

8. ; Maximum allowed size for uploaded files 9. upload_max_filesize = 2M

En la línea 5 indicamos si permitimos al usuario enviar ficheros al servidor. En la línea 7 indicamos el directorio temporal donde se almacenarán los ficheros enviados. Si se deja en blanco, se usará el directorio temporal del sistema. En la línea 9 indicamos el tamaño máximo de los ficheros enviados (expresado en Mega Bytes).

Ya hemos visto que para enviar ficheros hacemos uso de la entidad file de HTML. El tratamiento que PHP hace de esta entidad es bastante intuitivo: crea un archivo temporal en el servidor y almacena la siguiente información dentro de los vectores globales $_FILES y $HTTP_POST_FILES: $HTTP_POST_FILES['fichero']['name'] ó $_FILES['fichero']['name'] El nombre original del fichero en la máquina cliente. $HTTP_POST_FILES['fichero']['type'] ó $_FILES[' fichero ']['type'] El tipo mime del fichero (si el navegador lo proporciona). Un ejemplo podría ser "image/gif". $HTTP_POST_FILES['fichero']['size'] ó $_FILES[' fichero ']['size'] El tamaño en bytes del fichero recibido. $HTTP_POST_FILES['fichero']['tmp_name'] ó $_FILES[' fichero ']['tmp_name'] El nombre del fichero temporal que se utiliza para almacenar en el servidor el archivo recibido. Donde fichero es el nombre que le dimos a la entidad HTML encargada del envío de ficheros. Si además register_globals = on, las siguientes variables también serán creadas: $fichero: Nombre del fichero temporal que sirve para almacenar en el servidor el archivo recibido. $fichero_name: El nombre original que el fichero tenía en la máquina cliente (usuario). $fichero_size: El tamaño en bytes del fichero recibido.

UD5 – El lenguaje PHP 8.- Formularios

99 / 110

$fichero_type: El tipo mime del fichero (si el navegador lo proporciona). Un ejemplo podría ser "image/gif". Si en el transcurso del script, el fichero no es ni renombrado ni movido, éste es borrado al acabar el script.

Disponemos de dos funciones interesantes para trabajar con ficheros que han sido subidos al servidor: is_uploaded_file($fichero_subido) para comprobar si un fichero ha sido subido al servidor mediante el método POST. move_uploaded_file($fichero_subido, $fichero_destino) mueve un fichero subido mediante el método POST hasta el lugar deseado. Siempre que enviemos ficheros mediante el método POST (existe otro método llamado PUT que no veremos) es conveniente agregar la siguiente entidad oculta antes de la entidad file: <input type="hidden" name="MAX_FILE_SIZE" value="tam_max_en_bytes"> Con ella es posible conseguir que el navegador haga una primera comprobación del tamaño del fichero. Así como el navegador puede saltarse esta comprobación, hay que recordar que PHP tiene configurado un tamaño máximo para los archivos enviados y rechazará aquellos que superen dicho tamaño. Hay que recordar que no se nos puede olvidar añadir el atributo enctype="multipart/form-data" dentro de la etiqueta del formulario. Veamos un ejemplo completo: enviar_fichero.html

<html> <head> <title>Envío de Ficheros</title> </head> <body> <form enctype="multipart/form-data" action="recibe_fichero.php" method="post"> <!-- El navegador rechazará cualquier fichero que exceda de 1000 bytes, independientemente del tamaño máximo configurado en php.ini --> <input type="hidden" name="MAX_FILE_SIZE" value="1000"> Enviar el siguiente archivo: <input name="fichero" type="file"><br> <input type="submit" value="Enviar Fichero"> </form> </body> </html>

UD5 – El lenguaje PHP 8.- Formularios

100 / 110

recibir_fichero.php

También se permite el envío múltiple de ficheros. Para hacer esto, se utiliza la misma sintaxis que cuando tenemos listas múltiples, es decir, basta con cambiar el nombre de “fichero” por el de “fichero[]” en cada entidad “file” de HTML. Veamos un ejemplo: enviar_varios_ficheros.html

<?php // Nombre de la entidad HTML que nos envia el fichero $nombre='fichero'; // Carpeta dónde moveremos el fichero recibido $carpeta_destino='./ficheros_recibidos/'; // Si se nos ha enviado un fichero if (isset($_FILES[$nombre])) { // Comprobamos que el fichero ha sido enviado apropiadamente if (is_uploaded_file($_FILES[$nombre]['tmp_name'])) { echo "Datos del fichero recibido:<br>\n"; echo "<b>Nombre: </b>".$_FILES[$nombre]['name']."<br>\n"; echo "<b>Tipo MIME: </b>".$_FILES[$nombre]['type']."<br>\n"; echo "<b>Tamaño: </b>".$_FILES[$nombre]['size']." bytes<br>\n"; echo "<b>Temporal: </b>".$_FILES[$nombre]['tmp_name']."<br>\n"; $fich_destino=$carpeta_destino.$_FILES[$nombre]['name']; // Las dos lineas de abajo son equivalentes //if (copy($_FILES[$nombre]['tmp_name'], $fich_destino)) if (move_uploaded_file($_FILES[$nombre]['tmp_name'], $fich_destino)) echo "El fichero ha sido subido a la carpeta $carpeta_destino"; else echo "ERROR: El fichero no ha podido ser movido"; } } ?>

<html> <head> <title>Envío de Ficheros</title> </head> <body> <form action="recibe_varios_ficheros.php" method="post" enctype="multipart/form-data"> Enviar los siguiente ficheros:<br> <input type="hidden" name="MAX_FILE_SIZE" value="1000"> <input name="fichero[]" type="file" size="30"><br> <input name="fichero[]" type="file" size="30"><br> <input name="fichero[]" type="file" size="30"><br> <input name="fichero[]" type="file" size="30"><br> <input type="submit" value="Enviar Ficheros"> </form> </body> </html>

UD5 – El lenguaje PHP 8.- Formularios

101 / 110

recibir_varios_ficheros.php

<?php // Nombre de las entidades HTML que nos envian los ficheros $nombre='fichero'; // Carpeta donde moveremos el fichero recibido $carpeta_destino='./ficheros_recibidos/'; // Si se nos ha enviado un fichero if (isset($_FILES[$nombre])) { // Contaremos el número máximo de ficheros nos pueden haber enviado: $num_fich_max=count($_FILES[$nombre]['name']); // Digo máximo porque si había 4 entidades HTML de tipo file, se habrán // creado cuatro componentes name, cuatro type, etc.. // Pero el usuario puede haber dejado alguna de las entidades en blanco y // por tanto esas componentes estarán vacías. // Con esta vble contaremos los ficheros se han enviado en realidad. $num_fich_real=0; // Vamos fichero por fichero mostrando sus datos for ($i=0; $i<$num_fich_max; $i++) { // Comprobamos que el fichero ha sido enviado apropiadamente if (is_uploaded_file($_FILES[$nombre]['tmp_name'][$i])) { echo "Datos del fichero <b>$i</b>:<br>\n"; echo "<b>Nombre: </b>".$_FILES[$nombre]['name'][$i]."<br>\n"; echo "<b>Tipo MIME: </b>".$_FILES[$nombre]['type'][$i]."<br>\n"; echo "<b>Tamaño: </b>".$_FILES[$nombre]['size'][$i]." bytes<br>\n"; echo "<b>Temporal: </b>".$_FILES[$nombre]['tmp_name'][$i]."<br>\n"; $fich_destino=$carpeta_destino.$_FILES[$nombre]['name'][$i]; if (move_uploaded_file($_FILES[$nombre]['tmp_name'][$i], $fich_destino)) echo "SUBIDO<br>\n"; else echo "NO subido<br>\n"; $num_fich_real++; } } } // Mostramos el número máximo de posibles ficheros enviados y el real. echo "<br>"; // Línea en blanco echo "Máximo número de Ficheros recibidos: <b>$num_fich_max</b><br>\n"; echo "Número real de Ficheros recibidos: <b>$num_fich_real</b><br>\n"; ?>

UD5 – El lenguaje PHP 8.- Formularios

102 / 110

8.4. Creación Dinámica de Formularios

Sólo queda comentar que, gracias a PHP, la construcción dinámica de formularios puede ser algo extremadamente útil. Por ejemplo: tenemos una lista desplegable con las opciones más interesantes que ofrece nuestra web. Si dichas opciones se encuentran en una base de datos o en un fichero, podemos hacer que la lista desplegable se construya de forma dinámica. Gracias a este método, cuando queramos modificar el contenido de la lista, no tendremos que tocar nuestro código PHP, basta con que vayamos a la base de datos o al fichero y modifiquemos su contenido. Hay que pensar que la creación dinámica de páginas web permite evitar la redundancia e inconsistencia de los datos, sobre todo cuando se muestra información que es compartida y modificada por diversos usuarios.

Vamos a ver un ejemplo que crea un formulario de forma totalmente dinámica, en función del contenido de un fichero .ini4 de configuración: config.php (archivo ini)

4 Por razones de seguridad, se ha cambiado la extensión .ini a .php . Con este sencillo truco, evitamos que el usuario pueda descargarse y ver el contenido del archivo de configuración.

; <?php die("No está permitido el acceso a este fichero"); ?> ; Este es un fichero de configuración. ; El hecho que tenga extensión .php es para evitar accesos indeseados. ; La primera línea se encarga de ello. ; LISTA 1: Lista desplegable simple [secciones] ; Configuracion de la lista TEXTO = "Elije la sección a la que te quieres dirigir" SELECCION = TAMANYO = 1 ; Elementos de la lista Inicio = "index.php" Noticias = "noticias.php" Ofertas = "productos_en_oferta.php" Productos = "productos_nuevos.php" Quienes Somos = "quienes.php" Ayuda = "help.php" ; LISTA 2: Lista de selección múltiple [mejores_paginas] ; Configuracion de la lista TEXTO = "Elija sus sitios favoritos" SELECCION = multiple TAMANYO = 5 ; Elementos de la lista Apache = www.apache.org PHP = www.php.net MySQL = www.mysql.net FirePages = www.firepages.com.au WebDesigns = www.oswd.org HotScripts = www.hotscripts.com ; Podríamos seguir añadiendo todas las listas que necesitáramos

UD5 – El lenguaje PHP 8.- Formularios

103 / 110

formulario_dinamico.php

<?php // Incluimos el archivo que contiene la función "crea_lista_desp($vect, $l_nombre)" include("./func_crea_lista.php"); // Creación de un formulario en función del contenido de un fichero INI // Nombre del fichero $fich_conf="./config.php"; // Queremos secciones? En nuestro caso SÍ, es imprescindible pues cada sección // representa una lista desplegable $secciones=TRUE; // Parseamos su contenido $contenido=parse_ini_file($fich_conf, $secciones); // Primero creamos el formulario echo "<form method='POST' action='./procesa_form.php'>\n"; // Creamos una lista por seccion foreach($contenido as $nom_lista => $vect_elements) { echo "\n<p>"; crea_lista_desp($vect_elements, $nom_lista); echo "</p>\n"; } // Creamos el botones de envio y de reestablecer echo "\n<p><input type='submit' value='Enviar'> <input type='reset' value='Restablecer'></p>\n"; // También creamos la entidad oculta seenform para que funcione procesa_form.php echo "<input type='hidden' name='seenform' value='TRUE'>\n"; // Cerramos el formulario echo "\n</form>\n"; ?>

UD5 – El lenguaje PHP 8.- Formularios

104 / 110

func_crea_lista.php

<?php // Creamos una función que crea una lista desplegable a partir de un vector. // El vector debe contener tres componentes que configuran la lista: // TEXTO (indica el texto de la lista), SELECCION (indica si se permite // la selección múltiple) y TAMANYO (número de elementos a mostrar) // El orden no importa. // El resto de componentes son consideradas como los elementos de la lista function crea_lista_desp($vect, $l_nombre) { // Sirve para contar el número de elementos $i=0; // Numero de la lista. Indicamos que es estática para no perder su valor // en la siguiente llamada a la función. STATIC $l_numero=1; // Inicialmente la lista no tiene elementos $l_elementos=""; // Recorremos el vector foreach($vect as $clave => $valor) { switch($clave) { case "TEXTO": $l_texto=$valor; break; case "SELECCION": $l_seleccion=$valor; // Si la selección es múltiple, los datos han de guardarse // en un vector if ($l_seleccion=="multiple") $l_nombre.='[]'; break; case "TAMANYO": $l_tamanyo=$valor; break; default: // Sólo el primer elemento estará seleccionado if ($i==0) $sel_elem="selected"; else $sel_elem=""; // Agregamos un elemento a la lista $l_elementos.="<option value='$valor' $sel_elem>$clave</option>\n"; // Incrementamos el número de elementos $i++; break; } } // Ya tenemos toda la información de la lista. La mostramos por pantalla: echo "$l_texto<br>\n"; echo "<select size='$l_tamanyo' name='$l_nombre' $l_seleccion tabindex='$l_numero'>\n"; echo $l_elementos; echo "</select>\n"; // Incrementamos el numero de lista $l_numero++; } ?>

UD5 – El lenguaje PHP 9.- Sesiones

105 / 110

9. SESIONES

9.1. Introducción

Hoy en día resulta extremadamente útil el poder hacer un seguimiento del usuario dentro de nuestra web. Eso permite el poder mostrar información más personalizada atendiendo a los gustos de nuestro usuario. Pensemos en sitios web que se encarguen de vender productos. Si tenemos una tienda de libros y hacemos un seguimiento de los libros que consulta, podemos intuir los géneros que le resultan más atractivos. De este modo, la próxima vez que nos visite, lo primero que le mostraremos son las novedades y ofertas de los libros pertenecientes sus géneros favoritos. A parte de las ventajas comerciales y de marketing, también tiene fines de privacidad. Por ejemplo, podemos mostrar contenidos diferentes atendiendo al tipo de usuario que acceda a nuestra web. Un ejemplo claro lo tenemos dentro de la web de la universidad. Una forma sencilla de realizar este seguimiento es mediante las conocidas “cookies” (galletas). Una cookie no es más que un pequeño fichero de texto que se envía desde el servidor al navegador del usuario dónde se puede almacenar información. Esto permite que la información entre usuario y servidor sea persistente. En la actualidad existen cientos de sitios que usan este sencillo sistema para realizar compras on-line, crear webs personalizadas o mostrar publicidad selectiva. Pese a ser un método sencillo, las cookies tienen algunos inconvenientes: pueden ser desactivadas desde el explorador del usuario y, además, tienen un tamaño limitado (máximo 4KBytes). A parte de todo ésto, la información contenida puede no ser del todo fiable pues el usuario tiene acceso a ella y puede, por tanto, manipularla. PHP admite el uso de cookies de una forma extremadamente sencilla, pero añade otro método mucho más flexible, potente y fácil para realizar el seguimiento del usuario: SESIONES.

9.2. Manejo de Sesiones

La idea es bastante sencilla: cuando un usuario accede a nuestra web, se comprueba si ya había creado una sesión. Si no lo había hecho, se le crea un identificador único llamado “session id” (identificador de sesión). Dicho identificador es almacenado en la máquina del usuario (mediante una cookie). Si el usuario tuviera deshabilitadas las cookies, PHP propagará el identificador de sessión a través de la URL. El servidor guardará los datos de esa sesión creando un fichero (en el directo indicado por session.save_path en php.ini ) cuyo nombre será el identificador de la sesión y cuyo contenido será las variables que el usuario de dicha sesión vaya registrando. El usuario siempre podrá acceder a sus variables de sesión registradas gracias a los vectores $_SESSION y $HTTP_SESSION_VARS (en desuso). Si register_globals está activado, también se podrán acceder de forma directa a las variables. Recordar que no se aconseja el uso de register_globals debido a los problemas de seguridad y eficiencia. NOTA: Se puede configurar PHP para que que cualquier script que se ejecute, inicie automáticamente sesión. Eso se puede conseguir poniendo session.auto_start = 1 en el fichero php.ini, aunque no es muy recomendable. Cuando el usuario haya acabado de usar nuestra web, basta con que cierre su sesión de para que las variables registradas sean borradas y el fichero en el servidor también sea destruido. La cookie (si se ha usado) no se destruirá por el hecho de cerrar la sesión,

UD5 – El lenguaje PHP 9.- Sesiones

106 / 110

aguantará el tiempo que esté configurado en session.cookie_lifetime. Si su valor es 0, indica que el tiempo de vida de la cookie expira cuando se acabe la sesión. Es lo que suele estar puesto por defecto. Veamos ahora las funciones para el manejo de sesiones: a) Iniciar una sesión

Para iniciar una sesión, basta con llamar a la función session_start(). Crea una sesión o continúa una existente basandose en el session id pasado por GET o mediante una cookie. Antes de trabajar con sesiones, siempre hemos de llamar a esta función. NOTA: session_start() siempre devuelve TRUE, por tanto no tiene sentido usarla dentro de sentencias condicionales. Si queremos conocer el identificador que se le ha dado a la sesión, podemos usar session_id() que devuelve el identificador de la sesión. En un principio, no se puede cambiar este valor, aunque las últimas versiones de PHP (a partir de la 4.3.2) suministran la función session_regenerate_id() que permite generar un nuevo identificador conservando la información que había en la sesión.

Las sesiones también tienen un nombre. Es utilizado para albergar el valor del identificador de sesión en cookies y URL’s. Por ejemplo, si tenemos desactivadas las cookies en nuestro explorador y hemos iniciado sesión, cuando cambiemos de script veremos algo similiar a lo siguiente: http://localhost/public/9-sesiones/ejemplo_sencillo/mod_sesion.php?PHPSESSID=b51fb8d0c0c1b57eba42876a157e8823 Podemos conocer el nombre de la sesión llamando a la función session_name($nuevo_nombre) que devuelve el nombre de la sesión actual. Si se le suministra el parámetro opcional $nuevo_nombre, cambiará el nombre de la sesión. Debido a que al finalizar cada script el nombre de la sesión se restaura al valor por defecto, guardado en session.name, tendremos que llamar a la función session_name($nuevo_nombre) en cada script y después5 de llamar a la función session_start(). Si nos interesara cambiar el nombre por defecto, lo podemos realizar cambiando el atributo session.name en el fichero de configuración (que por defecto vale PHPSESSID). b) Registrar variables dentro de una sesión

Registrar variables es un proceso sencillo, pues sólo tenemos que ir creando elementos dentro del vector superglobal $_SESSION (o $HTTP_SESSION_VARS). Por ejemplo, si queremos registrar el vector de usuarios $vect_usuario basta hacer:

$_SESSION[‘vect_usuario’]=$vect_usuario;

Si queremos saber si una variable está registrada en la sesión usamos la función isset(), tal y cómo hacemos habitualmente cuando queremos conocer la existencia de una variable.

5 Si se llama a session_name() para cambiar el nombre de la sesión antes de haberla iniciado, el intérprete considerará que lo que queremos hacer es crear una nueva sesión, con lo que perderemos los datos de la sesión anterior y crearemos una sesión nueva (y con distinto identificador, evidentemente).

UD5 – El lenguaje PHP 9.- Sesiones

107 / 110

Si queremos saber si el vector de películas $vect_pelis está registrado en la sesión haremos:

if (isset($_SESSION[‘vect_pelis’])) echo “El vector EXISTE”; else echo “El vector NO existe”;

Borrar una variable de la sesión es igual de fácil que cuando borrábamos elementos de un vector. Hay que hacer una llamada a la función unset(): // Queremos borrar la variable $mail de la sesión unset($_SESSION[‘mail’]); IMPORTANTE: Hay que tener en cuenta que $vect_usuario y $_SESSON[‘vect_usuario’] son variables distintas. Por tanto si modificamos o borramos una de ellas, la otra no se verá afectada. Aunque el procedimiento anterior es el más cómodo y seguro, si register_globals está activado, tenemos un método alternativo. En vez de usar los vectores anteriores, podemos registrar las variables, preguntar por su existencia y borrarlas mediante las siguientes funciones: session_register(‘variable’); // Registra $variable en la sesión session_is_registered(‘variable’); // Pregunta si $variable está registrada en la sesión session_unregister(‘variable’); // Borra $variable de la sesión Al estar register_globals activado, se puede acceder y modificar las variables de sesión como si de variables locales se tratasen, aunque si se trata de acceder a ellas dentro de alguna función o un método habrá que poner delante la palabra reservada GLOBAL. No vamos a ver cómo manejar las variables de sesión mediante estas funciones. Como ya se ha comentado antes, no es conveniente trabajar con register_globals activado y si lo está, trabajaremos como si no lo estuviese. c) Destruir una sesión

Destruir una sesión pasa por dos simples pasos: llamar a la función session_unset() que se encarga de borrar todas las variables de sesión, y seguidamente llamar a session_destroy() que destruye la sesión y borra el archivo del servidor que almacenaba los datos de la sesión. d) Almacenar en disco las variables de una sesión

Cada vez que una sesión es destruida, sus datos son borrados. Si deseamos no perder los datos de la sesión, PHP nos suministra dos funciones: session_encode() y session_decode(). La primera codifica todos los datos de la sesión en una cadena de caracteres que puede ser almacenada en una base de datos o en un fichero. La segunda realiza el procedimiento inverso: se le pasa una cadena codificada y restaura su contenido creando las variables necesarias en la sesión actual. La función devuelve TRUE si todo ha ido bien y FALSE en caso contrario. Es evidente que esto puede resultar extremadamente útil si queremos que el usuario continúe con la sesión anterior. Por ejemplo, imaginemos que tenemos una tienda electrónica y que vendemos discos. Si el usuario había metido 4 discos en el carrito de la compra pero no se había decidido a comprarlos, es interesante que la próxima vez que inicie sesión en nuestra tienda, le dejemos el carrito tal y como estaba.

UD5 – El lenguaje PHP 9.- Sesiones

108 / 110

< ?php // Iniciamos sesión session_start(); // Registramos algunas variables $_SESSION['nombre']="Gabriel"; $_SESSION['mail']="[email protected]"; // Imprimimos el contenido de $_SESSION print_r($_SESSION); echo”<br>”; // Guardamos los datos de la sesión en una variable $datos_sesion=session_encode(); // Mostramos los datos codificados por pantalla: echo $datos_sesion; // nombre|s:7:"Gabriel";mail|s:18:"[email protected]"; echo”<br>”; // Ahora vaciamos los datos de la sesión $_SESSION=Array(); // Restauramos los datos guardados en $datos_sesion session_decode($datos_sesion); // Comprobamos que había lo mismo que antes en $_SESSION print_r($_SESSION); // Destruimos la sesión session_unset(); session_destroy(); ?> Veamos a continuación un ejemplo general que ilustra el manejo completo de las sesiones: crear_sesion.php <?php // Script que crea una sesión y registra una serie de variables dentro de ella session_start(); $_SESSION['nombre']="Gabriel"; $_SESSION['mail']="[email protected]"; // Obtenemos el identificador de sesión $sesion_id=session_id(); // Obtenemos el nombre de la sesión $sesion_nombre=session_name(); // Lo imprimimos por pantalla echo "<b>Identificador de sesión:</b> $sesion_id<br>\n"; echo "<b>Nombre de la sesión:</b> $sesion_nombre<br>\n"; // Modificar el nombre de la sesión y mostrar datos echo "<br><a href='mod_sesion.php'>Modificar el nombre de la sesión y mostrar las variables de sesión</a><br>\n"; ?>

UD5 – El lenguaje PHP 9.- Sesiones

109 / 110

mod_sesion.php <?php // Script que continúa con la sesión anterior. Le cambia el nombre de la sesión // y muestra las variables registradas en la sesión. session_start(); session_name("GANDALF_WebSite"); // Obtenemos el identificador de sesión $sesion_id=session_id(); // Obtenemos el nombre de la sesión $sesion_nombre=session_name(); // Lo imprimimos por pantalla echo "<b>Identificador de sesión:</b> $sesion_id<br>\n"; echo "<b>Nombre de la sesión:</b> $sesion_nombre<br>\n"; // Imprimimos TODAS las variables registradas echo "<br>Las siguientes variables están registradas en la sesión:<br>\n"; foreach($_SESSION as $nombre => $valor) echo "<b>$nombre</b> => $valor<br>\n"; // Enlace para destruir la sesión actual echo "<br><a href='del_sesion.php'>Destruir la sesión actual</a>"; ?> del_sesion.php <?php // Este script sólo se encarga de guardar los datos de la sesión en un fichero // y destruir la sesión actual. session_start(); // Guardamos las variables de la sesión en una cadena $datos_sesion=session_encode(); echo "Datos de la sesión codificados:<br>$datos_sesion<br><br>"; // Guardamos la cadena en un fichero $fp=fopen("./sesion.dat", "w"); if (fwrite($fp,$datos_sesion)) echo "Los datos han sido guardados en disco<br>"; else echo "ERROR: Los datos NO se han podido guardar en disco<br>"; fclose($fp); // Destruimos las variables de sesión session_unset(); // Ahora ya podemos destruir la sesión actual if (session_destroy()) echo "La sesión se ha destruido satisfactoriamente"; else echo "ERROR: No se ha podido destruir la sesión"; ?>

UD5 – El lenguaje PHP 9.- Sesiones

110 / 110

rebuild_sesion.php <?php // Script que inicia sesión y trata de restaurar los datos de la sesión anterior // contenidos en el fichero sesion.dat session_start(); // Obtenemos el identificador de sesión $sesion_id=session_id(); // Obtenemos el nombre de la sesión $sesion_nombre=session_name(); // Lo imprimimos por pantalla echo "<b>Identificador de sesión:</b> $sesion_id<br>\n"; echo "<b>Nombre de la sesión:</b> $sesion_nombre<br>\n"; // Ahora restauramos los datos de la sesión anterior $fp=fopen("sesion.dat", "r"); $datos_sesion=fread($fp, filesize("sesion.dat")); fclose($fp); // Descodificamos los datos y los restauramos session_decode($datos_sesion); // Imprimimos TODAS las variables registradas echo "<br>Las siguientes variables están registradas en la sesión:<br>\n"; foreach($_SESSION as $nombre => $valor) echo "<b>$nombre</b> => $valor<br>\n"; // Enlace para destruir la sesión actual echo "<br><a href='del_sesion.php'>Destruir la sesión actual</a>"; ?>