PHP UD3 OP MODIFICAR

De MediaWiki
Ir a la navegación Ir a la búsqueda

Introducción

  • Requerimentos previos:


  • NOTA IMPORTANTE: Vimos en seccións anteriores que cando empregmos datos dun formulario, existen unhas técnicas para evitar posibles ataques. Todos os exercicios que veñen a continuación empregan ditas técnicas. Existe un tipo de ataque que non se ten en conta ao non ter chegado á sección de emprego de variables de sesións. En dita sección se explica o que temos que facer. É importante que vos acordedes de aplicar a técnica descrita cando vexades os contidos.




  • Ao igual que no caso INSERT, se modificamos as claves primarias, farase o action recollido na creación das táboas.
Normalmente non se debe modificar a clave primaria das táboas e o que modificaremos será algún dos atributos da táboa.


  • A orde SQL UPDATE levará como parámetros os novos valores a modificar e enviarase a clave primaria para que poida buscar a fila concreta que vai modificarse.
Neste exercicio dita función debería devolver sempre 1, pero podería aplicarse a outros exemplo no que queremos informar ao usuario de cantos rexistros foron afectados pola opción.


  • Nota: Lembrar que nesta solución estamos a utilizar a chamada a multi_query pero se podería utilizar a chamada a query no caso de que o procedemento non devolva resultados (teña un select que queiramos recoller en PHP).



Caso Práctico: Modificación


Orientado a procedementos

  • Imos implementar esta opción na páxina consultar_estados.php continuando có visto na sección de ALTA.
Se estamos a utilizar procedementos almacenados, lembrar que en caso de erro '2014 - Commands out of sync; you can't run this command now', debemos engadir a seguinte liña despois de chamar a un procedemento almacenado:
                    if ($conex->multi_query($proc)){
                        $result = $conex->store_result();
                        if ($result && ($result->num_rows>0)){
                            while($fila=$result->fetch_assoc()){
                                // Procesamos cada fila
                            }
                            $result->free();
                        }
                        while($conex->next_result() && $conex->store_result());
                    }


  • O que temos que facer é:
  • Definir no arquivo bd.php unha constante coa orde SQL para modificar o nome dun estado a partires dun id dado (clave primaria)
  • Modificar a páxina consultar_estados.php e engadir a opción 'Editar' a cada un dos estados. Debemos ir a unha páxina editar_estado.php.
O poderemos facer:
  • Cun enlace href, enviando como parámetro o id do estado a modificar. Eu vou escoller esta opción, pero sodes libres de practicar e intentalo coa outra opción.
  • Cun formulario e un campo oculto có id do estado a modificar.
  • A páxina editar_estado.php terá un formulario cun action a 'procesar_editar_estado.php'. Dentro do formulario fará un include do arquivo campos_estado.php que xa foi feito na páxina de alta de estados.
Tamén obterá os datos do estado a partires do id enviado polo enlace href ou polo formulario da páxina consultar_estados.php. Ditos datos serán gardados en variables e o nome será empregado pola páxina campos_estado.php.
Modificaremos a páxina campos_estado.php para que teña en conta os datos obtidos da consulta á base de datos.

$e->getCode():* Crear a páxina procesar_borrar_estado.php que dará de baixa o estado e se se produce algún erro deberá de informar á páxina de consultar_estados.php de cal foi o erro. Ao igual que na alta, poderemos enviar dita información nun parámetro na URL de redirección ou veremos nas seguintes seccións como empregar variables de sesión.

A xestión do erro en caso de querer borrar un rexistro relacionado non a imos facer.
Lembrar que dito control poderíamos facelo no propio procedemento almacenado/páxina php, capturando a excepción ou comprobando cun select previo se existe o rexistro relacionado.






Posible solución Caso Práctico: Modificación Arquivo: bd.php

define('CONSULTAR_ESTADO_POR_ID',"SELECT id,descripcion FROM estados WHERE id=%d");
define('ACTUALIZAR_ESTADO',"UPDATE estados set descripcion='%s' WHERE id=%d");


Arquivo: consultar_estados.php

<?php
/* Lembrar quitar isto ao probar o scripts sen erros */
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

require ('/var/www/confBD/bd.php');

