PHP

Entorno de desarrollo.

  • El enfoque tradicional sería usar una máquina con windows o linux y:

    • Servidor web. Típicamente Apache 2.

    • Servidor de bases de datos. Típicamente Mysqsl.

    • Entorno de administración de bases de datos. Típicamente PhpMyAdmin.

  • Yo opto por usar docker. Esto me da más seguridad respecto al entorno usado por los alumnos.

  • Vamos a partir del entorno de desarrollo preparado con docker:

https://github.com/rafacabeza/entornods

  • Debemos clonar dicho repositorio en nuestro espacio de trabajo:

cd ~
git clone git@github.com:rafacabeza/entornods.git
  • Obtenemos un entorno docker para desarrollar en php:

    • Uno o más servicios web.

    • Un servicio de base de datos Mysql

    • Un servicio PhpMyAdmin para administrar las bases de datos.

  • Para gestionarlo necesitamos la consola y necesitamos ir a la carpeta que lo contine.

    cd entornods
  • Iniciar servicio:

    docker-compose up -d
  • Parar servicio:

    docker-compose down
  • Ver máquinas corriendo:

    docker-compose ps
  • En este entorno se van a usar tres sitios web de prueba. Para poder usarlos debemos engañar al DNS.

  • Debes editar tu fichero /etc/hosts para acceder a los dos sitios web creados por el mismo.

      127.0.0.1    web1.com
      127.0.0.1    web2.com 
      127.0.0.1    phpmyadmin.docker
  • Prueba a hacer ping a estos sitios.

  • Este entorno creo los siguientes contendedores en su rama master:

    • proxy: Es un proxy nginx para poder mantener simultaneamente múltiples contenedores con diferentes sitios web.

    • db: Contenedor mysql para uso de bases de datos.

    • phpmyadmin: Contenedor para administración web del anterior.

    • web1: sitios web1.com apache y php (Dockerfile web1)

    • web2: sitio web2.com con apache y php (php:7.4-apache)

  • El último sitio nos permite accede a phpmyadmin

  • Este entorno incorpora un script para inicializar una base de datos en ./data/init-db

  • Conectese a http://phpmyadmin.docker e importe el script citado.

  • Pruebe a acceder ahora de nuevo a http://web1.com/

  • Analiza lo ocurrido y crea otro sitio web en el mismo entorno llamado web3 (web3.com).

A trabajar!

Visual Studio Code

  • Vamos a añadir algunos complementos:

    • PHP IntelliSense

    • PHP Intelephense

    • PHPml (PHP in Html)

  • Atajo JSON: ctrl+shift+P + shotcut

    {
        "key": "ctrl+shift+d",
        "command": "editor.action.copyLinesDownAction",
        "when": "editorTextFocus"
    }

Entorno

  • El repositorio entornods está en su rama master. Ahí tenemos los servicios que hemos explicado.

  • Pero ahora no necesitamos web1 ni web2. Necesitamos un servicio para hacer ver ejemplos y hacer ejercicios.

  • El uso de ramas en git me permite hacer esto fácilmente

  • Vamos a cambiar a la rama ejercicios de nuestro "entornods"

    cd ~/entornods
    git checkout --track origin/ejercicios
  • Nuestro docker-compose ya está preparado para servir el contendio de "data/ejercicios". Examina el fichero docker-composer.yml para comprobarlo.

  • Lo siguiente es crear ese directorio data/ejercicios.

  • Podríamos hacerlo desde 0 pero vamos a usar el repositorio que a hemos preparado para eso.

  • Ese repositorio es propiedad del profesor. Me sirve para descargarme cosas pero no para guardar mis soluciones.

  • Por eso no me interesa hacer un "clon" sino un "fork".

    • Hacer un clon consiste en descargar el código del profesor (no me intereasa).

    • Hacer un fork consiste en copiar el repositorio del profesor en el espacio de GitHub del alumno.

    • Ese repositorio resultante es el que debe ser clonado.

    cd data
    git clone git@github.com:USUARIO_ALUMNO_EN_GITHUB/ejerciciciosphp.git
  • Una vez clonado, nuestro repositorio local está vinculado al que guardamos en GitHub

  • Podemos comprobarlo ejecutando:

    cd ejercicios
    git remote -v
  • El resultado indica algo así:

    origin    git@github.com:USUARIO_ALUMNO_EN_GITHUB/ejerciciciosphp.git (fetch)
    origin    git@github.com:USUARIO_ALUMNO_EN_GITHUB/ejerciciciosphp.git (push)
  • Como vermos más adelante, me puede interesar vincular un repositorio local a dos remotos:

    • El mío (alumno) con mis ejercicios.

    • El del profesor, por si añade ejemplos o enunciados de problemas.

  • Para hacerlo:

    cd ejercicios
    git remote add rafa git@github.com:rafacabeza/ejerciciciosphp.git
  • Nos falta preparar el fichero /etc/hosts. Debemos añadir:

    127.0.0.1     ejercicios.local
  • Ya casí está. Vamos a "entornods", paramos los servicios y los vovemos a levantar:

    cd ~/entornods
    docker-compose down
    docker-compose up -d
  • Y vamos a nuestro navegador: http://ejercicios.local

