Ejercicios - Bases de datos (3 B) - Ayuda

En construcciónEsta página de comentarios está en elaboración.

Esta página contiene comentarios ampliados con fragmentos de código PHP de los ejercicios Base de datos (3 B).

Bases de datos (3 B) - 1 - Mejoras en la aplicación (1)

  1. Al borrar todo, ofrecer la opción de insertar automáticamente algunos registros de prueba.
    • [administrador/borrar-todo-1.php]

      Podemos incluir un control para que el usuario indique si quiere incluir registros de prueba en la base de datos ...

      print "      <p><label><input type=\"checkbox\" name=\"demo\" value=\"Sí\"> Incluir datos de prueba</label></p>\n";
      
    • [administrador/borrar-todo-2.php]

      ... recogerlo y en caso afirmativo, llamar a una función que incluya los registros de prueba:

      $demo   = recoge("demo");
      ...
      
      if ($demo == "Sí") {
          insertaDemo();
      }
      
    • [comunes/demo.php]

      Podemos indicar los registros a crear en una matriz e insertarlos recorriendo la matriz. En el ejemplo, los registros incluyen incluso el valor del id. En este caso no es necesario, pero sí lo sería si los registros de una tabla hicieran referencia a los registros de otra tabla, como ocurre en el ejercicio 4, por lo que preparamos ya el código para esa situación.

      // Registros de prueba opcionales
      
      $cfg["registrosDemo"] = [
          [$cfg["dbUsuariosTabla"], [2, "usuario1", encripta("usuario1"), NIVEL_USUARIO_BASICO]],
          [$cfg["dbUsuariosTabla"], [3, "usuario2", encripta("usuario2"), NIVEL_USUARIO_BASICO]],
          [$cfg["dbUsuariosTabla"], [4, "admin1", encripta("admin1"), NIVEL_ADMINISTRADOR]],
          [$cfg["dbPersonasTabla"], [1, "Pepito", "Conejo", "271828182", "pepito.conejo@example.com"]],
          [$cfg["dbPersonasTabla"], [2, "Numa", "Nigerio", "161803398", "numa.nigerio@example.com"]],
          [$cfg["dbPersonasTabla"], [3, "Fulanito", "Mengánez", "314159265", "fulanito.menganez@example.com"]],
      ];
      
      function insertaDemo()
      {
          global $cfg, $pdo;
      
          print "    <p>Insertando registros de prueba ...</p>\n";
          print "\n";
          foreach ($cfg["registrosDemo"] as $registro) {
              if ($registro[0] == $cfg["dbUsuariosTabla"]) {
                  $consulta = "INSERT INTO $cfg[dbUsuariosTabla]
                               (id, usuario, password, nivel)
                               VALUES ({$registro[1][0]}, '{$registro[1][1]}', '{$registro[1][2]}',  {$registro[1][3]})";
              } elseif ($registro[0] == $cfg["dbPersonasTabla"]) {
                  $consulta = "INSERT INTO $cfg[dbPersonasTabla]
                               (id, nombre, apellidos, telefono, correo)
                               VALUES ({$registro[1][0]}, '{$registro[1][1]}', '{$registro[1][2]}', '{$registro[1][3]}', '{$registro[1][4]}')";
              }
      
              if (!$pdo->query($consulta)) {
                  print "    <p class=\"aviso\">Error al preparar la consulta. SQLSTATE[{$pdo->errorCode()}]: {$pdo->errorInfo()[2]}</p>\n";
              } else {
                  print "    <p>Registro creado correctamente.</p>\n";
              }
              print "\n";
          }
      }
      
  2. En SQLite, si no existe el directorio donde se quiere guardar la base de datos, mostrar un mensaje indicando el problema.
    • [comunes/biblioteca-sqlite.php]

      Podemos aplicar la función dirname(), que devuelve el camino padre (en este caso, elimina el nombre del archivo), a la variable de configuración $cfg["sqliteDatabase"]. Y a su resultado la función is_dir(), que indica si el camino es un directorio (es decir, si existe).

      function conectaDb()
      {
          global $cfg;
      
          if (!is_dir(dirname($cfg["sqliteDatabase"]))) {
              print "    <p class=\"aviso\">Error: El directorio <strong>" . dirname($cfg["sqliteDatabase"]) . "</strong> no está disponible.</p>\n";
              exit;
          } else {
              ...
      
  3. Al modificar el registro de un usuario, ofrecer la posibilidad de mantener la contraseña (por ejemplo, marcando una casilla).
    • [db/tabla-usuarios/modificar-2.php]

      En el formulario incluimos una casilla de verificación ...

              print "          <tr>\n";
              print "            <td>Contraseña:</td>\n";
              print "            <td>\n";
              print "              <input type=\"text\" name=\"password\" size=\"$cfg[formUsuariosTamPassword]\" maxlength=\"$cfg[formUsuariosTamPassword]\">\n";
              print "              <input type=\"checkbox\" name=\"mantenerPassword\" value=\"Sí\"> Mantener contraseña actual\n";
              print "            </td>\n";
              print "          </tr>\n";
      
    • [db/tabla-usuarios/modificar-3.php]

      ... recogemos el control y en función de su valor mantenemos o cambiamos la contraseña:

      $mantenerPassword = recoge("mantenerPassword");
      ...
                      } elseif ($mantenerPassword == "Sí") {
                          $consulta = "UPDATE $cfg[dbUsuariosTabla]
                                       SET usuario = :usuario, nivel = :nivel
                                       WHERE id = :id";
                          $resultado = $pdo->prepare($consulta);
                          if (!$resultado) {
                              print "    <p class=\"aviso\">Error al preparar la consulta. SQLSTATE[{$pdo->errorCode()}]: {$pdo->errorInfo()[2]}</p>\n";
                          } elseif (!$resultado->execute([":usuario" => $usuario, ":nivel" => $nivel, ":id" => $id])) {
                              print "    <p class=\"aviso\">Error al ejecutar la consulta. SQLSTATE[{$pdo->errorCode()}]: {$pdo->errorInfo()[2]}</p>\n";
                          } else {
                              print "    <p>Registro modificado correctamente.</p>\n";
                          }
                      } else {
                          $consulta = "UPDATE $cfg[dbUsuariosTabla]
                                       SET usuario = :usuario, password = :password, nivel = :nivel
                                       WHERE id = :id";
                          $resultado = $pdo->prepare($consulta);
                          if (!$resultado) {
                              print "    <p class=\"aviso\">Error al preparar la consulta. SQLSTATE[{$pdo->errorCode()}]: {$pdo->errorInfo()[2]}</p>\n";
                          } elseif (!$resultado->execute([":usuario" => $usuario, ":password" => encripta($password), ":nivel" => $nivel, ":id" => $id])) {
                              print "    <p class=\"aviso\">Error al ejecutar la consulta. SQLSTATE[{$pdo->errorCode()}]: {$pdo->errorInfo()[2]}</p>\n";
                          } else {
                              print "    <p>Registro modificado correctamente.</p>\n";
                          }
      
      
  4. Hacer que no se aplique el límite del número de registros en las tablas si el valor de $cfg["dbPersonasMaxReg"] o $cfg["dbUsuariosMaxReg"] es 0 o negativo.
    • [db/tabla-personas/insertar-1.php, db/tabla-personas/insertar-2.php, db/tabla-usuarios/insertar-1.php, db/tabla-usuarios/insertar-2.php]

      Modificamos la condición de superación del número máximo de registros para que no se cumpla si la variable de configuración no es mayor que 0:

          ...
      } elseif ($resultado->fetchColumn() >= $cfg["dbUsuariosMaxReg"] && $cfg["dbUsuariosMaxReg"] > 0) {
          ...
      

Bases de datos (3 B) - 2 - Mejoras en la aplicación (2)

En construcciónPor escribir.

Bases de datos (3 B) - 3 - Nueva base de datos: PostgreSQL

En construcciónPor escribir.

Bases de datos (3 B) - 4 - Agenda multiusuario (1)

Modifique la aplicación de manera que cada usuario básico de la aplicación sólo pueda trabajar con sus propios registros de Personas (listar, borrar, buscar, modificar).

  1. Añada en la tabla Personas un campo que contenga el id del usuario que crea el registro.
    • [comunes/biblioteca-sqlite.php]
      // SQLITE:
          $consulta = "CREATE TABLE $cfg[dbPersonasTabla]  (
                       id INTEGER PRIMARY KEY,
                       nombre VARCHAR($cfg[dbPersonasTamNombre]) COLLATE NOCASE,
                       apellidos VARCHAR($cfg[dbPersonasTamApellidos]) COLLATE NOCASE,
                       telefono VARCHAR($cfg[dbPersonasTamTelefono]) COLLATE NOCASE,
                       correo VARCHAR($cfg[dbPersonasTamCorreo]) COLLATE NOCASE,
                       id_usuario INTEGER,
                       FOREIGN KEY(id_usuario) REFERENCES $cfg[dbUsuariosTabla](id) ON DELETE CASCADE ON UPDATE CASCADE
                       )";
      
    • [comunes/biblioteca-mysql.php]
      // MYSQL:
                       $consulta = "CREATE TABLE $cfg[dbPersonasTabla]  (
                                    id INTEGER UNSIGNED AUTO_INCREMENT,
                                    nombre VARCHAR($cfg[dbPersonasTamNombre]),
                                    apellidos VARCHAR($cfg[dbPersonasTamApellidos]),
                                    telefono VARCHAR($cfg[dbPersonasTamTelefono]),
                                    correo VARCHAR($cfg[dbPersonasTamCorreo]),
                                    id_usuario INTEGER UNSIGNED,
                                    FOREIGN KEY(id_usuario) REFERENCES $cfg[dbUsuariosTabla](id) ON DELETE CASCADE ON UPDATE CASCADE,
                                    PRIMARY KEY(id)
                                    )";
      
    • [comunes/biblioteca.php]

      Para que se puedan ordenar los listados por el campo usuario debemos añadirlo a la matriz $cfg["dbPersonasColumnasOrden"]. Añadimos "usuario" y no "id_usuario" porque la columna mostrará el nombre del usuario.

      // Valores de ordenación de las tablas
      
      $cfg["dbPersonasColumnasOrden"] = [
          "nombre ASC", "nombre DESC",
          "apellidos ASC", "apellidos DESC",
          "telefono ASC", "telefono DESC",
          "correo ASC", "correo DESC",
          "usuario ASC", "usuario DESC",
      ];
      
    • [comunes/demo.php]

      Los registros de prueba deben incluir el campo id_usuario. Por ejemplo:

      // Registros de prueba opcionales
      
      $cfg["registrosDemo"] = [
          [$cfg["dbUsuariosTabla"], [2, "usuario1", encripta("usuario1"), NIVEL_USUARIO_BASICO]],
          [$cfg["dbUsuariosTabla"], [3, "usuario2", encripta("usuario2"), NIVEL_USUARIO_BASICO]],
          [$cfg["dbUsuariosTabla"], [4, "admin1", encripta("admin1"), NIVEL_ADMINISTRADOR]],
          [$cfg["dbPersonasTabla"], [1, "Pepito", "Conejo", "271828182", "pepito.conejo@example.com", 2]],
          [$cfg["dbPersonasTabla"], [2, "Numa", "Nigerio", "161803398", "numa.nigerio@example.com", 2]],
          [$cfg["dbPersonasTabla"], [3, "Pepito", "Conejo", "271828182", "pepito.conejo@example.com", 3]],
          [$cfg["dbPersonasTabla"], [4, "Fulanito", "Mengánez", "314159265", "fulanito.menganez@example.com", 3]],
          [$cfg["dbPersonasTabla"], [5, "Napoleón", "Bonaparte", "432520032", "napoleon.bonaparte@example.org", 3]],
          [$cfg["dbPersonasTabla"], [6, "Julio", "César", "129644790 ", "julio.cesar@example.org", 4]],
      ];
      
  2. Al identificarse como usuario, guarde una variable de sesión con el id del usuario conectado.
    • [acceso/login-2.php]

      El guardar el id del usuario conectado como variable de sesión nos permite que cada página "sepa" quién está realizando las operaciones, de la misma manera que la variable de sesión "nivel" nos permite "saber" si el usuario está autorizado a visualizar la página.

      $_SESSION["conectado"]  = true;
      $_SESSION["nivel"]      = $registro["nivel"];
      $_SESSION["id_usuario"] = $registro["id"];
      
  3. Los usuarios básicos sólo podrán administrar sus propios registros (listar, borrar, buscar, modificar).

    En todas las consultas SELECT de las páginas de administración de la tabla Personas se debe añadir la condición de que el campo id_usuario tenga el mismo valor que la variable de sesión id_usuario. Este valor no hace falta incluirlo como parámetro de la consulta preparada, puesto que no es un dato que se reciba del usuario.

    Por ejemplo, en la página /db/tabla-personas/insertar-2.php, la consulta para comprobar si el registro que se quiere añadir ya existe sería ahora:

        $consulta = "SELECT COUNT(*) FROM $cfg[dbPersonasTabla]
                     WHERE nombre = :nombre
                     AND apellidos = :apellidos
                     AND telefono = :telefono
                     AND correo = :correo
                     AND id_usuario = $_SESSION[id_usuario]";
    

    Y la consulta para comprobar si se ha superado el número máximo de registros permitidos en la tabla sería ahora:

            $consulta = "SELECT COUNT(*) FROM $cfg[dbPersonasTabla]
                         WHERE id_usuario = $_SESSION[id_usuario]";
    

    En la consulta de inserción se tendrá que añadir el campo id_usuario:

                $consulta = "INSERT INTO $cfg[dbPersonasTabla]
                             (nombre, apellidos, telefono, correo, id_usuario)
                             VALUES (:nombre, :apellidos, :telefono, :correo, $_SESSION[id_usuario] )";
    
  4. Un usuario básico podrá insertar un registro de Personas con los mismos datos que un registro de otro usuario, pero no repetir un registro propio.

    La consulta para comprobar si el registro que se quiere añadir que se ha mostrado en el apartado anterior cumple este requisito.

  5. Los usuarios administradores podrán listar, borrar y buscar todos los registros de Personas.

      Las consultas deberá ser diferentes en función del nivel del usuario conectado.

    • Las consultas del usuario administrador no incluirán generalmente la condición de que el registro pertenezca al usuario. Por ejemplo, en db/tabla-personas/buscar-1.php:
      if ($_SESSION["nivel"] == NIVEL_ADMINISTRADOR) {
          $consulta = "SELECT COUNT(*) FROM $cfg[dbPersonasTabla]";
      } else {
          $consulta = "SELECT COUNT(*) FROM $cfg[dbPersonasTabla]
                       WHERE id_usuario = $_SESSION[id_usuario]";
      }
      

      Las consultas del administrador que devuelvan registros de Personas deberán combinar la tabla Personas con la tabla Usuarios para mostrar el nombre de usuario del usuario que creó el registro. Por ejemplo, en db/tabla-personas/listar.php:

      if ($_SESSION["nivel"] == NIVEL_ADMINISTRADOR) {
          $consulta = "SELECT
                           personas.id,
                           personas.nombre,
                           personas.apellidos,
                           personas.correo,
                           personas.telefono,
                           usuarios.usuario
                       FROM $cfg[dbPersonasTabla] as personas
                       JOIN $cfg[dbUsuariosTabla] as usuarios
                       ON personas.id_usuario = usuarios.id
                       ORDER BY $ordena";
      } else {
        $consulta = "SELECT * FROM $cfg[dbPersonasTabla]
                     WHERE id_usuario = $_SESSION[id_usuario]
                     ORDER BY $ordena";
      }
      
  6. En los listados (listar, borrar, buscar, modificar) los usuarios administradores verán el nombre del usuario que creó el registro.

    La columna Usuario se mostrará cuando el nivel del usuario conectado sea el nivel administrador.

    
        if ($_SESSION["nivel"] == NIVEL_ADMINISTRADOR) {
            print "            <th>\n";
            print "              <button name=\"ordena\" value=\"usuario ASC\" class=\"boton-invisible\">\n";
            print "                <img src=\"../../img/abajo.svg\" alt=\"A-Z\" title=\"A-Z\" width=\"15\" height=\"12\">\n";
            print "              </button>\n";
            print "              Usuario\n";
            print "              <button name=\"ordena\" value=\"usuario DESC\" class=\"boton-invisible\">\n";
            print "                <img src=\"../../img/arriba.svg\" alt=\"Z-A\" title=\"Z-A\" width=\"15\" height=\"12\">\n";
            print "              </button>\n";
            print "            </th>\n";
        }
    ...
            if ($_SESSION["nivel"] == NIVEL_ADMINISTRADOR) {
                print "            <td>$registro[usuario]</td>\n";
            }
    
    
  7. Compruebe que los usuarios administradores pueden ordenar los registros de personas por el campo usuario.

    En el primer apartado de este ejercicio ya se ha indicado cómo añadir los valores de ordenación a la variable de configuración $cfg["dbPersonasColumnasOrden"].

  8. Los usuarios administradores no podrán insertar registros de Personas a nombre de otros usuarios, ni modificar el campo usuario de un registro de Personas. (esta funcionalidad se deja para el ejercicio siguiente)

    Si no se incluyen controles para ello en los formularios de db/tabla-personas/insertar-1.php o db/tabla-personas/modificar-2.php, los usuarios administradores no pueden realizar estas tareas.

Bases de datos (3 B) - 5 - Agenda multiusuario (2)

En construcciónPor escribir.

Bases de datos (3 B) - 6 - Campo de fecha

En construcciónPor escribir.