PHP Validando usuarios
Ir a la navegación
Ir a la búsqueda
Sumario
Introdución
- Un aspecto ao que case sempre imos enfrontarnos é ao de permitir o acceso a certas páxinas en función dos permisos que teña un determinado cliente.
- Para obter ditos permisos teremos que validar ao usuario e identificalo.
- A identificación case sempre vai vir dun formulario no que o usuario introduce o seu login-password.
- Nos recollemos ditos datos e normalmente faremos unha consulta a unha base de datos para comprobar que o usuario existe.
- Neste punto imos ver como podemos facer para que o usuario non poida entrar nas páxinas se non está validado.
- Fixarse que estamos implementando un mecanismo de autenticación de usuarios.
- Non indicamos nada acerca dos permisos que ten dito usuario. Por exemplo, un administrador e un usuario son usuarios que teñen dereito de conexión ao sitio web, pero cada un deles terá permisos diferentes para poder realizar accións distintas...
- IMPORTANTE: Durante o proceso de autenticación, o navegador envía ao servidor o usuario/password introducido polo usuario. Eses datos deben ir cifrados para que non poidan ser obtidos de forma fraudulenta pola rede. Para iso é necesario empregar certificados dixitais que no caso das páxinas web, tradúcese en empregar unha conexión https no que o servidor web emite un certificado dixital váliado que o indentifica.
- Nunca se debe desenvolver unha aplicación web no que non se empregue este tipo de certificado.
- Como facelo queda fora dos contidos deste curso, polo que as probas que estades a desenvolver empregan conexións non seguras de tipo http.
Exemplo rexistro/validación de usuario e carrito da compra
- Imos facer un pequeno sitio web no que imos poder rexistar novos usuarios e despois mediante unha validación imos poder ter acceso as páxinas para mercar produtos e xestionar un carrito da compra
Rexistro de usuarios
- Nesta páxina vaise amosar un login/password e vaise rexistrar un usuario/password.
- Primeiro temos que crear a táboa usuarios no Mysql:
1 CREATE TABLE `php`.`usuarios` ( 2 `id` INT NOT NULL AUTO_INCREMENT, 3 `login` VARCHAR(50) NOT NULL, 4 `password` VARCHAR(255) NOT NULL, 5 PRIMARY KEY (`id`), 6 UNIQUE INDEX `login_UNIQUE` (`login` ASC) VISIBLE);
- Nesta táboa o password vai estar encriptado cunha función de hash que en principio devolve como mínimo 60 caracteres, pero que pode chegar a devolver ata 255 caracteres, por se nun futuro cambia a implementación.
- Agora necesitamos gardar usuarios/password nesa táboa. Para iso imos facer uso das funcións:
- password_hash() => Para gardar a contrasinal
- password_veriry() => Para comprobar a contrasinal
- Engadimos ao arquivo bd.inc.php que queda fora da ruta onde apunta o sitio web, a orde para engadir un usuario. Lembrar que isto xa o vimos na UD3.
- Podemos empregar un procedemento almacenado de Mysql ou a orde SQL Insert. Lembrar que xa expliquei que é moito máis seguro empregar o procedemento ou ordes prepare.
Arquivo /var/www/confBD/bd.inc.php
1 define('INSERIR_USUARIOS',"INSERT INTO usuarios (login,password) VALUES ('%s','%s')");
- Creamos unha páxina php para dar de alta usuarios.
- Como queremos enviar a esta páxina información se o rexistro foi correcto ou se houbo algún tipo de erro, imos crear un include no que se amosarán o contido de dúas variables de sesión que imos empregar para isto:
Arquivo UD4_Exemplo1_Mensaxes.inc.php
<?php if (!empty($_SESSION['msg'])){ printf("<div>INFORMACIÓN: <b>%s</b>",$_SESSION['msg']); } if (!empty($_SESSION['error'])){ printf("<div>ERROR: <b>%s</b>",$_SESSION['error']); } unset($_SESSION['msg']); unset($_SESSION['error']);
- Arquivo UD4_Exemplo1_Rexistro_Formulario.php
<?php session_start(); unset($_SESSION['autenticado']); $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); // Para evitar ataques csrf ?> <!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 charset="utf-8" /> <title>Formulario</title> <style> .formularios{ width: 30%; margin: 0px auto; } .etiqueta{ float: left; width: 190px; } .botonesformularios{ width: 50%; margin: 30px auto; text-align: center; } </style> </head> <body> <form id="frmValidacion" class="formularios" method="post" action="procesar_UD4_Exemplo1_Rexistro_Usuarios.php"> <input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>"> <div> <div class='etiqueta'>Login:</div> <input type="text" required size="15" maxlength="15" name="txtLogin" /> </div> <div> <div class='etiqueta'>Password:</div> <input type="password" required size="15" maxlength="15" name="txtPassword" /> </div> <div class="botonesformularios"> <input type='submit' value="ENVIAR" name="btnRexistrar" /> <input type='reset' value="LIMPAR" name="btnLimpar" /> </div> </form> <?php include('UD4_Exemplo1_Mensaxes.inc.php') ?> </body> </html>
- Liña 2: Sempre debemos ter o session_start() ao comezo da páxina se imos traballar con variables de sesión.
- Liña 3: Dita variable de sesión estará explicada posteriormente. Adiantar que é a variable que imos utilizar para deixar visualizar ao usuario as páxinas protexidas (que requiran unha autenticación previa).
- Liña 47: Facemos o include das mensaxes de erro e aviso se se producen na páxina de procesar.
- Visualizamos isto:
- O seguinte será rexistrar o usuario/password na táboa usuarios.
- Para iso imos facer uso da función password_hash() que permite encriptar un texto cun cifrado e vai ser a password a gardar na táboa de usuarios.
- Para comprobar o usuario cando intente entrar empregaremos password_verify().
- Arquivo procesar_UD4_Exemplo1_Rexistro_Usuarios.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); session_start(); if (!isset($_POST['btnRexistrar']) || ($_POST['csrf_token'] !== $_SESSION['csrf_token'])){ // Se non vimos de premer o botón de rexistro volvemos a login. O csrf_token para evitar ataques unset($_SESSION['csrf_token']); header("location:UD4_Exemplo1_Rexistro_Formulario.php"); exit(); } require ('/var/www/confBD/bd.inc.php'); try { $conex = new mysqli(SERVIDOR, USUARIO, PASSWORD,BD); $conex->set_charset('utf8mb4'); // Xestionamos a operacion do segundo formulario => Alta , Baixa ou Modificacion if ((strlen($_POST['txtLogin'])<4) || (strlen($_POST['txtPassword'])<4)){ $_SESSION['error'] = sprintf("A lonxitude do login e password non poden ter menos de 4 caracteres..."); } else { // Eliminamos caracteres non permitidos $login = filter_var($_POST['txtLogin'],FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_FLAG_NO_ENCODE_QUOTES); $password = password_hash($_POST['txtPassword'],PASSWORD_DEFAULT); // Escapamos as comillas simples e dobres $login = $conex->real_escape_string(strtoupper($login)); $ordeSQL=sprintf(INSERIR_USUARIOS,$login,$password); $conex->query($ordeSQL); $_SESSION['msg'] = sprintf("Usuario rexistrado correctamente."); } } // Pecha o try da parte superior da páxina. Lembrar que aos usuarios non se lle deben amosar os erros. Isto está posto a nivel informativo para os programadores catch (mysqli_sql_exception $e) { $_SESSION['error']=sprintf("Erro mysql: %s",htmlentities($e->getMessage())); // Lembra que getMessage non se debe enviar ao cliente. Posto por motivos de depuración } catch (Expcetion $e) { $_SESSION['error']=sprintf("Erro xeral: %s",htmlentities($e->getMessage())); // Lembra que getMessage non se debe enviar ao cliente. Posto por motivos de depuración } finally{ if(!empty($conex)){ $conex->close(); } } unset($_SESSION['csrf_token']); // Para evitar ataques csrf $url = sprintf("UD4_Exemplo1_Rexistro_Formulario.php"); header("Location:" . $url); ?>
- Liña 8: Fixarse que despois da orde 'header' hai un exit para que o script non continúe executándose. Isto é así xa que o header non se enviará ao cliente ata que non remate o script. Dependerá de nos como programadores se queremos 'facer' algo máis antes de redirixir a páxina do navegador do cliente.
- Liña 13: Sempre debemos ter o session_start() ao comezo da páxina se imos traballar con variables de sesión.
- Liña 28: Encriptamos o password.
Validando usuarios
- Agora que xa podemos rexistrar usuarios imos crear un formulario de login.
- O código será o mesmo que o de rexistro, cambiando o action do formulario (poderiamos poñer a mesma páxina cunha variable cambiando o action en función do que páxina se cargue).
Arquivo UD4_Exemplo1_Login_Formulario.php
1 <?php 2 session_start(); 3 unset($_SESSION['autenticado']); 4 $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); // Para evitar ataques csrf 5 ?> 6 7 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 8 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 9 <html xmlns="http://www.w3.org/1999/xhtml" lang="es" xml:lang="es"> 10 <head> 11 <meta charset="utf-8" /> 12 <title>Formulario</title> 13 <style> 14 .formularios{ 15 width: 30%; 16 margin: 0px auto; 17 } 18 .etiqueta{ 19 float: left; 20 width: 190px; 21 } 22 .botonesformularios{ 23 width: 50%; 24 margin: 30px auto; 25 text-align: center; 26 } 27 </style> 28 </head> 29 <body> 30 <form id="frmValidacion" class="formularios" method="post" action="procesar_UD4_Exemplo1_Login_Usuarios.php"> 31 <input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>"> 32 <div> 33 <div class='etiqueta'>Login:</div> 34 <input type="text" required size="15" maxlength="15" name="txtLogin" /> 35 </div> 36 <div> 37 <div class='etiqueta'>Password:</div> 38 <input type="password" required size="15" maxlength="15" name="txtPassword" /> 39 </div> 40 <div class="botonesformularios"> 41 <input type='submit' value="ENVIAR" name="btnRexistrar" /> 42 <input type='reset' value="LIMPAR" name="btnLimpar" /> 43 </div> 44 </form> 45 46 <?php 47 include('UD4_Exemplo1_Mensaxes.inc.php') 48 ?> 49 </body> 50 </html>
- Agora necesitamos comprobar se o login-password está rexistrado.
- Para iso creamos no arquivo bd.inc.php a orde SQL que vai comprobar isto.
Arquivo bd.inc.php
1 define('VALIDAR_USUARIOS', "SELECT password FROM usuarios WHERE login='%s'"); // O login non debería poder repetirse ao rexistrar un usuario
- E por último, creamos a páxina que vai validar dito usuario. En caso de que exista e sexa correcto o login/password, empregaremos a variable de sessión $_SESSION['autenticado'] para darlle o valor do login e cargaremos unha páxina de nome consultar_exemplares_por_libro_con_validacion.php baseada nunha páxina feita na UD3.
- A variable a empregaremos para chequear todas as páxinas nas que se necesite que o usuario estea autentificado.
Arquivo procesar_UD4_Exemplo1_Login_Usuarios.php
1 <?php 2 /* Lembrar quitar isto ao probar o scripts sen erros */ 3 ini_set('display_errors', 1); 4 ini_set('display_startup_errors', 1); 5 error_reporting(E_ALL); 6 7 session_start(); 8 9 if (!isset($_POST['btnRexistrar']) || ($_POST['csrf_token'] !== $_SESSION['csrf_token'])){ // Se non vimos de premer o botón de rexistro volvemos a login. O csrf_token para evitar ataques 10 unset($_SESSION['csrf_token']); 11 header("location:UD4_Exemplo1_Login_Formulario.php"); 12 exit(); 13 } 14 unset($_SESSION['csrf_token']); // Para evitar ataques csrf 15 16 require ('/var/www/confBD/bd.inc.php'); 17 18 try { 19 $conex = new mysqli(SERVIDOR, USUARIO, PASSWORD,BD); 20 $conex->set_charset('utf8mb4'); 21 // Xestionamos a operacion do segundo formulario => Alta , Baixa ou Modificacion 22 if ((strlen($_POST['txtLogin'])>50)){ 23 $_SESSION['error'] = sprintf("A lonxitude do login non pode ser maior a 50 caracteres..."); 24 } 25 else { 26 // Eliminamos caracteres non permitidos 27 $login = filter_var($_POST['txtLogin'],FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_FLAG_NO_ENCODE_QUOTES); 28 $password = $_POST['txtPassword']; 29 30 // Escapamos as comillas simples e dobres 31 $login = $conex->real_escape_string(strtoupper($login)); 32 $ordeSQL=sprintf(VALIDAR_USUARIOS,$login,$password); 33 $result = $conex->query($ordeSQL); 34 if ($result && $result->num_rows>0){ 35 $row = mysqli_fetch_assoc($result); 36 $result->free(); // Liberamos da memoria os recursos 37 if(password_verify($password, $row['password'])){ // Usuario/Password correcto 38 $_SESSION['autenticado']=$login; // Permite saber se está autenticado no resto de páxinas 39 header("Location:UD4_consultar_exemplares_por_libro_con_validacion.php"); 40 exit(); 41 } 42 else{ 43 $_SESSION['error']=sprintf("Usuario ou password non correctos"); // Lembra que getMessage non se debe enviar ao cliente. Posto por motivos de depuración 44 header("Location:UD4_Exemplo1_Login_Formulario.php"); 45 exit(); 46 } 47 } 48 else{ 49 $_SESSION['error']=sprintf("Usuario ou password non correctos"); // Lembra que getMessage non se debe enviar ao cliente. Posto por motivos de depuración 50 header("Location:UD4_Exemplo1_Login_Formulario.php"); 51 exit(); 52 } 53 54 } 55 56 } // Pecha o try da parte superior da páxina. Lembrar que aos usuarios non se lle deben amosar os erros. Isto está posto a nivel informativo para os programadores 57 catch (mysqli_sql_exception $e) { 58 $_SESSION['error']=sprintf("Erro mysql: %s",htmlentities($e->getMessage())); // Lembra que getMessage non se debe enviar ao cliente. Posto por motivos de depuración 59 } 60 catch (Expcetion $e) { 61 $_SESSION['error']=sprintf("Erro xeral: %s",htmlentities($e->getMessage())); // Lembra que getMessage non se debe enviar ao cliente. Posto por motivos de depuración 62 } 63 finally{ 64 if(!empty($conex)){ 65 $conex->close(); 66 } 67 } 68 69 unset($_SESSION['csrf_token']); // Para evitar ataques csrf 70 $url = sprintf("UD4_Exemplo1_Login_Formulario.php"); 71 header("Location:" . $url); 72 73 ?>
- Agora soamente temos que verificar en todas as páxinas que necesiten autentificación a variable de sesión
Arquivo UD4_consultar_exemplares_por_libro_con_validacion.php
1 <?php 2 /* Lembrar quitar isto ao probar o scripts sen erros */ 3 ini_set('display_errors', 1); 4 ini_set('display_startup_errors', 1); 5 error_reporting(E_ALL); 6 7 session_start(); 8 9 if(!isset($_SESSION['autenticado'])){ 10 header("Location:UD4_Exemplo1_Login_Formulario.php"); 11 } 12 13 require ('/var/www/confBD/bd.inc.php'); 14 15 try { 16 $conex = new mysqli(SERVIDOR, USUARIO, PASSWORD,BD); // Indico o nome da bd 17 $conex->set_charset('utf8mb4'); 18 19 ?> 20 21 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 22 <html xmlns="http://www.w3.org/1999/xhtml" lang="es" xml:lang="es"> 23 <head> 24 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 25 <title>Operacións BD</title> 26 </head> 27 28 <body> 29 <div style='float:right; margin:20px'> 30 <a href='UD4_Exemplo1_validacion_sair.php'>Saír da aplicación</a> 31 </div> 32 <?php 33 34 $result=$conex->query(CONSULTAR_LIBROS); 35 if ($result && $result->num_rows>0){ 36 printf("<form action='%s' method='post'>",htmlentities($_SERVER['PHP_SELF'])); 37 echo "<select name='lstLibros' onChange='this.form.submit();'>"; 38 echo "<option value='-1'></option>"; 39 while($row = $result->fetch_assoc()) { 40 $cadea = ''; 41 if(isset($_POST['lstLibros']) && $row['id']==$_POST['lstLibros']){ // Se o libro seleccionado é igual ao id da fila, o seleccionamos en html 42 $cadea="selected='selected'"; 43 } 44 45 printf("<option value='%d' %s>%s</option>",htmlentities($row["id"]),$cadea,htmlentities($row["titulo"])); 46 } 47 echo "</select>"; 48 printf("</form>"); 49 $result->free(); // Liberamos da memoria os recursos 50 } 51 else { 52 echo "Non hai datos que amosar!!!!"; 53 } 54 ?> 55 <?php 56 // CONSULTAMOS OS EXEMPLARES DUN LIBRO SELECCIONADO NA COMBO 57 if (!empty($_POST['lstLibros']) && filter_var($_POST['lstLibros'],FILTER_VALIDATE_INT) && $_POST['lstLibros']!=-1){ 58 echo "<div style='margin-top:40px'>"; 59 $query=sprintf(CONSULTAR_EXEMPLARES_POR_LIBRO,$conex->real_escape_string($_POST['lstLibros'])); 60 $result=$conex->query($query); 61 if ($result && ($result->num_rows>0)){ 62 echo "<table border='1'>"; 63 echo "<th>Num. Exemplar</th><th>Imaxe</th><th>Prezo</th><th>Estado</th>"; 64 while($row = $result->fetch_assoc()) { 65 echo '<tr>'; 66 printf("<td>%d</td><td><img alt='%s' src='%s' width='42' height='42' /></td><td>%.2f</td><td>%s</td>", 67 htmlentities($row["id_exemplar"]),htmlentities($row["imaxe"]),CARTAFOL_IMAXES_WEB . htmlentities($row["imaxe"]), 68 htmlentities($row["prezo"]),htmlentities($row["desc_estado"])); 69 echo '</tr>'; 70 } 71 echo '</table>'; 72 $result->free(); // Liberamos da memoria os recursos 73 } 74 else { 75 echo "Non hai datos que amosar!!!!"; 76 } 77 echo "</div>"; 78 } 79 // $conex->close(); // Non fai falla pechar a conexión xa que esta se pecha ao final do páxina web. Noutras páxinas pode ser necesario 80 81 ?> 82 83 </body> 84 </html> 85 86 <?php 87 } // Pecha o try da parte superior da páxina 88 catch (mysqli_sql_exception $e) { 89 die("Erro mysql: " . $e->getMessage()); 90 } 91 catch (Expcetion $e) { 92 die("Erro xeral: " . $e->getMessage()); 93 } 94 finally{ 95 if(!empty($conex)){ 96 $conex->close(); 97 } 98 } 99 ?>
- E como queremos que o usuario poida pechar a sesión, creamos a páxina que o fai:
Arquivo UD4_Exemplo1_validacion_sair.php
1 <?php 2 session_start(); 3 4 session_unset(); 5 session_destroy(); 6 setcookie(session_name(),'',0,'/'); 7 8 header("Location:UD4_Exemplo1_Login_Formulario.php");
Carrito da compra
- Imos modificar a pantalla UD4_consultar_exemplares_por_libro_con_validacion.php para que podamos engadir exemplares a un suposto carrito.
- Engado a seguridade csrf_token ao formulario no que se escolle o libro.
- Comprobo que o usuario esté autenticado.
- Engado un enlace á paxina UD4_Exemplo1_engadir_produto_carrito.php no que envío como datos o csrf_token, o id de libro, o id de exemplar e o título. Neste caso opto por un enlace, pero tamén se podería facer cun formulario, enviando en campos ocultos os datos anteriores. Envío o título para non ter que ir á base de datos para obter o nome e amosalo no carrito.
- Engado un enlace para poder ver o contido do carrito da compra na páxina UD4_Exemplo1_ver_carrito.php
Arquivo UD4_consultar_exemplares_por_libro_con_validacion.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); session_start(); if(!isset($_SESSION['autenticado'])){ header("Location:UD4_Exemplo1_Login_Formulario.php"); exit(); } if (!empty($_POST['lstLibros'])) { // Seleccionamos un libro if ($_POST['csrf_token'] !== $_SESSION['csrf_token']){ // Se non vimos de premer a combo sae.csrf_token para evitar ataques unset($_SESSION['csrf_token']); header("location:UD4_Exemplo1_Login_Formulario.php"); exit(); } } $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); // Para evitar ataques csrf if(!isset($_SESSION['autenticado'])){ header("Location:UD4_Exemplo1_Login_Formulario.php"); exit(); } require ('/var/www/confBD/bd.inc.php'); $titulo = ""; // Empregado polos exemplares para cando se engade ao carrito try { $conex = new mysqli(SERVIDOR, USUARIO, PASSWORD,BD); // Indico o nome da 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>Operacións BD</title> </head> <body> <div style='float:right; margin:20px'> <a href='UD4_Exemplo1_validacion_sair.php'>Saír da aplicación</a> <a href='UD4_Exemplo1_ver_carrito.php'>Ver carrito <?php if(!empty($_SESSION['carrito'])) printf("(%s)",count($_SESSION['carrito']));?> </a> </div> <?php $result=$conex->query(CONSULTAR_LIBROS); if ($result && $result->num_rows>0){ printf("<form action='%s' method='post'>",htmlentities($_SERVER['PHP_SELF'])); printf("<input type='hidden' name='csrf_token' value=%s />",$_SESSION['csrf_token']); echo "<select name='lstLibros' onChange='this.form.submit();'>"; echo "<option value='-1'></option>"; while($row = $result->fetch_assoc()) { $cadea = ''; if(isset($_POST['lstLibros']) && $row['id']==$_POST['lstLibros']){ // Se o libro seleccionado é igual ao id da fila, o seleccionamos en html $cadea="selected='selected'"; $titulo = htmlentities($row["titulo"]); } printf("<option value='%d' %s>%s</option>",htmlentities($row["id"]),$cadea,htmlentities($row["titulo"])); } echo "</select>"; printf("</form>"); $result->free(); // Liberamos da memoria os recursos } else { echo "Non hai datos que amosar!!!!"; } ?> <?php // CONSULTAMOS OS EXEMPLARES DUN LIBRO SELECCIONADO NA COMBO if (!empty($_POST['lstLibros']) && filter_var($_POST['lstLibros'],FILTER_VALIDATE_INT) && $_POST['lstLibros']!=-1){ echo "<div style='margin-top:40px'>"; $query=sprintf(CONSULTAR_EXEMPLARES_POR_LIBRO,$conex->real_escape_string($_POST['lstLibros'])); $result=$conex->query($query); if ($result && ($result->num_rows>0)){ echo "<table border='1'>"; echo "<th>Num. Exemplar</th><th>Imaxe</th><th>Prezo</th><th>Estado</th>"; while($row = $result->fetch_assoc()) { echo '<tr>'; printf("<td>%d</td><td><img alt='%s' src='%s' width='42' height='42' /></td><td>%.2f</td><td>%s</td>", htmlentities($row["id_exemplar"]),htmlentities($row["imaxe"]),CARTAFOL_IMAXES_WEB . htmlentities($row["imaxe"]), htmlentities($row["prezo"]),htmlentities($row["desc_estado"])); printf("<td><a href='UD4_Exemplo1_engadir_produto_carrito.php?id_libro=%s&id_exemplar=%s&titulo=%s&token=%s'>ADD CARRITO</a></td>", htmlentities($row["libro_id"]),htmlentities($row["id_exemplar"]),$titulo, $_SESSION['csrf_token']); echo '</tr>'; } echo '</table>'; $result->free(); // Liberamos da memoria os recursos } else { echo "Non hai datos que amosar!!!!"; } echo "</div>"; } // $conex->close(); // Non fai falla pechar a conexión xa que esta se pecha ao final do páxina web. Noutras páxinas pode ser necesario ?> </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(); } } ?>
- Liñas 9-12: Se o usuario non está autenticado, sae da pantalla.
- Liñas 15-20: Comprobo se al premer a combo de selección de libro, o csrf_token enviado coincide có xerado ao cargar a páxina por primeira vez
- Liñas 45-47: Engado os enlaces para saír e ver o carrito.
- Liña 54: Engado o token de seguridade.
- Liñas 91-92: Engado o enlace para engadir un produto ao carrito enviando a clave primaria de exemplares e o token de seguridade.
Arquivo UD4_Exemplo1_engadir_produto_carrito.php
1 <?php 2 /* Lembrar quitar isto ao probar o scripts sen erros */ 3 ini_set('display_errors', 1); 4 ini_set('display_startup_errors', 1); 5 error_reporting(E_ALL); 6 7 8 session_start(); 9 10 11 if(!isset($_SESSION['autenticado'])){ 12 header("Location:UD4_Exemplo1_Login_Formulario.php"); 13 exit(); 14 } 15 16 if ($_GET['token'] !== $_SESSION['csrf_token']){ // Se non vimos de premer o enlace volvemos. FIXARSE QUE SE EMPREGA $_GET 17 unset($_SESSION['csrf_token']); 18 header("location:UD4_Exemplo1_Login_Formulario.php"); 19 exit(); 20 } 21 unset($_SESSION['csrf_token']); // Para evitar ataques csrf 22 23 $id_libro = htmlentities($_GET['id_libro']); 24 $id_exemplar = htmlentities($_GET['id_exemplar']); 25 $titulolibro = htmlentities($_GET['titulo']); 26 27 if(!isset($_SESSION['carrito'])) $_SESSION['carrito'] = []; 28 29 $datos_asociativo= ['id_libro' => $id_libro, 30 'id_exemplar' => $id_exemplar, 31 'titulo' => $titulolibro 32 ]; 33 34 foreach($_SESSION['carrito'] as $item){ 35 36 if($item==$datos_asociativo){ 37 $_SESSION['error']="O exemplar xa está no carrito"; // Lembra que getMessage non se debe enviar ao cliente. Posto por motivos de depuración 38 header("Location:UD4_consultar_exemplares_por_libro_con_validacion.php"); 39 exit(); 40 } 41 } 42 43 $_SESSION['carrito'][] = $datos_asociativo; 44 45 $_SESSION['msg'] = "Producto engadido correctamente"; 46 47 48 header("Location:UD4_consultar_exemplares_por_libro_con_validacion.php"); 49 50 ?>
-- Ángel D. Fernández González -- (2023).