try {
    $conex = new mysqli(SERVIDOR, USUARIO, PASSWORD,BD);   
    $conex->set_charset('utf8mb4');

?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="es" xml:lang="es">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>Xestión de estados</title>
    </head>
    <body>
        <form action="alta_estado.php" method="post">
            <button type="submit">Novo Estado</button>
        </form>
        <table border="1" style="margin-top:20px">
            <tr>
                <th>Estado</th>
                <th>Accións</th>
            </tr>
        <?php

            $resultado = $conex->query(CONSULTAR_ESTADOS);

            while($fila = $resultado->fetch_assoc()) {
                $nombre = htmlentities($fila['descripcion']);
                echo "<tr>";
                echo "<td>$nombre</td>";
                echo "<td>";
                printf("<td><a href='editar_estado.php?id=%d'>Editar</a>",urlencode($fila['id']));
                printf("<form action='procesar_borrar_estado.php' method='post'>");
                printf("<input type='hidden' name='id' value='%s' />",htmlentities($fila['id']));
                echo '<input onclick="return confirm(\'Estás seguro de que queres borrar este estado?\');" type="submit" value="Borrar" name="btnBorrarEstado" style="background:none;border:none;padding:0;maring:0;color: blue; text-decoration:underline; cursor:pointer; font-size:inherit" />';
                echo '</form>';
                echo "</td>";

                echo "</tr>";
            }

            $resultado->free();
        ?>    
        </table>


        <div>
            <?php
                if(isset($_GET['id'])) printf("<h3>Estado con id %s dado de alta correctamente.</h3>",htmlentities($_GET['id']));
                if(isset($_GET['msg'])) printf("<h4>%s</h3>",htmlentities($_GET['msg']));
                if(isset($_GET['error'])) printf("<h2>Houbo un erro: %s</h2>",htmlentities($_GET['error']));
            ?>
        </div>    
        
    </body>    
</html>
<?php
}   // Pecha o try da parte superior da páxina
catch (mysqli_sql_exception $e) {
    die("Erro mysql: " . $e->getMessage());
}
catch (Expcetion $e) {
    die("Erro xeral: " . $e->getMessage());
}
finally{
  if(!empty($conex)){
      $conex->close();
  }
}
?>



Arquivo: campos_estado.php

<label for="nombre">Descricción:</label>
<input type="text" maxlength="100" id="descripcion" name="descripcion" required value="<?php echo isset($descripcion) ? htmlentities($descripcion) : ''; ?>"><br>


Arquivo: editar_estado.php

<?php
/* Lembrar quitar isto ao probar o scripts sen erros */
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

require ('/var/www/confBD/bd.php');
$conex = new mysqli(SERVIDOR, USUARIO, PASSWORD, BD);
$conex->set_charset('utf8mb4');
$erros = '';

?>

<?php 
    $consulta = sprintf(CONSULTAR_ESTADO_POR_ID,$conex->real_escape_string($_GET['id']));
    $result=$conex->query($consulta);  // Ven na URL da paxina listar_pistas.php
    if ($result && $result->num_rows>0){
        $row = mysqli_fetch_assoc($result); // Os datos serán empregados polos inputs do formulario
        $descripcion = htmlentities($row['descripcion']);
        $id = htmlentities($row['id']);  //O id non se amosa ao usuario

        $result->free();
    }
    else {
        $erros = "Non se atopan os datos da pista!!!!";
    }


?>
<!DOCTYPE html>
<html>
<head>
  <title>Modificar Estado</title>
</head>
<body>  
    <h3>EDITAR ESTADO</h3>

  <form method="POST" action="procesar_editar_estado.php">
    <?php include 'campos_estado.php'; ?>
    <div>
        <input type="hidden" name="id_orixinal" value="<?php echo $id; ?>">
        <input type="submit" value="Modificar" name="btnModificarEstado">
    </div>
  </form>
  <?php 
    if(!empty($erros)){
        printf("<h3>$erros</h3>");
    }
  ?>
</body>
</html>


Arquivo: procesar_editar_estado.php

<?php
/* Lembrar quitar isto ao probar o scripts sen erros */
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

require ('/var/www/confBD/bd.php');

$conex = new mysqli(SERVIDOR, USUARIO, PASSWORD, BD);
$conex->set_charset('utf8mb4');

$error = '';
$msg = '';
if (isset($_POST['btnModificarEstado'])) {
  try {

    // Lóxica para dar de alta unha nova pista
    $desc_novo = $conex->real_escape_string(strtoupper($_POST['descripcion']));
    if(strlen($desc_novo)<4 || strlen($desc_novo)>100){
      $error = sprintf("error=%s", urlencode("O nome do estado non pode ter menos de 4 ou 100 caracteres"));
    }
    else{
      $id = $conex->real_escape_string($_POST['id_orixinal']); // Ven nun campo oculto do form
      $consulta = sprintf(ACTUALIZAR_ESTADO,$desc_novo, $id);
      $conex->query($consulta);
  
      $msg = sprintf("msg=%s", urlencode("Estado actualizado correctamente."));
  
    }
  }
  catch (mysqli_sql_exception $e) {
      $error=sprintf("error='Erro mysql: %s'",urlencode($e->getMessage()));
  }
  catch (Expcetion $e) {
      $error=sprintf("error='Erro xeral: %s'",urlencode($e->getMessage()));
  }
  finally{
    if(!empty($conex)){
      $conex->close();
    }  
  }
}
$url = sprintf("consultar_estados.php?%s&%s",$msg,$error);
header("Location:" . $url);