Primeros pasos

  • Damos por hecho que el alumno tiene una base de programación y de orientación a objetos.

  • Vamos a hacer un recorrido rápido sobre las bases de PHP.

  • Para completar información respecto a lo que aquí se cuenta el mejor sitio

    es la documentación oficial php.net/manual/es/

¿Qué es PHP?

  • PHP (acrónimo recursivo de "PHP: Hypertext Preprocessor") es un lenguaje de código abierto muy popular especialmente adecuado para el desarrollo web y que puede ser incrustado en HTML.

<!DOCTYPE html>
<html>
    <head>
        <title>Ejemplo</title>
    </head>
    <body>

        <?php
            echo "¡Hola, soy un script de PHP!";
        ?>

    </body>
</html>
  • PHP está construído a partir de Perl

  • Perl está basado en C.

  • Las variables son al estilo Perl

  • La sintáxis es muy similar a C (y por tanto a Java)

Sintáxis básica:

  • Los ficheros php deben tener extensión ".php"

  • El php puede estar embebido en código html

    • Los fragmentos de php deben ir etiquetasdos entre <?php ?>

  • O pueden ser ficheros código php puro.

    • Sólo debe aparecer al inicio la marca de apertura: <?php

      echo "Hola mundo!";
  • Las sentencias acaban en ";".

  • Los comentarios:

    <?php
        echo 'Esto es una prueba'; // Comentario estilo de C de una línea
        // (o C++ o Java o ....)
        /* Esto es un comentario multilínea
        y otra lína de comentarios */
        echo 'Una prueba final'; # Comentario estilo de consola de una línea
        /**
        * Comentario al estilo Phpdoc
        * Como en Javadoc ....
        */
    ?>

Tipos

  • Los tipos básicos son:

    • Entero: número entero con signo

    • Flotante: número decimal con signo

    • Booleano: vale true o false

    • Cadena de caracteres: cadena de caracteres delimitada por comillas simples o dobles.

  • Existen otros más complejos que iremos viendo:

    • Arrays

    • Objetos

    • Recursos

    • ....

  • Podemos consultar el tipo de una variable con gettype().

  • Y hacer casting para cambiar el tipo:

    $foo = 10;            // $foo es un integer
    $str = "$foo";        // $str es un string
    $fst = (string) $foo; // $fst es tambien un string
  • Casting o forzados permitidos

    • (int), (integer) - forzado a integer

    • (bool), (boolean) - forzado a boolean

    • (float), (double), (real) - forzado a float

    • (string) - forzado a string

    • (array) - forzado a array

    • (object) - forzado a object

    • (unset) - forzado a NULL (PHP 5)

Variables

  • Las variables deben comenzar por dolar: $miVariable

  • No necesitan ser declaradas, basta inicializarlas.

  • No tienen un tipo fijo.

  • Deben segir notación de estilo $camelCase;

  • Podemos consultar si una variable está definida y su tipo de dato:

    isset($variable)  //true si existe 
    empty($variable)  //true si no existe o su valor es 0 o ""
  • El ámbito de las variables es:

    • Global si está fuera de una función o una clase

    • Local dentro de funciones

  • Podemos definir variables estáticas dentro de las funciones. Su valor no cambia entre invocaciones.

  • El ámbito es compartido con ficheros incuídos.

Constantes

  • Las constantes se crear usarndo define o const

  • El estándar dice que deben ser en mayúsculas:

    define("MAXSIZE", 100);
    
    echo MAXSIZE;
    echo constant("MAXSIZE"); // lo mismo que la línea anterior
    // Funciona a partir de PHP 5.3.0
    const CONSTANTE = 'Hola Mundo';
    echo CONSTANTE;

Operadores

  • Los operadores lógicos y matemáticos son casi ideńticos a C o Java.

  • Rseñar:

    • Concatenación ..

    • Asignación y concatenacion .=, similar a +=.

  • Hay alguna curiosidad en los los de comparación

Estructuras de control

  • Las estructuras de control son muy similares a Java

  • Podemos empezar a codificar con lo que sabemos.

  • Podemos importar el contenido de otros ficheros de código con include, include_once, require, require_once

    • Require para la ejecución si no encuentra el fichero.

    • La variante "_once" comprueba que no se ha requerido/incluído el mismo fichero antes. Importante al importar clases.

  • La estructura foreach permite recorrer arrays (y otros objetos iterables).

Arrays

  • En Php un array es un tipo de dato compuesto. Es una colección de datos.

  • En un array hay una asociación entre cada valor y su clave de acceso.

  • Las claves pueden ser:

    • Números: arrays ordenados.

    • Cadenas de texto: arrays asociativos (mapas).

