Upload de archivos al servidor - Otras variantes en la aplicación

Haremos una serie de modificaciones a nuestra aplicación del calendario de comidas, 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. Modificaremos la aplicación para poder cargar por teclado las calorías de la comida consumida.

    El primer paso será modificar la estructura de la tabla 'eventoscomida', para no modificar el proyecto anterior crearemos una segunda tabla llamada 'eventoscomidacalo' que tendrá los mismos campos de la otra tabla más un campo que indique la cantidad de calorías:

    CREATE TABLE `eventoscomidacalo` (
      `codigo` int(11) NOT NULL AUTO_INCREMENT,
      `titulo` varchar(255) DEFAULT NULL,
      `inicio` datetime DEFAULT NULL,
      `fin` datetime DEFAULT NULL,
      `calorias` int(11) NOT NULL,
      PRIMARY KEY (`codigo`)
    );
    

    Veamos ahora los cambios a implementar en el archivo 'datoseventos.php':

    datoseventos.php
    <?php
    
    header('Content-Type: application/json');
    
    require("conexion.php");
    
    $conexion = retornarConexion();
    
    switch ($_GET['accion']) {
        case 'listar':
            $datos = mysqli_query($conexion, "select codigo as id,
                                                     titulo as title,
                                                     inicio as start,
                                                     fin as end,
                                                     calorias
                                                 from eventoscomidacalo");
            $resultado = mysqli_fetch_all($datos, MYSQLI_ASSOC);
            echo json_encode($resultado);
            break;
    
        case 'agregar':
            $archi = $_FILES['Archivo']['name'];
            $ext = pathinfo($archi, PATHINFO_EXTENSION);
            if ($ext == 'jpg') {
                $fechahora = $_POST['FechaInicio'] . ' ' . $_POST['HoraInicio'];
                $respuesta = mysqli_query($conexion, "insert into eventoscomidacalo(titulo,inicio,fin,calorias) values(
                                                      '$_POST[Titulo]','$fechahora',date_add('$fechahora', interval 15 minute),$_POST[Calorias])");
                $valor = mysqli_insert_id($conexion);
                move_uploaded_file($_FILES['Archivo']['tmp_name'], 'fotos/' . $valor . '.' . $ext);
                echo json_encode($respuesta);
            } else
                echo "error";
            break;
    
        case 'borrar':
            $respuesta = mysqli_query($conexion, "delete from eventoscomidacalo where codigo=$_GET[codigo]");
            echo json_encode($respuesta);
            break;
    }
    

    Como vemos tanto en el comando SQL select como el insert hacemos referencia al campo 'calorias'.

    Luego el archivo index.php sufre los siguientes cambios:

    index.php
    <!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="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/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='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/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>
            Fotos de Comidas
          </h1>
          <h3>Calorias consumidas este mes: <strong id="TotalCalorias"></strong></h3>
        </section>
    
        <div class="row">
    
          <div class="col-12">
            <div id="Calendario1" style="border: 1px solid #000;padding:2px"></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-12">
                  <label>Calorias:</label>
                  <input type="number" id="Calorias" class="form-control" placeholder="">
                </div>
              </div>
              <div class="form-row">
                <div class="form-group col-md-12">
                  <label>Foto:</label>
                  <input type="file" id="Archivo" class="form-control" placeholder="" name="Archivo">
                </div>
              </div>
              <div class="form-row">
                <div class="form-group col-md-12">
                  <label>Fecha:</label>
    
                  <div class="input-group" data-autoclose="true">
                    <input type="date" id="FechaInicio" value="" class="form-control" readonly />
                  </div>
                </div>
                <div class="form-group col-md-12">
                  <label>Hora:</label>
    
                  <div class="input-group" data-autoclose="true">
                    <input type="text" id="HoraInicio" value="" class="form-control" readonly />
                  </div>
                </div>
              </div>
            </div>
            <div class="modal-footer">
    
              <button type="button" id="BotonAgregar" class="btn btn-success">Agregar</button>
              <button type="button" class="btn btn-success" data-dismiss="modal">Cancelar</button>
    
            </div>
          </div>
        </div>
      </div>
    
    
    
      <!-- FormularioImagen -->
      <div class="modal fade" id="FormularioImagen" 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="CodigoFoto">
              <div class="form-row">
                <div class="form-group col-md-12">
                  <label>Comida:</label>
                  <input type="text" id="Comida" class="form-control" placeholder="" readonly>
                </div>
              </div>
              <div class="form-row">
                <div class="form-group col-md-12">
                  <label>Calorias:</label>
                  <input type="text" id="CaloriasMuestra" class="form-control" placeholder="" readonly>
                </div>
              </div>
              <div class="form-row">
                <div class="form-group col-md-12">
                  <img id="Foto" src="#" style="width:100%">
                </div>
              </div>
            </div>
            <div class="modal-footer">
              <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() {
          var totalcalorias = 0;
          let calendario1 = new FullCalendar.Calendar(document.getElementById('Calendario1'), {
            plugins: ['dayGrid', 'timeGrid', 'interaction'],
            droppable: true,
            locale: 'es',
            showNonCurrentDates: false,
            header: {
              left: 'today,prev,next',
              center: 'title',
              right: ''
            },
            editable: false,
            events: 'datoseventos.php?accion=listar',
            height: "parent",
            dateClick: function(info) {
              limpiarFormulario();
              let fechaHora = info.dateStr.split("T");
              $('#FechaInicio').val(fechaHora[0]);
              $('#HoraInicio').val(moment(new Date()).format("HH:mm"));
              $("#FormularioEventos").modal();
            },
            eventClick: function(info) {
              $('#Comida').val(info.event.title + '  -  ' + moment(info.event.start).format("HH:mm - DD/MM/YYYY") + '');
              $("#Foto").attr("src", "fotos/" + info.event.id + '.jpg');
              $('#CodigoFoto').val(info.event.id);
              $('#CaloriasMuestra').val(info.event.extendedProps.calorias);
              $("#FormularioImagen").modal();
            },
            eventRender: function(info) {
              totalcalorias += parseInt(info.event.extendedProps.calorias);
              info.el.children[0].innerHTML += ' - <small>(' + info.event.extendedProps.calorias + ' calorías)</small><br><span class="fc-content">' + '<img style="width:100%;border-radius:20%" src="fotos/' + info.event.id + '.jpg"></span>';
              $("#TotalCalorias").text(totalcalorias);
              return true;
            }
          });
          calendario1.render();
    
          //Eventos de botones de la aplicación
          $('#BotonAgregar').click(function() {
            if ($('#Calorias').val() == '') {
              alert('No puede dejar vacío el campo de calorias');
              return;
            }
            if ($('#Archivo').val() == '') {
              alert('No puede dejar vacío el campo del archivo');
              return;
            }
            agregarRegistro();
            $("#FormularioEventos").modal('hide');
          });
    
          $('#BotonBorrar').click(function() {
            borrarRegistro();
            $("#FormularioImagen").modal('hide');
          });
    
    
          // funciones para comunicarse con el servidor via ajax
          function agregarRegistro() {
            let archivo1 = $('#Archivo').prop('files')[0];
            let datos = new FormData();
            datos.append('Archivo', archivo1);
            datos.append('Titulo', $('#Titulo').val());
            datos.append('FechaInicio', $('#FechaInicio').val());
            datos.append('HoraInicio', $('#HoraInicio').val());
            datos.append('Calorias', $('#Calorias').val());
            $.ajax({
              type: 'POST',
              url: 'datoseventos.php?accion=agregar',
              data: datos,
              dataType: 'text',
              cache: false,
              contentType: false,
              processData: false,
              success: function(msg) {
                if (msg == "error")
                  alert("No se puede subir ese formato de archivo");
                totalcalorias = 0;
                $("#TotalCalorias").text(totalcalorias);
                calendario1.refetchEvents();
              },
              error: function(error) {
                alert("Hay un problema:" + error);
              }
            });
          }
    
          function borrarRegistro(registro) {
            $.ajax({
              type: 'GET',
              url: 'datoseventos.php?accion=borrar&codigo=' + $('#CodigoFoto').val(),
              success: function(msg) {
                totalcalorias = 0;
                $("#TotalCalorias").text(totalcalorias);
                calendario1.refetchEvents();
              },
              error: function(error) {
                alert("Hay un problema:" + error);
              }
            });
          }
    
          function limpiarFormulario() {
            $('#Codigo').val('');
            $('#Titulo').val('');
            $('#Archivo').val('');
            $('#Calorias').val('');
          }
    
        });
      </script>
    
    </body>
    
    </html>
    

    En el formulario de carga de la foto agregamos el campo para ingresar las calorías:

              <div class="form-row">
                <div class="form-group col-md-12">
                  <label>Calorias:</label>
                  <input type="number" id="Calorias" class="form-control" placeholder="">
                </div>
              </div>
    

    Cuando mostramos los datos del evento procedemos a imprimir también las calorías de dicha comida:

            eventRender: function(info) {
              totalcalorias += parseInt(info.event.extendedProps.calorias);
              info.el.children[0].innerHTML += ' - <small>(' + info.event.extendedProps.calorias + ' calorías)</small><br><span class="fc-content">' + '<img style="width:100%;border-radius:20%" src="fotos/' + info.event.id + '.jpg"></span>';
              $("#TotalCalorias").text(totalcalorias);
              return true;
            }
    

    Luego también acumulamos en la variable global 'totalcalorias' las calorías de cada comida. Dicho acumulador lo mostramo en la parte superior de la página:

        <section class="content-header">
          <h1>
            Fotos de Comidas
          </h1>
          <h3>Calorias consumidas este mes: <strong id="TotalCalorias"></strong></h3>
        </section>
    

    El resultado visual de la página es:

    upload php

  2. Ahora modificaremos la aplicación para tener el acceso a datos utilizando la librería PDO de PHP.

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

    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")); 
    }
    
    ?>
    
    datoseventos.php
    <?php
    
    header('Content-Type: application/json');
    
    require("conexion.php");
    
    $pdo = retornarConexion();
    
    switch ($_GET['accion']) {
        case 'listar':
            $sql = $pdo->prepare("select codigo as id,
                                             titulo as title,
                                             inicio as start,
                                             fin as end,
                                             calorias
                                         from eventoscomidacalo");
            $sql->execute();
            $resultado = $sql->fetchAll(PDO::FETCH_ASSOC);
            echo json_encode($resultado);
            break;
    
        case 'agregar':
            $archi = $_FILES['Archivo']['name'];
            $ext = pathinfo($archi, PATHINFO_EXTENSION);
            if ($ext == 'jpg') {
                $fechahora = $_POST['FechaInicio'] . ' ' . $_POST['HoraInicio'];
                $sql = $pdo->prepare("insert into eventoscomidacalo(titulo,inicio,fin,calorias) values(
                                       :titulo,:fechahora,date_add(:fechahora, interval 15 minute),:calorias)");
                $resultado = $sql->execute(array(
                    "titulo" => $_POST['Titulo'],
                    "fechahora" => $fechahora,
                    "calorias" => $_POST['Calorias']
                ));
                $valor = $pdo->lastInsertId();
                move_uploaded_file($_FILES['Archivo']['tmp_name'], 'fotos/' . $valor . '.' . $ext);
                echo json_encode($resultado);
            } else
                echo "error";
            break;
    
        case 'borrar':
            $sql = $pdo->prepare("delete from eventoscomidacalo where codigo=:codigo");
            $resultado = $sql->execute(array(
                "codigo" => $_GET['codigo']
            ));
            echo json_encode($resultado);
            break;
    }
    

    No se producen cambios en el archivo index.php