?>



Empregando PDO

  • Imos implementar esta opción na páxina consultar_estados.php continuando có visto na sección de ALTA.


  • O que temos que facer é:
  • Definir no arquivo bd.php unha constante coa orde SQL para modificar o nome dun estado a partires dun id dado (clave primaria)
  • Modificar a páxina consultar_estados.php e engadir a opción 'Editar' a cada un dos estados. Debemos ir a unha páxina editar_estado.php.
O poderemos facer:
  • Cun enlace href, enviando como parámetro o id do estado a modificar. Eu vou escoller esta opción, pero sodes libres de practicar e intentalo coa outra opción.
  • Cun formulario e un campo oculto có id do estado a modificar.
  • A páxina editar_estado.php terá un formulario cun action a 'procesar_editar_estado.php'. Dentro do formulario fará un include do arquivo campos_estado.php que xa foi feito na páxina de alta de estados.
Tamén obterá os datos do estado a partires do id enviado polo enlace href ou polo formulario da páxina consultar_estados.php. Ditos datos serán gardados en variables e o nome será empregado pola páxina campos_estado.php.
Modificaremos a páxina campos_estado.php para que teña en conta os datos obtidos da consulta á base de datos.

$e->getCode():* Crear a páxina procesar_borrar_estado.php que dará de baixa o estado e se se produce algún erro deberá de informar á páxina de consultar_estados.php de cal foi o erro. Ao igual que na alta, poderemos enviar dita información nun parámetro na URL de redirección ou veremos nas seguintes seccións como empregar variables de sesión.

A xestión do erro en caso de querer borrar un rexistro relacionado non a imos facer.
Lembrar que dito control poderíamos facelo no propio procedemento almacenado/páxina php, capturando a excepción ou comprobando cun select previo se existe o rexistro relacionado.






Posible solución Caso Práctico: Modificación Arquivo: bd.php

define('CONSULTAR_ESTADO_POR_ID',"SELECT id,descripcion FROM estados WHERE id=:id_estado");
define('ACTUALIZAR_ESTADO',"UPDATE estados set descripcion=:descripcion WHERE id=:id_estado");


Arquivo: consultar_estados.php

<?php
/* Lembrar quitar isto ao probar o scripts sen erros */
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

require('/var/www/confBD/bd.php');

try {
    $dsn = sprintf("mysql:host=%s;dbname=%s;charset=utf8mb4", SERVIDOR, BD);
    $conex = new PDO($dsn, USUARIO, PASSWORD);
    $conex->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    $erro = "";   // Variable que a usaremos para amosar os posibles erros controlados por nos que poidan darse.
?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="es" xml:lang="es">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>Xestión de estados</title>
    </head>
    <body>
        <form action="alta_estado.php" method="post">
            <button type="submit">Novo Estado</button>
        </form>
        <table border="1" style="margin-top:20px">
            <tr>
                <th>Estado</th>
                <th>Accións</th>
            </tr>
        <?php
            $result=$conex->query(CONSULTAR_ESTADOS);    // Temos que poñer prepare
            if ($result && $result->rowCount() > 0) {
                while ($row = $result->fetch(PDO::FETCH_ASSOC)) { 
                    $nombre = htmlentities($row['descripcion']);
                    echo "<tr>";
                    echo "<td>$nombre</td>";
                    echo "<td>";
                    printf("<a href='editar_estado.php?id=%s'>Editar</a>",urlencode($row['id']));
                    echo("<form action='procesar_borrar_estado.php' method='post'>");
                    printf("<input type='hidden' name='id' value='%s' />",htmlentities($row['id']));
                    echo '<input onclick="return confirm(\'Estás seguro de que queres borrar este estado?\');" type="submit" value="Borrar" name="btnBorrarEstado" style="background:none;border:none;padding:0;margin:0;color: blue; text-decoration:underline; cursor:pointer; font-size:inherit" />';
                    echo '</form>';
                    echo "</td>";
                    echo "</tr>";
                }
            }

            $result = null;
        ?>    
        </table>


        <div>
            <?php
                if(isset($_GET['id'])) printf("<h3>Estado con id %s dado de alta correctamente.</h3>",htmlentities($_GET['id']));
                if(isset($_GET['msg'])) printf("<h4>%s</h3>",htmlentities($_GET['msg']));
                if(isset($_GET['error'])) printf("<h2>Houbo un erro: %s</h2>",htmlentities($_GET['error']));
            ?>
        </div>    
        
    </body>    
</html>
<?php
}    // Pecha o try do principio da páxina
catch (PDOException $e) {
    die("Erro PDO: " . $e->getMessage());
} catch (Exception $e) {
    die("Erro xeral: " . $e->getMessage());
} finally {
    $conex = null; // Pechar a conexión
}
?>



