Login y sesiones en un sitio web - Otras variantes en la aplicación

Haremos una serie de modificaciones a nuestra aplicación del login a un sitio web, luego de haber visto la estructura fundamental en los conceptos anteriores, ésto nos servirá para identificar que partes de la aplicación se deben modificar.

Algoritmos a implementar.

  1. Modificar el acceso a datos utilizando la librería PDO.

    Hay que hacer cambios en todos los archivos que accedemos a datos de MySQL.

    conexion.php
    <?php
    
    function retornarConexion() {
        $server="localhost";
        $usuario="root";
        $clave="";
        $base="base1";
        return new PDO("mysql:dbname=$base;host=$server", "$usuario","$clave", array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8")); 
    }
    
    ?>
    
    login.php
    <?php
    require("conexion.php");
    
    $pdo = retornarConexion();
    
    $sql = $pdo->prepare("select nombre,clave from usuarios where nombre=:nombre and clave=:clave");
    $sql->execute(array("nombre" => $_POST['usuario'], "clave" => $_POST['clave']));
    if ($sql->rowCount() == 1) {
        session_start();
        $_SESSION['usuario'] = $_POST['usuario'];
        echo "correcta";
    } else {
        echo "incorrecta";
    }
    
    ?>
    
    datosusuarios.php
    <?php
    header('Content-Type: application/json');
    
    require("conexion.php");
    
    $pdo = retornarConexion();
    
    switch ($_GET['accion']) {
      case 'agregar':
        $sql = $pdo->prepare("insert into usuarios(nombre,clave) values (:nombre,:clave)");
        $resultado = $sql->execute(array(
            "nombre" => $_POST['nombrenuevo'],
            "clave" => $_POST['clave1']
        ));
        echo json_encode($resultado);
        break;
      case 'existe':
        $sql = $pdo->prepare("select nombre from usuarios where nombre=:nombre");
        $sql->execute(array("nombre" => $_POST['nombrenuevo']));
        if ($sql->rowCount() == 1) 
          echo '{"resultado":"repetido"}';      
        else
          echo '{"resultado":"norepetido"}';
        break;
    }
    
    ?>
    
    index.php
    <?php
    session_start();
    if (!isset($_SESSION['usuario'])) {
      header("Location:login.html");
      exit(0);
    }
    ?>
    
    <!DOCTYPE html>
    <html lang="es">
    
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Calendario de Eventos</title>
    
      <link href="bootstrap-4.3.1/css/bootstrap.min.css" rel="stylesheet">
      <link href="datatables/datatables.min.css" rel="stylesheet">
      <link href="clockpicker/bootstrap-clockpicker.css" rel="stylesheet">
      <link href="fullcalendar-4.3.1/packages/core/main.css" rel="stylesheet">
      <link href="fullcalendar-4.3.1/packages/daygrid/main.css" rel="stylesheet">
      <link href="fullcalendar-4.3.1/packages/timegrid/main.css" rel="stylesheet">
      <link href="fullcalendar-4.3.1/packages/list/main.css" rel="stylesheet">
      <link href="fullcalendar-4.3.1/packages/bootstrap/main.css" rel="stylesheet">
    
    
      <script src="js/jquery-3.4.1.js"></script>
      <script src="js/popper.min.js"></script>
      <script src="bootstrap-4.3.1/js/bootstrap.min.js"></script>
      <script src="datatables/datatables.min.js"></script>
      <script src="clockpicker/bootstrap-clockpicker.js"></script>
      <script src='js/moment-with-locales.js'></script>
      <script src='fullcalendar-4.3.1/packages/core/main.js'></script>
      <script src='fullcalendar-4.3.1/packages/daygrid/main.js'></script>
      <script src='fullcalendar-4.3.1/packages/timegrid/main.js'></script>
      <script src='fullcalendar-4.3.1/packages/interaction/main.js'></script>
      <script src='fullcalendar-4.3.1/packages/list/main.js'></script>
      <script src='fullcalendar-4.3.1/packages/core/locales/es.js'></script>
      <script src='fullcalendar-4.3.1/packages/bootstrap/main.js'></script>
    </head>
    
    <body>
      <div class="container-fluid">
        <section class="content-header">
          <h1>
            <small>Panel de control de <strong><?php echo $_SESSION['usuario']; ?></strong></small>
            <small style="float:right"><a href="logout.php">Cerrar la sesión</a></small>
          </h1>
    
        </section>
    
        <div class="row">
    
          <div class="col-10">
            <div id="Calendario1" style="border: 1px solid #000;padding:2px"></div>
          </div>
    
          <div class="col-2">
            <div id='external-events' style="margin-bottom:1em; height: 350px; border: 1px solid #000; overflow: auto;padding:1em">
              <h4 class="text-center">Eventos predefinidos</h4>
              <div id='listaeventospredefinidos'>
                <?php
                require("conexion.php");
                $pdo = retornarConexion();
                $sql = $pdo->prepare("SELECT codigo,titulo,horainicio,horafin,colortexto,colorfondo FROM eventospredefinidosusuarios where usuario=:usuario");
                $sql->execute(array(
                  "usuario" => $_SESSION['usuario']
                ));
                $ep = $sql->fetchAll(PDO::FETCH_ASSOC);
                foreach ($ep as $fila)
                  echo "<div class='fc-event' data-titulo='$fila[titulo]' data-horafin='$fila[horafin]' data-horainicio='$fila[horainicio]' 
                        data-colorfondo='$fila[colorfondo]' data-colortexto='$fila[colortexto]' data-codigo='$fila[codigo]'
                        style='border-color:$fila[colorfondo];color:$fila[colortexto];background-color:$fila[colorfondo];margin:10px'>
                        $fila[titulo]  [" . substr($fila['horainicio'], 0, 5) . " a " . substr($fila['horafin'], 0, 5) . "]</div>";
    
                ?>
    
    
              </div>
            </div>
            <hr>
            <div style="text-align:center"><button type="button" id="BotonEventosPredefinidos" class="btn btn-success">Administrar eventos predefinidos</button>
            </div>
          </div>
    
        </div>
      </div>
    
    
      <!-- FormularioEventos -->
      <div class="modal fade" id="FormularioEventos" tabindex="-1" role="dialog">
        <div class="modal-dialog" role="document">
          <div class="modal-content">
            <div class="modal-header">
              <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                <span aria-hidden="true">×</span>
              </button>
            </div>
            <div class="modal-body">
              <input type="hidden" id="Codigo">
              <div class="form-row">
                <div class="form-group col-md-12">
                  <label>Título del evento:</label>
                  <input type="text" id="Titulo" class="form-control" placeholder="">
                </div>
              </div>
    
              <div class="form-row">
                <div class="form-group col-md-6">
                  <label>Fecha de inicio:</label>
    
                  <div class="input-group" data-autoclose="true">
                    <input type="date" id="FechaInicio" value="" class="form-control" />
                  </div>
                </div>
                <div class="form-group col-md-6" id="TituloHoraInicio">
                  <label>Hora de inicio:</label>
    
                  <div class="input-group clockpicker" data-autoclose="true">
                    <input type="text" id="HoraInicio" value="" class="form-control" autocomplete="off" />
                  </div>
                </div>
              </div>
    
              <div class="form-row">
                <div class="form-group col-md-6">
                  <label>Fecha de fin:</label>
    
                  <div class="input-group" data-autoclose="true">
                    <input type="date" id="FechaFin" value="" class="form-control" />
                  </div>
                </div>
                <div class="form-group col-md-6" id="TituloHoraFin">
                  <label>Hora de fin:</label>
    
                  <div class="input-group clockpicker" data-autoclose="true">
                    <input type="text" id="HoraFin" value="" class="form-control" autocomplete="off" />
                  </div>
                </div>
              </div>
    
              <div class="form-group">
                <label>Descripción:</label>
                <textarea id="Descripcion" rows="3" class="form-control"></textarea>
              </div>
              <div class="form-group">
                <label>Color de fondo:</label>
                <input type="color" value="#3788D8" id="ColorFondo" class="form-control" style="height:36px;">
              </div>
              <div class="form-group">
                <label>Color de texto:</label>
                <input type="color" value="#ffffff" id="ColorTexto" class="form-control" style="height:36px;">
              </div>
    
            </div>
            <div class="modal-footer">
    
              <button type="button" id="BotonAgregar" class="btn btn-success">Agregar</button>
              <button type="button" id="BotonModificar" class="btn btn-success">Modificar</button>
              <button type="button" id="BotonBorrar" class="btn btn-success">Borrar</button>
              <button type="button" class="btn btn-success" data-dismiss="modal">Cancelar</button>
    
            </div>
          </div>
        </div>
      </div>
    
    
      <script>
        document.addEventListener("DOMContentLoaded", function() {
    
          $('.clockpicker').clockpicker();
    
          let calendario1 = new FullCalendar.Calendar(document.getElementById('Calendario1'), {
            plugins: ['dayGrid', 'timeGrid', 'interaction'],
            height: 800,
            droppable: true,
            locale: 'es',
            showNonCurrentDates: false,
            header: {
              left: 'today,prev,next',
              center: 'title',
              right: 'dayGridMonth,timeGridWeek,timeGridDay'
            },
            editable: true,
            events: 'datoseventos.php?accion=listar',
            dateClick: function(info) {
              limpiarFormulario();
              $('#BotonAgregar').show();
              $('#BotonModificar').hide();
              $('#BotonBorrar').hide();
              if (info.allDay) {
                $('#FechaInicio').val(info.dateStr);
                $('#FechaFin').val(info.dateStr);
              } else {
                let fechaHora = info.dateStr.split("T");
                $('#FechaInicio').val(fechaHora[0]);
                $('#FechaFin').val(fechaHora[0]);
                $('#HoraInicio').val(fechaHora[1].substring(0, 5));
              }
              $("#FormularioEventos").modal();
            },
            eventClick: function(info) {
              $('#BotonModificar').show();
              $('#BotonBorrar').show();
              $('#BotonAgregar').hide();
              $('#Codigo').val(info.event.id);
              $('#Titulo').val(info.event.title);
              $('#Descripcion').val(info.event.extendedProps.descripcion);
              $('#FechaInicio').val(moment(info.event.start).format("YYYY-MM-DD"));
              $('#FechaFin').val(moment(info.event.end).format("YYYY-MM-DD"));
              $('#HoraInicio').val(moment(info.event.start).format("HH:mm"));
              $('#HoraFin').val(moment(info.event.end).format("HH:mm"));
              $('#ColorFondo').val(info.event.backgroundColor);
              $('#ColorTexto').val(info.event.textColor);
              $("#FormularioEventos").modal();
            },
            eventResize: function(info) {
              $('#Codigo').val(info.event.id);
              $('#Titulo').val(info.event.title);
              $('#FechaInicio').val(moment(info.event.start).format("YYYY-MM-DD"));
              $('#FechaFin').val(moment(info.event.end).format("YYYY-MM-DD"));
              $('#HoraInicio').val(moment(info.event.start).format("HH:mm"));
              $('#HoraFin').val(moment(info.event.end).format("HH:mm"));
              $('#ColorFondo').val(info.event.backgroundColor);
              $('#ColorTexto').val(info.event.textColor);
              $('#Descripcion').val(info.event.extendedProps.descripcion);
              let registro = recuperarDatosFormulario();
              modificarRegistro(registro);
            },
            eventDrop: function(info) {
              $('#Codigo').val(info.event.id);
              $('#Titulo').val(info.event.title);
              $('#FechaInicio').val(moment(info.event.start).format("YYYY-MM-DD"));
              $('#FechaFin').val(moment(info.event.end).format("YYYY-MM-DD"));
              $('#HoraInicio').val(moment(info.event.start).format("HH:mm"));
              $('#HoraFin').val(moment(info.event.end).format("HH:mm"));
              $('#ColorFondo').val(info.event.backgroundColor);
              $('#ColorTexto').val(info.event.textColor);
              $('#Descripcion').val(info.event.extendedProps.descripcion);
              let registro = recuperarDatosFormulario();
              modificarRegistro(registro);
            },
            drop: function(info) {
              limpiarFormulario();
              $('#ColorFondo').val(info.draggedEl.dataset.colorfondo);
              $('#ColorTexto').val(info.draggedEl.dataset.colortexto);
              $('#Titulo').val(info.draggedEl.dataset.titulo);
              let fechaHora = info.dateStr.split("T");
              $('#FechaInicio').val(fechaHora[0]);
              $('#FechaFin').val(fechaHora[0]);
              if (info.allDay) { //verdadero si el calendario esta en vista de mes
                $('#HoraInicio').val(info.draggedEl.dataset.horainicio);
                $('#HoraFin').val(info.draggedEl.dataset.horafin);
              } else {
                $('#HoraInicio').val(fechaHora[1].substring(0, 5));
                $('#HoraFin').val(moment(fechaHora[1].substring(0, 5)).add(1, 'hours'));
              }
              let registro = recuperarDatosFormulario();
              agregarEventoPredefinido(registro);
            }
          });
    
          calendario1.render();
    
    
          new FullCalendarInteraction.Draggable(document.getElementById('listaeventospredefinidos'), {
            itemSelector: '.fc-event',
            eventData: function(eventEl) {
              return {
                title: eventEl.innerText.trim()
              }
            }
          });
    
          //Eventos de botones de la aplicación
          $('#BotonAgregar').click(function() {
            let registro = recuperarDatosFormulario();
            agregarRegistro(registro);
            $("#FormularioEventos").modal('hide');
          });
    
          $('#BotonModificar').click(function() {
            let registro = recuperarDatosFormulario();
            modificarRegistro(registro);
            $("#FormularioEventos").modal('hide');
          });
    
          $('#BotonBorrar').click(function() {
            let registro = recuperarDatosFormulario();
            borrarRegistro(registro);
            $("#FormularioEventos").modal('hide');
          });
    
          $('#BotonEventosPredefinidos').click(function() {
            window.location = "eventospredefinidos.php";
          });
    
    
          // funciones para comunicarse con el servidor via ajax
          function agregarRegistro(registro) {
            $.ajax({
              type: 'POST',
              url: 'datoseventos.php?accion=agregar',
              data: registro,
              success: function(msg) {
                calendario1.refetchEvents();
              },
              error: function(error) {
                alert("Hay un problema:" + error);
              }
            });
          }
    
          function modificarRegistro(registro) {
            $.ajax({
              type: 'POST',
              url: 'datoseventos.php?accion=modificar',
              data: registro,
              success: function(msg) {
                calendario1.refetchEvents();
              },
              error: function(error) {
                alert("Hay un problema:" + error);
              }
            });
          }
    
          function borrarRegistro(registro) {
            $.ajax({
              type: 'POST',
              url: 'datoseventos.php?accion=borrar',
              data: registro,
              success: function(msg) {
                calendario1.refetchEvents();
              },
              error: function(error) {
                alert("Hay un problema:" + error);
              }
            });
          }
    
          function agregarEventoPredefinido(registro) {
            $.ajax({
              type: 'POST',
              url: 'datoseventos.php?accion=agregar',
              data: registro,
              success: function(msg) {
                calendario1.removeAllEvents();
                calendario1.refetchEvents();
              },
              error: function(error) {
                alert("Hay un problema:" + error);
              }
            });
          }
    
          // funciones que interactuan con el formulario de entrada de datos
          function limpiarFormulario() {
            $('#Codigo').val('');
            $('#Titulo').val('');
            $('#Descripcion').val('');
            $('#FechaInicio').val('');
            $('#FechaFin').val('');
            $('#HoraInicio').val('');
            $('#HoraFin').val('');
            $('#ColorFondo').val('#3788D8');
            $('#ColorTexto').val('#ffffff');
          }
    
          function recuperarDatosFormulario() {
            let registro = {
              codigo: $('#Codigo').val(),
              titulo: $('#Titulo').val(),
              descripcion: $('#Descripcion').val(),
              inicio: $('#FechaInicio').val() + ' ' + $('#HoraInicio').val(),
              fin: $('#FechaFin').val() + ' ' + $('#HoraFin').val(),
              colorfondo: $('#ColorFondo').val(),
              colortexto: $('#ColorTexto').val()
            };
            return registro;
          }
    
        });
      </script>
    
    </body>
    
    </html>
    
    datoseventos.php
    <?php
    
    header('Content-Type: application/json');
    
    session_start();
    
    require("conexion.php");
    
    $pdo = retornarConexion();
    
    switch ($_GET['accion']) {
        case 'listar':
            $sql = $pdo->prepare("select codigo as id,
                                         titulo as title,
                                         descripcion,
                                         inicio as start,
                                         fin as end,
                                         colortexto as textColor,
                                         colorfondo as backgroundColor 
                                    from eventosusuarios where usuario=:usuario");
            $sql->execute(array(
                "usuario" => $_SESSION['usuario']
            ));
            $resultado = $sql->fetchAll(PDO::FETCH_ASSOC);
            echo json_encode($resultado);
            break;
    
        case 'agregar':
            $sql = $pdo->prepare("insert into eventosusuarios(titulo,descripcion,inicio,fin,colortexto,colorfondo,usuario) values 
                                                     (:titulo,:descripcion,:inicio,:fin,:colortexto,:colorfondo,:usuario)");
            $resultado = $sql->execute(array(
                "titulo" => $_POST['titulo'],
                "descripcion" => $_POST['descripcion'],
                "inicio" => $_POST['inicio'],
                "fin" => $_POST['fin'],
                "colortexto" => $_POST['colortexto'],
                "colorfondo" => $_POST['colorfondo'],
                "usuario" => $_SESSION['usuario']
            ));
            echo json_encode($resultado);
            break;
    
        case 'modificar':
            $sql = $pdo->prepare("update eventosusuarios set titulo=:titulo,
                                                             descripcion=:descripcion,
                                                             inicio=:inicio,
                                                             fin=:fin,
                                                             colortexto=:colortexto,
                                                             colorfondo=:colorfondo
                                                         where codigo=:codigo");
            $resultado = $sql->execute(array(
                "titulo" => $_POST['titulo'],
                "descripcion" => $_POST['descripcion'],
                "inicio" => $_POST['inicio'],
                "fin" => $_POST['fin'],
                "colortexto" => $_POST['colortexto'],
                "colorfondo" => $_POST['colorfondo'],
                "codigo" => $_POST['codigo']
            ));
            echo json_encode($resultado);
            break;
    
        case 'borrar':
            $sql = $pdo->prepare("delete from eventosusuarios where codigo=:codigo");
            $resultado = $sql->execute(array(
                "codigo" => $_POST['codigo']
            ));
            echo json_encode($resultado);
            break;
    }
    
    datoseventospredefinidos.php
    <?php
    header('Content-Type: application/json');
    session_start();
    
    require("conexion.php");
    
    $pdo = retornarConexion();
    
    switch ($_GET['accion']) {
        case 'listar':
            $sql = $pdo->prepare("select codigo,titulo,horainicio,horafin,colortexto,colorfondo from eventospredefinidosusuarios where usuario=:usuario");
            $sql->execute(array("usuario" => $_SESSION['usuario']));
            $resultado = $sql->fetchAll(PDO::FETCH_ASSOC);
            echo json_encode($resultado);
            break;
    
        case 'agregar':
            $sql = $pdo->prepare("insert into eventospredefinidosusuarios(titulo,horainicio,horafin,colortexto,colorfondo,usuario) values 
                                                                         (:titulo,:horainicio,:horafin,:colortexto,:colorfondo,:usuario)");
            $resultado = $sql->execute(array(
                "titulo" => $_POST['titulo'],
                "horainicio" => $_POST['horainicio'],
                "horafin" => $_POST['horafin'],
                "colortexto" => $_POST['colortexto'],
                "colorfondo" => $_POST['colorfondo'],
                "usuario" => $_SESSION['usuario']
            ));
            echo json_encode($resultado);    
            break;
    
        case 'borrar':
            $sql = $pdo->prepare("delete from eventospredefinidosusuarios where codigo=:codigo");
            $resultado = $sql->execute(array(
                "codigo" => $_POST['codigo']
            ));
            echo json_encode($resultado);        
            break;
    }
    ?>
    

    No sufren cambios los archivos: login.html, logout.php y eventospredefinidos.php.