Declarar un array ordenado:

  • Podemos usar los corchetes o la función array.

    $frutas = ['manzana', 'naranja', 'uva'];
    $frutas = array('manzana', 'naranja', 'uva');
    $frutas = [0 => 'manzana', 1 => 'naranja', 2 => 'uva'];
    $frutas = array(0 => 'manzana', 1 => 'naranja', 2 => 'uva');
    //las cuatro sentencias son equivalentes
  • Ojo, podríamos combinar tipos de datos:

    $array = [2, 'naranja', 3.1416];
  • Y acceder así:

    echo "Me gusta la $frutas[2]";

Añadir y quitar elementos

Podemos añadir elementos. El array crece a demanda:

  $frutas[] = 'manzana'; // si fruta está vacío, posición 0
  $frutas[] = 'naranja'; // ahora posición 1
  $frutas[2] = 'uva'; //ahora posición 2 porque lo ponemos, o cualquier otra.

Y podemos eliminar elementos:

  unset($frutas[1]);

Recorrer un array

  • Lo ideal es usar un bucle foreach. Hay dos variantes:

    //si no nos preocupa la clave de cada valor
    foreach ($frutas as $fruta){
      echo $fruta . '<br>';
    }
    foreach ($frutas as $clave => $fruta){
      echo $clave . ": " . $fruta . '<br>';
    }

Arrays asociativos

  • En un array asociativo las claves para referenciar cada valor son strings.

  • Para declarar un array o añadir elementos:

    //podemos declarar un array:
    $alumno = array (
        'id' => 5,
        'nombre' => 'Manuel',
        'apellido' => 'García López',
        'edad' => 23
    );
    $alumno['sexo'] = "V"; //y podemos añadir elementos
  • Igualmente podemos usar foreach en cualquiera de sus variantes.

  • Y podemos acceder a un valor usando corchetes: $alumno['nombre'] = "Juan";

Arrays multidimensionales

  • Un elemento de un array puede ser otro array.

  • Esto nos permite definir arrays de dos o más dimensiones.

$filas  = [
    0 => [11, 12],
    1 => [21, 22],
    3 => [31, 32]
];

Formularios

  • Los formularios son la forma más común de enviar información del cliente al servidor.

  • Vamos a ver en qué consiste.

HTML

  • ¿Qué puedo encontrar en un formulario?

    • La etiqueta form que define el método (method get o post)

    • El destinatario (action)

    • Y los datos a rellenar o inputs

<form action="/ruta_destino" method="get">
    <input type="text" name="nombre" value="">
    <input type="password" name="password" value="">
    <input type="hidden" name="secreto" value="">
    <input type="submit" value="enviar">
</form>
  • El método GET envía los datos en la cabecera.

    • Los datos se ven en la barra del navegador.

    • Pueden usarse en enlaces.

    http://misitioweb.com/destino.php?nombre="juan"&edad="16"
  • El método POST envía los datos en el cuerpo. Es más seguro.

    http://misitioweb.com/destino.php
  • Normalmente el formulario lo crea un fichero y recibe sus datos otro fichero indicado en el action.

  • El action puede:

    • Usar rutas absolutas (RECOMENDABLE)

    action="/destino.php"
    • Usar rutas relativas

      action="destino.php"
    • Hacer referencia al fichero actual

      `action="#"`
  • Los input que debéis usar son los del ejemplo: text, password, hidden y submit.

  • No debéis usar tipos como numeric o date. Estos tipos mejoran la esperiencia de usuario pero no permiten probar algunas cosas en el servidor. No nos interesa usarlos en este módulo

Variables superglobales

  • Las variables superglobales son creadas por el sistema.

  • Las variables que podemos encontrar son:

    • $_SERVER. Inf. del script actual y del servidor.

    • $_GET. Datos formulario con método GET.

    • $_POST. Idem con método POST.

    • $_FILES. Ficheros enviados en un formulario.

    • $_COOKIE. Cookies (para más adelante)

    • $_REQUEST. Combina las tres anteriores.

    • $_SESSION. Datos de sesión (para más adelante)

    </small>

Recepción de datos

  • Los datos se reciben así:

    $nombre = $_GET['nombre']; //si el método es GET
    $nombre = $_POST['nombre']; //si es POST
    $nombre = $_REQUEST['nombre'];//válido en ambos casos
  • Puede ser conveniente comprobar si existe la variable:

if (isset($_GET['nombre'])) {
  $nombre = $_GET['nombre'];
} else {
  $nombre = '';
}