Arquivo: campos_estado.php

<label for="nombre">Descricción:</label>
<input type="text" maxlength="100" id="descripcion" name="descripcion" required value="<?php echo isset($descripcion) ? htmlentities($descripcion) : ''; ?>">


Arquivo: editar_estado.php

<?php
/* Lembrar quitar isto ao probar o scripts sen erros */
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

require('/var/www/confBD/bd.php');

try {
    $dsn = sprintf("mysql:host=%s;dbname=%s;charset=utf8mb4", SERVIDOR, BD);
    $conex = new PDO($dsn, USUARIO, PASSWORD);
    $conex->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    $erro = "";   // Variable que a usaremos para amosar os posibles erros controlados por nos que poidan darse.

    $stmt = $conex->prepare(CONSULTAR_ESTADO_POR_ID);
    $stmt->bindValue(":id_estado", $_GET['id'], PDO::PARAM_INT);
    $result = $stmt->execute();
    if ($result) {
        $row = $stmt->fetch(PDO::FETCH_ASSOC);
        $id = $row['id'];
        $descripcion = htmlentities($row['descripcion']);

        $stmt = null;
    } else {
        $erros = "Non se atopan os datos da pista!!!!";
    }


?>
<!DOCTYPE html>
<html>
<head>
  <title>Modificar Estado</title>
</head>
<body>  
    <h3>EDITAR ESTADO</h3>

  <form method="POST" action="procesar_editar_estado.php">
    <?php include 'campos_estado.php'; ?>
    <div>
        <input type="hidden" name="id_orixinal" value="<?php echo $id; ?>">
        <input type="submit" value="Modificar" name="btnModificarEstado">
    </div>
  </form>
  <?php 
    if(!empty($erros)){
        printf("<h3>$erros</h3>");
    }
  ?>
</body>
</html>

<?php
}    // Pecha o try do principio da páxina
catch (PDOException $e) {
    die("Erro PDO: " . $e->getMessage());
} catch (Exception $e) {
    die("Erro xeral: " . $e->getMessage());
} finally {
    $conex = null; // Pechar a conexión
}
?>


Arquivo: procesar_editar_estado.php

<?php
/* Lembrar quitar isto ao probar o scripts sen erros */
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

require('/var/www/confBD/bd.php');

try {
    $dsn = sprintf("mysql:host=%s;dbname=%s;charset=utf8mb4", SERVIDOR, BD);
    $conex = new PDO($dsn, USUARIO, PASSWORD);
    $conex->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);


    $error = '';
    $msg = '';
    if (isset($_POST['btnModificarEstado'])) {

        $desc_novo = strtoupper($_POST['descripcion']);
        if (strlen($desc_novo) < 4 || strlen($desc_novo) > 100) {
            $error = sprintf("error=%s", urlencode("O nome do estado non pode ter menos de 4 ou 100 caracteres"));
        } else {
            $stmt = $conex->prepare(ACTUALIZAR_ESTADO);    // Temos que poñer prepare
            $stmt->bindValue(':id_estado', $_POST['id_orixinal'], PDO::PARAM_INT);
            $stmt->bindValue(':descripcion', $desc_novo, PDO::PARAM_STR);
            $result = $stmt->execute();

            if ($result) {
                $msg = sprintf("msg=%s", urlencode("Estado actualizado correctamente."));
            } else {
                $error = sprintf("error=$s", urlencode("Houbo un problema na actualización."));
            }
        }
    }
} catch (PDOException $e) {
    $error = sprintf("error=PDO:%s", urlencode($e->getMessage()));
} catch (Exception $e) {
    $error = sprintf("error=ERRO XERAL:%s", urlencode($e->getMessage()));
} finally {
    $conex = null; // Pechar a conexión
}
$url = sprintf("consultar_estados.php?%s&%s", $msg, $error);
header("Location:" . $url);





-- Ángel D. Fernández González -- (2025).