Diferencia entre revisiones de «PHP UD3 OP ALTA»
Ir a la navegación
Ir a la búsqueda
| Línea 337: | Línea 337: | ||
$result = $conex->query($query); | $result = $conex->query($query); | ||
if ($result){ | if ($result){ | ||
| − | $msg = | + | $msg = sprintf("id=%d", $conex->insert_id); |
} | } | ||
} | } | ||
| Línea 369: | Línea 369: | ||
<br /> | <br /> | ||
| + | |||
===== Posible Solución: Utilizando procedementos almacenados ===== | ===== Posible Solución: Utilizando procedementos almacenados ===== | ||
Revisión del 07:00 25 oct 2023
Sumario
Introducción
- Requerimentos previos:
- Ter creada a base de datos indicada nunha sección anterior
- Ter gardados os parámetros de conexión nun arquivo separado como foi indicado nunha sección anterior
- Estes exercicios están baseados nunha versión de PHP 8.1 ou superior onde as ordes PHP para manexar a base de datos lanzan expcecións. Se tedes unha vesión anterior, teredes que facer o indicado na sección de consultas e na sección de conexión.
- 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.
- Para dar de alta novos rexistros na base de datos temos que facer uso da instrución SQL INSERT.
- O proceso é moi parecido ao que fixemos coas consultas, coa diferenza que no caso dunha instrución INSERT non temos rexistros de volta.
- Soamente debemos comprobar se a inserción a fixo correctamente, comprobando se a chamado ao método query devolve false.
- Comentar que tamén pode sernos útil a instrución INSERT IGNORE. Esta instrución non vai emitir ningún erro se intentamos inserir unha clave duplicada nunha táboa. Loxicamente a operación non se fai.
- Nestes exemplos, vaise empregar a versión PHP 8.1 ou superior que vai lanzar excepcións en caso de erro como xa vimos no control erros ao abrir a conexión á base de datos.
- Podedes consultar como controlar os erros nunha versión PHP anterior consultando a sección de consultas xa que o procedemento é o mesmo cambiando a orde SQL a executar.
- O proceso para realizar unha inserción é o seguinte:
- Abrimos unha conexión á base de datos.
- Construímos a orde SQL: INSERT INTO TABOA_1 (col1,col2) VALUES (valor1,'valor2')
- Neste caso a TABOA_1 está constituída por dúas columnas, a primeira numérica e a segunda de tipo cadea.
- Executamos a orde e comprobamos que a operación foi correcta:
- Pechamos a conexión á base de datos.
1 try { 2 3 $conex = new mysqli('SERVIDOR', 'USUARIO', 'PASSWORD', 'BD'); 4 $conex->set_charset('utf8mb4'); 5 6 7 $consulta = "INSERT INTO TABOA_1 (col1,col2) VALUES (valor1,'valor2')"; // Envía un dato numérico e un dato cadea. Nos empregaremos %d e %s nunha constante previamente definida e despois sprintf 8 $conex->query($consulta); 9 10 } catch (mysqli_sql_exception $e) { 11 die("Erro: " . $e->getMessage()); 12 } 13 catch (Expcetion $e) { 14 die("Erro xeral: " . $e->getMessage()); 15 } 16 finally{ 17 if(!empty($conex)){ 18 $conex->close(); 19 } 20 } 21 }
- Fixarse como a consulta a gardamos nunha variable para non ter problemas coas comiñas na chamada á función query.
- Cando o rexistro foi dado de alta correctamente podemos comprobar o número de rexistros afectados (no caso dun único rexistro sempre vai devolver 1, pero tamén se podería aplicar a un insert multifila).
1 .................. 2 $result=$conex->query($query); 3 if ($result) { 4 echo "Rexistro dado de alta correctamente"; 5 echo "Num. rexistros afectados:" . $conex->affected_rows; 6 } 7 $conex->close(); // Pechamos a conexión
Obtendo o valor dun campo autonumérico
- Normalmente cando deseñamos unha base de datos, certos campos que son claves os definimos como autonuméricos.
- Ao facelo, cando engadimos unha nova fila a un táboa, xérase un novo valor e en certas ocasións necesitamos obter dito valor xa que o podemos utilizar para gardar outros datos noutras táboas que o necesitan por estar relacionadas.
- Non vale a solución de engadir un dato e inmediatamente facer un 'select' buscando o valor máis alto, xa que non entorno multiusuario, dito valor non ten porqué ser o último engadido.
- Necesitamos utilizar a función mysqli::$insert_id].
- Dita función devolve o id autoxerado que se utilizou na última operación.
- Por exemplo, imaxinemos que temos a táboa TABLE_1 con dúas columnas, col1 int primary key autogenerate e col2 varchar(100).
- Cando executamos a orde: INSERT INTO TABLE_1 (col2) VALUES ('valor1')
- O proceso é o seguinte:
- Abrimos a conexión á base de datos.
- Executamos a orde SQL que engade unha nova fila.
1 $result=$conex->query("INSERT INTO TABLE_1 (col2) VALUES ('valor')"); 2 if ($result){ 3 // Operación correcta 4 printf ("Novo rexistro có id %d.\n", $conex->insert_id); 5 }
- Pechamos a conexión.
1 $conex->close(); // Pechamos a conexión
Alta utilizando procedementos almacenados
- O proceso de alta é o mesmo que o visto nas consultas, pero utilizando a orde SQL INSERT dentro do procedemento.
- Se estamos a utilizar procedementos almacenados, lembrar que en caso de erro '2014 - Commands out of sync; you can't run this command now', teredes que engadir debemos de engadir a seguinte liña despois de chamar a un procedemento almacenado:
1 if ($conex->multi_query($proc)){ // Neste caso supoño que o procedemento de alta devolve un conxunto de filas a maiores de facer o INSERT. Non é o normal. 2 $result = $conex->store_result(); 3 if ($result && ($result->num_rows>0)){ 4 while($fila=$result->fetch_assoc()){ 5 // Procesamos cada fila 6 } 7 $result->free(); 8 } 9 while($conex->next_result() && $conex->store_result());
- IMPORTANTE: Se o procedemento de alta non vai devolver datos (cun select) podemos facer uso da orde $conex->query($proc) sendo $proc='CALL NOME_PROC(parámetros)'
- Nota: Hai que ter unha correspondencia entre o tipo de dato e tamaño do parámetro do procedemento almacenado e a columna da táboa onde imos a inserir o dato.
- Así, se a táboa TABOA_1 ten de columnas col1 int, col2 varchar(100)
- Se defino un procedemento almacenado para dar de alta unha nova fila: CREATE PROCEDURE ALTA_FILA_TABOA_1(_param1 int, _param2 varchar(100))
- Indicar que dentro dun procedemento almacenado imos poder ter sentenzas:
- E outras de control de fluxo como podedes ver neste enlace.
Caso práctico
- Imos facer o mantemento da táboa ESTADOS.
- Imos crear unha páxina de nome consultar_estados.php. Dita páxina amosará o listado de estados nunha táboa e terá un botón cun formulario na parte superior para dar de alta un novo estado.
- Dito formulario apuntará a unha páxina de nome alta_estado.php onde se amosará un formulario cun campo de texto para engadir a descricción do estado (lembrar que o id é autonumérico).
- O action da páxina 'alta_estado.php' chamará a unha páxina de nome 'procesar_alta_estado.php' o cal fará a operación de INSERT e fará unha redirección á paxina 'consultar_estados' enviando na URL o novo id xerado e unha mensaxe que poderá ser de información (alta dada de alta correctamente) ou de erro.
- A páxina alta_estado fará uso dun include de nome campos_estado.php. En dita páxina (campos_estado.php) estará definido a caixa de texto do formulario que debe ser obrigatorio introducir un dato e o tamaño máximo será de 100 caracteres e o mínimo de 4.
- No exemplo emprégase a función strtoupper para converter o texto a maiúsculas antes de envialo á base de datos.
- Cando traballades con tipos de datos cadeas será algo que teredes que ter en conta. Vai depender se no formulario de entrada de datos permitides ou non as minúsculas, ides necesitar empregar esta opción.
- Outro aspecto importante é que ten que haber unha correspondencia de tipo e tamaño entre o campo da táboa onde imos facer a operación (neste caso a táboa ESTADOS, campo descripcion, que é un varchar(100)) e o parámetro que imos definir no procedemento almacenado.
- O envío das mensaxes de erro e id a través da URL non é o máis correcto, pero neste punto do curso aínda no vimos o emprego de variables de sesión que sería a forma correcto de facelo.
Posible Solución: Utilizando orden INSERT
- Lembrar que dependendo dos casos, teremos que verificar que o valor a engadir non estea dado de alta previamente...
Páxina bd.inc.php
1 define ('CONSULTAR_ESTADOS','select id,descripcion from estados order by descripcion'); 2 define('CONSULTAR_ESTADO_NUM',"SELECT count(*) as existe FROM estados WHERE upper(descripcion)=upper('%s')"); 3 define('INSERIR_ESTADO',"INSERT INTO estados (descripcion) VALUES ('%s')");
Arquivo consultar_estados.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 require ('/var/www/confBD/bd.inc.php'); 8 9 try { 10 $conex = new mysqli(SERVIDOR, USUARIO, PASSWORD,BD); 11 $conex->set_charset('utf8mb4'); 12 13 ?> 14 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 15 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 16 <html xmlns="http://www.w3.org/1999/xhtml" lang="es" xml:lang="es"> 17 <head> 18 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 19 <title>Xestión de estados</title> 20 </head> 21 <body> 22 <form action="alta_estado.php" method="post"> 23 <button type="submit">Novo Estado</button> 24 </form> 25 <table border="1" style="margin-top:20px"> 26 <tr> 27 <th>Estado</th> 28 </tr> 29 <?php 30 31 $resultado = $conex->query(CONSULTAR_ESTADOS); 32 33 while($fila = $resultado->fetch_assoc()) { 34 $nombre = htmlentities($fila['descripcion']); 35 echo "<tr>"; 36 echo "<td>$nombre</td>"; 37 echo "</tr>"; 38 } 39 40 $resultado->free(); 41 ?> 42 </table> 43 44 45 <div> 46 <?php 47 if(isset($_GET['id'])) printf("<h3>Estado con id %d dado de alta correctamente.</h3>",htmlentities($_GET['id'])); 48 if(isset($_GET['error'])) printf("<h2>Houbo un erro: %s</h2>",htmlentities($_GET['error'])); 49 ?> 50 </div> 51 52 </body> 53 </html> 54 <?php 55 } // Pecha o try da parte superior da páxina 56 catch (mysqli_sql_exception $e) { 57 die("Erro mysql: " . $e->getMessage()); 58 } 59 catch (Expcetion $e) { 60 die("Erro xeral: " . $e->getMessage()); 61 } 62 finally{ 63 if(!empty($conex)){ 64 $conex->close(); 65 } 66 } 67 ?>
Arquivo alta_estado.php
Arquivo campos_estado.php
1 <label for="nombre">Nome:</label> 2 <input type="text" maxlength="100" id="nombre" name="nombre" required><br>
Arquivo alta_estado.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 // Aunque esta página no hace uso de las constantes, al cargar los campos de animal, esa sí que hace uso de ellas. 8 // Podríamos ponerlo en la página de campos_animal.php, pero necesitaríamos poner require_once ya que la página de editar_animal.php también tiene el include 9 require('/var/www/confBD/bd.inc.php'); 10 ?> 11 12 13 <!DOCTYPE html> 14 <html> 15 <head> 16 <title>Alta Estado</title> 17 </head> 18 <body> 19 <h3>ALTA ESTADO</h3> 20 <form method="POST" action="procesar_alta_estado.php"> 21 <?php include 'campos_estado.php'; ?> 22 <div style='margin-top:20px'> 23 <input type="submit" value="ALTA" name="btnOperacion"> 24 </div> 25 </form> 26 </body> 27 </html>
Arquivo procesar_alta_estado.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 require ('/var/www/confBD/bd.inc.php'); 8 9 $error=""; // Variable que a usaremos para amosar os posibles erros que poidan darse 10 $msg=''; // Variable empregada para enviar o novo id xerado 11 try { 12 $conex = new mysqli(SERVIDOR, USUARIO, PASSWORD,BD); 13 $conex->set_charset('utf8mb4'); 14 // Xestionamos a operacion do segundo formulario => Alta , Baixa ou Modificacion 15 if (!empty($_POST['btnOperacion']) && $_POST['btnOperacion']=='ALTA'){ 16 if ((strlen($_POST['nombre'])<4) || (strlen($_POST['nombre'])>100)){ 17 $error = sprintf("error=%s", "A lonxitude do estado non pode ter máis de 100 caracteres nin menos de 5..."); 18 } 19 else { 20 // Eliminamos caracteres non permitidos 21 $novoEstado = filter_var($_POST['nombre'],FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_FLAG_NO_ENCODE_QUOTES); 22 // Escapamos as comillas simples e dobres 23 $novoEstado = $conex->real_escape_string(strtoupper($novoEstado)); 24 $query=sprintf(CONSULTAR_ESTADO_NUM,$novoEstado); 25 $result = $conex->query($query); 26 if ($result && ($result->num_rows>0)){ 27 $fila=$result->fetch_assoc(); 28 if ($fila['existe']>0) { 29 $error = sprintf("error=%s", "Ese estado xa existe."); 30 } 31 $result->free(); 32 } 33 34 if($error==''){ 35 $query=sprintf(INSERIR_ESTADO,$novoEstado); 36 $result = $conex->query($query); 37 if ($result){ 38 $msg = sprintf("id=%d", $conex->insert_id); 39 } 40 } 41 } 42 43 } // Fin da operacion de ALTA 44 45 } // 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 46 catch (mysqli_sql_exception $e) { 47 $error=sprintf("error='Erro mysql: %s'",htmlentities($e->getMessage())); 48 } 49 catch (Expcetion $e) { 50 $error=sprintf("error='Erro xeral: %s'",htmlentities($e->getMessage())); 51 } 52 finally{ 53 if(!empty($conex)){ 54 $conex->close(); 55 } 56 } 57 58 $url = sprintf("consultar_estados.php?%s&%s",$msg,$error); 59 header("Location:" . $url); 60 61 ?>
Posible Solución: Utilizando procedementos almacenados
- A diferenza do caso anterior:
- O id xerado terá que devolvelo o procedemento, mediante SELECT, un parámetro de SAÍDA ou un RETURN se estamos a utilizar unha función.
- Teremos que utilizar a función last_insert_id() para obter o id xerado dende o procedemento de Mysql.
- A comprobación de se o dato existe o facemos dentro do procedemento.
Procedemento almacenado creado en Mysql
1 DELIMITER $$ 2 3 CREATE DEFINER=`root`@`localhost` PROCEDURE `INSERIR_ESTADO`(_descripcion varchar(100)) 4 etiqueta:BEGIN -- Asociamos unha etiqueta ao código do procedemento para que poidamos facer algo parecido a un exit 5 declare existe int; 6 7 SELECT count(*) 8 INTO existe 9 FROM ESTADOS 10 WHERE upper(descripcion)=upper(_descripcion); 11 12 IF existe=1 THEN 13 begin 14 SELECT -1 as valor_devolto; 15 leave etiqueta; -- Para que saia do procedemento 16 end; 17 END IF; -- Fin do IF 18 19 INSERT INTO ESTADOS (descripcion) 20 VALUES (_descripcion); 21 22 SELECT last_insert_id() as valor_devolto; 23 24 END
- Liña 4: Utilizamos unha etiqueta para que poidamos utilizar a orde LEAVE xa que Mysql non ten outra forma de poder saír dun procedemento almacenado.
- Neste caso en concreto quizais podería ser más aconsellable utilizar unha función, xa que estamos a devolver un único dato (neste caso -1 ou a id xerada). Desta maneira, poñendo un return xa sairiamos da función.
- Liña 16: Utilizamos a funciuón last_insert_id() para obter o último id xerado da inserción.
- Comentar que dentro dos xestores de base de datos, nos procedementos/funcións podemos empregar as consultas directamente como expresións, por exemplo, no caso anterior:
1 DELIMITER $$ 2 3 CREATE DEFINER=`root`@`localhost` PROCEDURE `INSERIR_ESTADO`(_descripcion varchar(100)) 4 etiqueta:BEGIN -- Asociamos unha etiqueta ao código do procedemento para que poidamos facer algo parecido a un exit 5 6 IF (SELECT count(*) FROM ESTADOS WHERE upper(descripcion)=upper(_descripcion))>0 THEN 7 begin 8 SELECT -1 as valor_devolto; 9 leave etiqueta; -- Para que saia do procedemento 10 end; 11 END IF; -- Fin do IF 12 13 INSERT INTO ESTADOS (descripcion) 14 VALUES (_descripcion); 15 16 SELECT last_insert_id() as valor_devolto; 17 18 END
Páxina bd.inc.php
1 define('PROCEDEMENTO_INSERIR_ESTADO',"INSERIR_ESTADO('%s')");
Páxina Xestionar_Estados_Proc.php
1 <?php 2 3 require ('/var/www/confBD/bd.inc.php'); 4 //error_reporting(0); 5 6 $conex = new mysqli(SERVIDOR,USUARIO,PASSWORD,BD); 7 $conex->set_charset('utf8'); 8 9 if ($conex->connect_error){ 10 die('Erro de Conexión (' . mysqli_connect_errno() . ') ' . mysqli_connect_error()); 11 } 12 $erro=""; // Variable que a usaremos para amosar os posibles erros que poidan darse 13 ?> 14 15 16 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 17 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 18 <html xmlns="http://www.w3.org/1999/xhtml" lang="es" xml:lang="es"> 19 <head> 20 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 21 <title>Xestionar táboa Estados BD</title> 22 </head> 23 24 <body> 25 <!-- Esta parte poderíase facer con javascript --> 26 <form action="<?php echo htmlentities($_SERVER['PHP_SELF']) ?>" method='post'> 27 <h2>Escolle a operación a facer sobre a táboa ESTADOS</h2> 28 29 <input <?php echo (isset($_POST['rbtnOperacion']) && $_POST['rbtnOperacion']=='ALTA') ? "checked='checked'" : ""; ?> 30 onclick='javascript:this.form-submit()' type='radio' name="rbtnOperacion" value='ALTA'>ALTA</input> 31 <input <?php echo (isset($_POST['rbtnOperacion']) && $_POST['rbtnOperacion']=='BAIXA') ? "checked='checked'" : ""; ?> 32 onclick='javascript:this.form-submit()' type='radio' name="rbtnOperacion" value='BAIXA'>BAIXA</input> 33 <input <?php echo (isset($_POST['rbtnOperacion']) && $_POST['rbtnOperacion']=='MODIFICACION') ? "checked='checked'" : ""; ?> 34 onclick='javascript:this.form-submit()' type='radio' name="rbtnOperacion" value='MODIFICACION'>MODIFICACIÓN</input> 35 <?php 36 37 if (!empty($_POST['rbtnOperacion'])){ // Premimos unha opción => Xeramos o formulario 38 switch ($_POST['rbtnOperacion']){ 39 case 'ALTA': 40 printf("<div>Nome do novo estado:"); 41 printf("<input name='txtEstado' type='text' size='50' maxlength='100' /></div>"); 42 printf("<div><input name='btnOperacion' type='submit' value='ALTA' />"); 43 printf("<input type='reset' value='BORRAR' /></div>"); 44 break; 45 } 46 } 47 48 49 // Xestionamos a operacion do segundo formulario => Alta , Baixa ou Modificacion 50 if (!empty($_POST['btnOperacion']) && $_POST['btnOperacion']=='ALTA'){ 51 if (strlen($_POST['txtEstado'])>100){ 52 $erro = ">A lonxitude da cadea non pode ter máis de 100 caracteres..."; 53 } 54 else { 55 // Eliminamos caracteres non permitidos 56 $novoEstado = filter_var($_POST['txtEstado'],FILTER_SANITIZE_STRING); 57 // Escapamos as comillas simples e dobres 58 $novoEstado = $conex->real_escape_string($novoEstado); 59 $proc=sprintf(PROCEDEMENTO_INSERIR_ESTADO,$novoEstado); 60 $proc = sprintf("CALL %s",$proc); 61 if ($conex->multi_query($proc)){ 62 $result = $conex->store_result(); 63 if ($result && ($result->num_rows>0)){ 64 $fila=$result->fetch_assoc(); 65 switch($fila['valor_devolto']){ 66 case -1: 67 $erro = "Ese valor xa está dado de alta na base de datos..."; 68 break; 69 default: 70 printf("<h2>Valor dado de alta correctamente</h2>"); 71 printf("<h3>Nova clave %d</h3>",$fila['valor_devolto']); 72 } 73 $result->free(); 74 } 75 else{ // Sempre ten que devolver algo como temos implementado o proc. 76 $erro = 'Houbo un erro na chamada á base de datos'; 77 } 78 } 79 else{ 80 $erro = 'Houbo un erro na chamada á base de datos'; 81 } 82 } 83 84 } // Fin da operacion de ALTA 85 86 ?> 87 </form> 88 89 90 <?php 91 if ($erro!='') { 92 printf("<h3>%s</h3>",$erro); 93 } 94 $conex->close(); // Pechamos a conexión 95 96 ?> 97 98 99 </body> 100 </html>
- Neste caso é necesario utilizar a opción multi_query xa que recuperamos un dato que devolve o procedemento.
Como tratar aos caracteres 'estraños'
- Con caracteres 'estraños' queremos dicir caracteres fora do abecedario e caracteres numéricos, coma por exemplo: ', ,\n,....
- Aquí debemos diferenciar dous casos.
- Cando queremos gardar caracteres estraños dentro da base de datos.
- Cando queremos impedir que o usuario poida utilizar ese tipo de caracteres.
Necesitamos gardar caracteres 'estraños' na base de datos
- Neste caso, teremos que 'codificar' e 'descodificar' os datos.
- Codificaremos os datos cando os gardemos (ou modifiquemos) coa orde SQL INSERT e UPDATE.
- Decodificaremos: Pode non ser necesario, dependerá do dato e o que queiramos facer con él.
- As funcións que podemos empregar para isto son:
- Función htmlentities: Codifica os caracteres en entidades html. Por exemplo, '<' o codifica como '<'. Fixarse nas 'opcións' xa que por defecto codifica as comiñas dobres pero non as simples.
- Función html_entity_decode: Realiza o proceso inverso ao anterior.
- Por exemplo, imaxinade que o usuario engade nunha caixa de texto un código HTML que queredes gardar na base de datos, pero que o navegador non debe 'interpretar'. Por exemplo a cadea: <script>alert('ola);</script>
- Isto podería ser interpretado como un ataque como xa vimos anteriormente. Codificando a cadea coa función htmlentities isto non é posible.
- Cando amosemos o resultado de aplicar a función, non deberemos decodificalo, xa que o que queremos é que o navegador 'amose' a cadea, non que 'interprete' o código e execute o código javascript.
IMPORTANTE: Lembrar que para utilizar esta solución, todos os datos (ou os que nos interesen que poidan ter este tipo de caracteres) deben ser codificados.
- Se un usuario fai unha busca sobre algún destes campos, teremos que codificar tamén a cadea escrita polo usuario.
- Outra forma de 'codificar' caracteres 'estraños' é empregando a función mysqli::real_escape_string.
- Esta función, aplicada a unha cadea de caracteres, 'escapa' os seguintes caracteres: NUL (ASCII 0), \n, \r, \, ', ", e Control-Z. Isto quere dicir que antepón a ditos caracteres o carácter \ e isto fai que o Mysql interprete o seguinte carácter como o que é.
Nota:Deberemos aplicar sempre esta función para impedir a inxección de código se non aplicamos outra función que 'codifique' as comiñas simples, antes de enviar os datos á base de datos.
- Vexamos un exemplo coa seguinte cadea:
- $valor = "O'Really";
- Queremos facer a seguinte consulta: INSERT INTO AUTORES (nome) VALUES ('$valor')
- Se substituímos $valor polo que vale, vemos que temos un problema coas comiñas simples e daría un erro de sintaxe SQL.
- Para solucionalo,podemos aplicar a función 'real_escape_string' a $valor da forma:
1 <?php 2 $mysqli = new mysqli("localhost", "usuario", "contrasinal", "bd"); 3 4 if (mysqli_connect_errno()) { 5 printf("Erro na conexión: %s\n", mysqli_connect_error()); 6 exit(); 7 } 8 9 10 $valor = "O'Really"; 11 12 /* esta consulta faia debido a que non escapa $cidade */ 13 if (!$mysqli->query("INSERT INTO AUTORES (nome) VALUES ('$valor')")) { 14 printf("Erro: %s\n", $mysqli->sqlstate); 15 } 16 17 $valor = $mysqli->real_escape_string($valor); 18 19 /* esta consulta con $valor escapada funcionará */ 20 if (!$mysqli->query("INSERT INTO AUTORES (nome) VALUES ('$valor')")) { 21 printf("%d fila inserida.\n", $mysqli->affected_rows); 22 } 23 24 $mysqli->close(); 25 ?>
Non queremos que o usuario poida utilizar este tipo de caracteres
- A forma máis sinxela é utilizar os filtros xa vistos anteriormente nesta wiki.
-- Ángel D. Fernández González -- (2023).