Elegir entre varias opciones:checkbox, radio y select

  • Para entender las posibilidades debes analizar el ejemplo 11.

  • Si queremos elegir uno entre varios podemos usar

    • Radio:

    <input type="radio" name="sexo" value="male" checked> Varón <br>
    <input type="radio" name="sexo" value="female"> Mujer <br>
    • Select:

    <select name="color">
        <option>rojo</option>
        <option>azul</option> 
        ...
        <option selected>blanco</option>
    </select>

    MIRA BIEN: para preseleccionar una opción debemos usar checker o selected.

  • Si queremos seleccionar varios entre varios debemos usar checkbox (o select multiple).

  • En ambos casos nos interesa recibir un array con la colección de varios elegida.

  • En PHP, debemos nombrar a nuestros inputs (o select) con corchetes:

    <input type="text" name="ideas[]"> 
    <input type="text" name="ideas[]">
  • Otra cosa interesante es que un script puede enviarse los datos a sí mismo. Basta con poner en el action del formulario el propio script, o más fácil todavía, dejando el action en blanco:

    //Código del ejemplo 13
    <form action="">
      <input type="text" name="nombres[]">
      <input type="submit" value="Nuevo">  
      <hr>
      <?php
      if (isset($_GET['nombres'])) {
        foreach($_GET['nombres'] as $nombre) {
          echo '<input type="text" name="nombres[]" value="' . $nombre . '"><br>';
        }
      }
      ?>
    </form>

Ejercicio

  • Crea un formulario para enviar los datos de registro de un libro: título, autor, editorial, páginas.

Ejercicio

  • Crea un formulario para enviar campo nombre. Si el nombre existe se da un saludo. Si no existe se vuelve atrás indicando que el campo es obligatorio.

Ejercicio

  • Envío del script al mismo script. Crea un formulario para enviar campo nombre. El nombre debe existir y debe tener un tamaño mínimo de 3 caracteres. Si es válido se da un saludo. Si no lo es se vuelve a mostar el formulario indicando que el campo es obligatorio y mostrando en el "input" el valor anterior no válido.

Ejercicio

  • Envío del script al mismo script. Crea un formulario que funcione como calculadora. Debe contener dos input como operandos y un select para elegir operador.

    • Si se reciben los datos muestra el resultado.

    • Si no son válidos o no existen debe devolver a la página anterior.

Ejercicio

  • Crea un formulario que envíe un array de 3 nombres. Para hacerlo debes usar el mismo nombre en todos los input (name="nombres[]").

Ejercicio

  • Crea una lista usando etiquetas ul y li. La lista inicialmente estará vacía pero un formulario con un input servirá para añadir los elementos. Usa input de tipo hiddens para que no "olvidar" los elementos ya añadidos a la lista.

Funciones

  • Php es un lenguaje de scripting. El punto de entrada es la primera línea de un script siempre.

  • Pero soporta programación estructurada, por tanto funciones, y programación orientada a objetos, por tanto clases.

  • No vamos a poner mucha energía en las funciones (sí en POO), pero veamos un ejemplo:

      <?php
    
      function factorial($numero) {
        $resultado = 1;
        for ($i=1; $i <= $numero; $i++) { 
          $resultado = $resultado * $i;
        }
        return $resultado;
      }
      echo "El factorial de 5 es " . factorial(5);
      echo "<br>";
      echo "Y el factorial de 10 es " . factorial(10);
      ?>

POO

  • Php soporta POO desde la versión 5

  • En las versiones 7.* las posibilidades son muy completas.

  • Vamos a ver las cuestiones básicas.

  • Conceptos base: clases, objetos, atributos y métodos.

  • Visibilidad: public, protected, private

  • Métodos mágicos: constructor, destructor, toString, ...

  • Herencia, interfaces, métodos y atributos estáticos y finales

  • Muchas cosas y algunas de ellas no las emplearemos nunca.

  • Vamos a ir explicando conceptos ya conocidos segun nos haan falta.

Notación

  • Nombre de la clase CamelCase.

  • Una clase - un fichero, y ambos con el mismo nombre.

  • Atributos y funciones con nombres camelCase

class ClaseSencilla
{
    // Declaración de una propiedad
    public $var = 'un valor predeterminado';

    // Declaración de un método
    public function mostrarVar() {
        echo $this->var;
    }
    //NOTA: $this hace referenca a este objeto
    //"->" se usa para acceder a métodos y atributos
}
?>

Métodos mágicos

  • Reciben este nombre los que se ejecutan de foma "mágica". Sin petición explícita.

  • Siempre empiezan por doble guión bajo. Los más destacables:

    • __construct(): constructor. Se ejecuta al crear un objeto.

    • __destruct(): destructor. Se ejecuta al eliminar un objeto.

    • __toString(): se ejecuta cuando imprimimos un objeto. Lo convierte a string.

Particularidades

  • Para acceder a métodos y atributos usamos "->".

  • Para acceder a constantes de clase y métodos estáticos usamos "::"

  • Para referirnos al propio objeto usamos $this

Mi primera clase

<?php

class Persona  
{
  public $nombre;
  public $apellido;
  public $edad;

  public function __construct($nombre, $apellido, $edad)
  {
    $this->nombre = $nombre;
    $this->apellido = $apellido;
    $this->edad = $edad;
  }

  public function saludar()
  {
    echo "Buenos días!";
  }

  public function __toString()
  {
    return $this->nombre;
  }
}
  • Y ahora la usamos:

<body>
  <?php
    require('Persona.php');
    $juan = new Persona('Juan', 'García', 15);

    echo $juan-> saludar();
    echo "<br>";
    echo "Soy $juan";
    echo "<br>";
    echo "Mi nombre completo es $juan->nombre $juan->apellido y tengo $juan->edad años";
  ?>
</body>

Una clase como aplicación web

  • El script de entrada:

<?php

require_once "App.php";
$app = new App;
$app->run();
  • La clase

<?php

class App
{
  public function __construct($name = "Aplicación PHP")
  {
    echo "Consturyendo la app <hr>";
    $this->name = $name;
    $this->module = "Desarrollo Web en Entorno Servidor";
    $this->teacher = "Rafael Cabeza";
    $this->student = "Fulano De Tal";
  }

  public function run()
  {
    echo "Moneda al aire... <hr>";
    $moneda = rand(0,1);
    // if ($moneda == 1) {
    if ($moneda) {
      echo "<h3>Ha salido cara:  </h3> <br>";
      $this->index();
    } else {
      echo "<h3> Ha salido cruz: </h3> <br>";
      $this->login();
    }
  }

  public function index()
  {
    echo "Estamos en el index<br>";
    echo "Estos es $this->name<br>";
    echo "Me llamo $this->student<br>";
    echo "Estamos estudiando $this->module con el profesor $this->teacher<br>";
  }

  public function login()
  {
    echo "Ahora podría mostrar un formulario de login <br>";
  }  
}

Separar vista de lógica

  • Pero podemos ser un poco formales en nuestro código:

    • Los cálculos que debamos hacer los hacemos dentro de un método de la clase. Un fichero php puro.

    • El html lo generaremos en un fichero mixto html/php.

  • Esto no es obligatorio. No es requisito del lenguaje. Pero nos ayudará a crear código limpio.

  • Podríamos trasformar nuestra clase así:

  public function index()
  {
    echo "Estamos en el index<br>";
    include('views/index.php');
  }

  public function login()
  {
    echo "Estamos en login <br>";
    include('views/form.php');
  }
  • Ojo. Necesiamos un carpeta views

  • Y nuestras vistas quedarían así:

...
<body>
  <h1>Home de <?= $this->name ?></h1>
  <div>
  Estamos en el index
  </div>

  Me llamo <?= $this->student ?>
  <br>
  Estamos estudiando <?= $this->module ?> con el profesor <?= $app->teacher ?>
</body></html>
...
<body>
  <h1>Login de  <?= $this->name ?></h1>

  <form action="">
    <label for="">nombre</label>
    <input type="text" name="name"> <br>
    <label for="">contraseña</label>
    <input type="password" name="password"> <br>
    <input type="submit">
  </form>
</body>
</html>
  • Vamos a refinar un poco más nuestra aplicación

  • Dejemos de jugar al azar. ¿Cómo decidimos qué método?

  • Podemos hacerlo de muchas maneras. Vamos a optar por argumentos GET.

http://ejercicios.local/ejemplos/18/index.php?method=index
http://ejercicios.local/ejemplos/18/index.php?method=login
//equivalente:
http://ejercicios.local/ejemplos/18?method=index
http://ejercicios.local/ejemplos/18?method=login
  • Debemos recoger esos argumentos en el run de App:

  public function run()
  {
    if (isset($_GET['method'])) {
      $method = $_GET['method'];
    } else {
      $method = 'index';
    }
    $this->$method();
  }
  • Y debemos añadir enlaces en ambas páginas.

    <header>
      <ul>
        <li><a href="/ejemplos/18?method=index">Inicio</a></li>
        <li><a href="/ejemplos/18?method=login">Login</a></li>
      </ul>
    </header>
  • ¿Lo ponemos en cada vista?

    • Mejor creamos un header.php

    • Y lo incluímos en ambas vistas

      <?php
        require('views/header.php');
      ?>
  • Además podemos añadir un poco de CSS

ul {
  list-style-type: none;
  margin: 0;
  padding: 0;
  overflow: hidden;
}

li {
  float: left;
}

li a {
  display: block;
  padding: 8px;
  background-color: #dddddd;
}

Ejercicio.

  • Crea una aplicación web con una clase App y varios métodos. En todos los casos se trata de obtener una serie numérica. El método debe calcular la serie y guardarla en un array, después hay que incluir una vista que muestre la serie. Puede ser que necesites crear métodos auxiliares (private) para el cálculo del array, por ejemplo: esPrimo(). Los métodos necesarios son:

  • Index (index). Presentación de la App y enlaces.

  • Fibonacci (fibonacci). Muestra la serie de Fibonacci. Debe mostrar todos los términos menores a un millón.

  • Potencias de 2 (potencias2). Debe mostrar los valores de las potencias de 2 hasta 2 elevado a 24 (nº de colores True Color, por ejemplo).

  • Factorial (factoriales). Debe mostar los factoriales desde 1 hasta n de tal manera que el último término sea el más próximo cercano al millón.

  • Nº. primos (primos). Debe encontrar los números primos entre 1 y 10.000.

Cookies

  • Una cookie es un fichero de texto que se guarda en el equipo del cliente.

  • Este fichero está ligado al sitio web que lo crea y al navegador usado.

  • En él se almacena el contenido de un array de variables.

  • Se crea mediante la función setcookie(). La función necesita:

    • Clave: nombre de la variable.

    • Valor: contenido de la misma. Debe ser texto (o convertible).

    • Tiempo unix de vida (en segundos). Por defecto, 0, se elimina al cerrar el navegador.

  • Se accede a su contenido mendiante la variable superglobal $_COOKIE

  • Para eliminar una cookie usa setcookie con tiempo menor al actual:

setcookie(x,y,time()-1)
  • Ejemplo de creación de cookies. Incluso arrays y objetos:

    setcookie("user", "Fulanito de Tal", time() + 3600);

    //ojo para guardar arrays:
    $hobbies = ['futbol', 'música rock', 'tocar la guitarra con mis amigos'];
    setcookie("hobbies", serialize($hobbies), time() + 3600);
    setcookie("hobbies2", json_encode($hobbies), time() + 3600);

    //y objetos:
    $persona = new Persona("Juan", "Pérez", 21);
    setcookie("persona", serialize($persona), time() + 3600);
    setcookie("persona2", json_encode($persona), time() + 3600);
  • Arrays y objetos deben tratarse con:

    • serialize/unserialize: nativo php. Los objetos se recrean en su clase.

    • json_encode/json_decode: estándar. Los objetos se recrean como stdClass.

Reenvío

  • Habitualmente una petición acaba con la construcción de una vista html.

    • home: página de inicio de una apliación

    • login: página con formulario de entrada, ...

  • Pero otras veces queremos que el servidor haga una tarea y después el navegador vaya a una dirección determinada. Por ejemplo:

    • auth: toma los datos de login. Si son "buenos" reenvía a "home" y si son malos reenvía a "login" de nuevo.

  • Para hacer esto hay que usar el status 302 de HTTP.

  • Con php debemos hacer esto con la función header. Veamos ejemplos

    header('Location: direccion');
    header('Location: /index.php');
    header('Location: ?method=home');
    header('Location: https://google.com');
  • Siempre que te pidan reenvío usa header() y no include()

Ejercicio

  • Vamos a crear una App con estos métodos:

    • login: muestra un formulario de login (usuario y contraseña).

    • auth: guarda el usuario y su contraseña en una cookie. Después reenvía la petición a home.

    • home: Muestra un saludo y un enlace para cerrar sesión.

    • logout: elimina las cookies (setcookie(...., time() - 1)) y reenvía a login.

  • Depura tu código. En login, comprueba que no hay ya un usuario. Si lo hay reenvía a home.

Enlaces que aportan información

  • Ya hemos visto que los enlaces pueden incluir parámetros "GET".

  • Cuando manejamos listas podemos definir enlaces con mucha información. Veamos un ejemplo para luego usarlo en un ejercicio:

    <?php foreach ($lista as $id => $element) { ?>
      <li>
        <?= $element ?>     
        <a href="?method=ver&id=<?= $id ?>">Ver</a> -
        <a href="?method=borrar&id=<?= $id ?>">Borrar</a>
      </li>  
    <?php } ?>

Ejercicio 19

Se trata de crear una lista de deseos Usaremos la clase App con los siguietens métodos:

  • login método que muestra formulario de entrada.

  • auth método que toma el nombre de usuario tras el login. Tras hacer esto reenvía a home.

  • home método que muestra la lista de deseos. Además muestra un formulario de nuevos deseos. El formulario envía al método new

  • new toma el nuevo deseo y lo incluye en la lista.

  • delete borra un deseo de la lista. Debe recibir el indice del deseo.

  • empty vacía la lista de deseos.

  • close Cierra sesión: borra la cookie.

Ejercicio 20

Colorear una página con ayuda de una cookie. Usaremos la clase App con los siguietens métodos:

  • home muestra un mensaje de bienvenida. Comprueba si hay una cookie llamada "color". Si existe la usa para darle color al fondo de la ágina.

  • colores muestra una lista de colores. Cada color tiene un enlace del estilo ?method=cambio&color=red . Al hacer clic cambiará el color del home.

  • cambio . Recibe el color de la página anterior, crea la cookie y reenvia ('header...') al método home.

NOTA: dos vistas (home y colores) y un reenvío (cambio).

Sesiones

  • También llamadas cookies del lado del servidor.

  • Guardan la información en el servidor (RAM, fichero, BBDD, ...).

  • Se apoyan en una cookie que se envía al navegador y que sirve de clave para recuperar la información almacenada.

  • Antes de agregar o acceder a las variables de sesión, debemos "avisar" con la función session_start().

  • Al iniciar la sesión se crea un id aleatorio para la sesión. Este id se puede transmitir en la url o guardar en una cookie de forma transparente al programador. La opción de la url es poco recomendaable por segurirdad.

  • La información se guarda en la variable superglobal $_SESSION. Es un array al que podemos añadir elementos según necesitamos y que podemos leer como es habitual.

  • Añadir elementos a sesión:

$_SESSION['name'] = $name;
//añadir elementos a un array dentro de la sesión
$_SESSION['deseos'][] = $new;
//lo mismo pero más "pensado"
$deseos = $_SESSION['deseos'];
$deseos[] = $new;
$_SESSION['deseos'] = $deseos;
  • Se pueden elimnar elementos selectivamente o borar toda la sesión:

 unset($_SESSION['elemento']); #borra un elemento
 session_destroy(); #elimina toda la información de sesión.

Sobre las opciones de sesión. Sus parámetros se establecen en el php.ini: enlace.

Cookie o url.
Autostart, para requerir el uso de session_start() o no.
Tiempo de vida
Nombre (por defecto PHPSESSID)
otros...

Ejercicio 21

  • Haz el ejercicio 19 pero usando sesiones en vez de cookies

Ejercicio 22

  • Haz el ejercicio 20 pero usando sesiones en vez de cookies

Excepciones

  • Una excepción es un objeto. Describe un error o comportamiento indeseado.

  • Existe en php como en otros muchos lenguajes, p.ej. Java.

  • Sirven para parar el funcionamiento normal ante situaciones indeseadas.

  • Muchas funciones y clases del lenguaje lanzan excepciones.

  • En nuestro código también podemos lanzar excepciones.

<?php
function dividir($dividendo, $divisor) {
  if($divisor == 0) {
    throw new Exception("División por cero");
  }
  return $dividendo / $divisor;
}

//esto funciona
echo dividir(5, 3);
//esto va a fallar porque no sabemos que hacer con la excepción
echo dividir(5, 0);

La sentencia try..catch

  • Su sintáxis es:

try {
  //código que puede lanzar excepciones
} catch(Exception $e) {
  //código que coge (catch) la excepción
  //se ejecuta si se lanza una excepción
}
  • Ejemplo:

<?php
function dividir($dividendo, $divisor) {
  if($divisor == 0) {
    throw new Exception("División por cero");
  }
  return $dividendo / $divisor;
}

try {
  echo dividir(5, 3) . "<br>";
  echo dividir(5, 0) . "<br>";
} catch (Throwable $e) {
  echo "Fallo: " . $e->getMessage();
}

Sentencia try...catch...finally

  • Permite añadir código que se ejecute siempre, haya o no excepción.

try {
  //código que puede lanzar excepciones
} catch(Exception $e) {
  //código que coge (catch) la excepción
  //se ejecuta si se lanza una excepción
} finally {
  //código que se ejecuta siempre,
  //haya o no excepción
}
  • Ejemplo

<?php
function dividir($dividendo, $divisor) {
  if($divisor == 0) {
    throw new Exception("División por cero");
  }
  return $dividendo / $divisor;
}

try {
  echo dividir(5, 3) . "<br>";
  echo dividir(5, 0) . "<br>";
} catch (Throwable $e) {
  echo "Fallo: " . $e->getMessage();
} finally {
  echo "<hr>";
  echo "divisiones acabadas";
}

El objeto "Exception"

  • Al crear un objeto exception podemos pasar 3 atributos:

 new Exception(message, code, previous)
  • message es un texto. Parámetro principal

  • code un código numérico de error

  • previous se usa si lanzamos una excepción dentro de un catch

  • La excepción recibida dispone de los métodos:

    • getMessage(), getter del message.

    • getPrevious(), getter del previous

    • getCode(), getter del code

    • getFile(), devuelve el fichero que lanza la excepción

    • getLine(), devuelve la línea que lanza la excepción

    • getTrace(), devuelve array con la traza de la pila de llamadas.

    • getTraceAsString(), idem convertido a texto.

Excepciones a medida

  • Podemos crear nuestro propio tipo de excepciones:

<?php
class emailException extends Exception {
  public function errorMessage() {
    //error message
    $errorMsg = 'Error en la línea '.$this->getLine().' del fichero '.$this->getFile()
    .': <b>'.$this->getMessage().'</b> no es una dirección válida de correo';
    return $errorMsg;
  }
}

$email = "someone@example...com";

try {
  if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE) {
    throw new emailException($email);
  }
}
catch (emailException $e) {
  echo $e->errorMessage();
}
  • Incluso más de una:

<?php
class emailException extends Exception {
  public function errorMessage() {
    //error message
    $errorMsg = 'Error en la línea '.$this->getLine().' del fichero '.$this->getFile()
    .': <b>'.$this->getMessage().'</b> no es una dirección válida de correo';
    return $errorMsg;
  }
}

class ageException extends Exception {
  public function errorMessage() {
    $errorMsg = 'Error en la línea '.$this->getLine().' del fichero '.$this->getFile()
    .': <b>'.$this->getMessage().'</b> no es una edad válida';
    return $errorMsg;
  }
}

$email = "someone@example...com";
$age = "-5";

try {
  if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE) {
    throw new emailException($email);
  }
  throw new ageException($age);
    if($age < 0) {
  }

}
catch (emailException $e) {
  echo $e->errorMessage();
}
catch (ageException $e) {
  echo $e->errorMessage();
}
  • Podríamos incluso añadir un catch por defecto:

$email = "someone@example...com";
$age = "-5";
$condition = true; 
try {
  if ($condition) {
    throw new Exception("excepción por que sí!");
  }
  if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE) {
    throw new emailException($email);
  }
  throw new ageException($age);
    if($age < 0) {
  }
}
catch (emailException $e) {
  echo $e->errorMessage();
}
catch (ageException $e) {
  echo $e->errorMessage();
}
catch ($e) {
  echo $e;
}

Ficheros

if (!$fp = fopen("miarchivo.txt", "r")){
  echo "No se ha podido abrir el archivo";
}
  • El fichero puede ser incluso una url:

$fp = fopen("http://localhost/miarchivo.txt", "r");
  • Donde modo:

r   Apertura para lectura. Puntero al principio del archivo
r+  Apertura para lectura y escritura. Puntero al principio del archivo
w   Apertura para escritura. Puntero al principio del archivo y lo sobreescribe. Si no existe se intenta crear.
w+  Apertura para lectura y escritura. Puntero al principio del archivo y lo sobreescribe. Si no existe se intenta crear.
a   Apertura para escritura. Puntero al final del archivo. Si no existe se intenta crear.
a+  Apertura para lectura y escritura. Puntero al final del archivo. Si no existe se intenta crear.
x   Creación y apertura para sólo escritura. Puntero al principio del archivo. Si el archivo ya existe dará error E_WARNING. Si no existe se intenta crear.
x+  Creación y apertura para lectura y escritura. Mismo comportamiento que x.
c   Apertura para escritura. Si no existe se crea. Si existe no se sobreescribe ni da ningún error. Puntero al principio del archivo.
c+  Apertura para lectura y escritura. Mismo comportamiento que C.

Ojo:

  • Si el archivo no es escribible, abrirlo con r+ fallará, incluso cuando sólo se intenta leer.

  • w y w+ eliminarán el contenido de cualquier archivo. Para sólo añadir y no borrar, se usa a y a+.

  • Si quieres crear nuevos archivos y evitar sobreescribir sin querer un archivo existente, utiliza x o x+.

  • Cuando se trabaja con archivos binarios, como imágenes, hay que añadir 'b' después del modo. Como rb o r+b

  • Ejemplo de escritura

<?php
$file = fopen("archivo.txt", "w");
fwrite($file, "Esto es una nueva linea de texto" . PHP_EOL);
fwrite($file, "Otra más" . PHP_EOL);
fclose($file);
echo "texto escrito!!";
  • Ejemplo de añadir texto:

<?php
$file = fopen("archivo.txt", "a");
fwrite($file, "Linea anexada en: " . time() . PHP_EOL);
fclose($file);
echo "texto escrito!!";
echo "<hr>";
  • Ejemplo de lectura completa:

<?php
$file = "miarchivo.txt";
$fp = fopen($file, "r");
$contents = fread($fp, filesize($file));
fclose($fp);
var_dump($contents);

<<<<<<< HEAD

Ejercicio 23.

  • Crea una aplicación para almacenar una lista de deseos

  • Lista de métodos:

    • home, método por defecto. Muestra la lista de deseos y un formulario para añadir nuevos.

    • new, toma la informacion del nuevo deseo y lo añade al fichero. Después reenvía a home.

    • clear, borra toda la lista de deseos y velve al home.

  • delete, borra selectivamente elementos de la lista de deseos. Mira el siguiente ejemplo para ver como cargar las líneas del fichero en un array. NOTA: debes, cargar el array, borrar el elemento y volver a escribir el fichero completo.

<?php
$fp = fopen("archivo.txt", "r");
if ($fp) {
    while (($line = fgets($fp)) !== false) {
        $lista[] =  $line;
    }
    if (!feof($fp)) {
        echo "Error: fallo inesperado de fgets()\n";
    }
    fclose($fp);
    foreach ($lista as $key => $item) {
        echo "$key: $item <br>";
    }
} else {
    echo "datos no disponibles";
}

=======

Ejercicio 23

Realiza el ejercicio de la lista de deseos usando un fichero deseos.txt. Usa seriel

  • Método index, lee el contendio de la lista de deseos.

  • Método new, crea un

    ea147b71ce3839cc9819e8b4cb1db6c0151c0319

Last updated