PHP Operacións BD Mysql
Sumario
Introdución
- Como comentamos no punto anterior, para conectarnos a un xestor de base de datos específico imos ter que ter instalados os drivers correspondentes.
- Un driver é o software que nos permite comunicarnos cun xestor de base de datos, pero normalmente non imos facer dita comunicación utilizando o driver directamente se non que o usaremos a través dunha API, que son un conxunto de clases, funcións,... que nos permiten facer uso do driver e conectar a un xestor de base de datos.
- Existen dous tipos de API´s:
- Procedimentais: Facemos uso de funcións para realizar as operacións contra a base de datos.
- Orientadas a obxectos: Instanciamos clases e chamamos a métodos dos obxectos creados.
Normalmente faremos uso desta segunda opción.
- En PHP, ditas API´s se 'activan' facendo uso de Extensións.
- Indicar que unha API non é o mesmo que unha extensión en PHP, xa que algunhas extensións non proporcionan ningunha API ao usuario (por exemplo a extensión do driver PDO MySQL, non proporciona ningunha API ó programador PHP).
- Existen tres APIs principais para conectar a un servidor de bases de datos MySQL:
- Extensión MySQL de PHP
- Extensión mysqli de PHP
- Obxectos de Datos de PHP (PDO)
- Para conectarnos imos utilizar as funcións mysqli (mysql improved) que foron introducidas a partires de Mysql 4.1
- A extensión mysqli ven incluída nas versiones PHP 5 e posteriores.
- Algunha das melloras de dita extensión con respecto á extensión mysql:
- Interfaz orientada a obxectos
- Soporte para declaracións preparadas.
- Soporte para Transaccións
- Dita extensión tamén ten unha versión procedural, de tal forma que imos poder chamar ás funcións de dúas maneiras diferentes:
Exemplo de función cun estilo procedimental que pecha unha conexión a unha base de datos ($link é un identificador cando se fai a conexión contra a base de datos):
1 mysqli_close($link);
Exemplo de función cun estilo obxectual que pecha unha conexión a unha base de datos:
1 mysqli::close();
- Aquí tedes un cadro comparativo obtido de php.net onde se ve o comentado anteriormente:
Nota: Máis información neste enlace.
Conexión
- Partimos da base de que xa temos instalado:
- O xestor de bases de datos Mysql
- Unha base de datos creada. Neste manual vai ter de nome PHP. Facer que o 'default collation' sexa utf8_spanish2_ci.
- Un usuario / password que teña todos os permisos sobre a base de datos creada. Neste manual o usuario/password creado son user_php/user_php.
- Todo o anterior xa está indicado no punto anterior da wiki.
- Utilizando procedementos: mysqli_connect
- Utilizando obxectos: mysql::_construct
- Sintaxe (se indica a sintaxe do construtor e polo tanto será equivalente a facer un 'new' da clase mysqli):
1 mysqli::__construct ([ string $host = ini_get("mysqli.default_host") [, string $username = ini_get("mysqli.default_user") [, string $passwd = ini_get("mysqli.default_pw") [, string $dbname = "" [, int $port = ini_get("mysqli.default_port") [, string $socket = ini_get("mysqli.default_socket") ]]]]]] )
- Todos eles son optativos, pero normalmente indicaremos o nome de host, login, password e base de datos.
- Os parámetros son:
- Host a conectar (cadea): Pode ser o nome ou a dirección IP. Normalmente imos poñer 'localhost' (se o xestor de bases de datos está instalado no mesmo equipo que o servidor web).
- Nome do usuario con acceso á base de datos (cadea): Nome do usuario que ten acceso á base de datos.
- Password (cadea): Password do usuario.
- Dbname (cadea): Nome da base de datos sobre a que imos traballar.
- Porto (numérico): Porto no que está escoitando o xestor de base de datos. No caso de mysql ó o 3306.
- Socket (cadea): Socket ou tubería para conectar có xestor de bases de datos. En Linux é un tipo especial de arquivo que serve para 'transmitir' información, neste caso, cara o xestor de bases de datos.
- Aplicado ao noso caso, teremos a seguinte orde:
1 $conex = new mysqli('localhost','user_php','user_php','PHP');
- En caso de erro, $conex é un obxecto que represente a conexión á base de datos.
- En caso de ter unha versión PHP anterior á PHP 5.2.9 e 5.3.0 teremos que chamar á función mysqli_connect_error() desta forma:
1 $conex = new mysqli('localhost','user_php','user_php','PHP'); 2 if (mysqli_connect_error()){ 3 die('Erro de Conexión (' . mysqli_connect_errno() . ') ' . mysqli_connect_error()); 4 }
- En caso de ter unha versión PHP posterior á PHP 5.2.9 e 5.3.0:
1 $conex = new mysqli('localhost','user_php','user_php','PHP'); 2 if ($conex->connect_error) { 3 die('Erro de Conexión (' . $conex->connect_errno . ') ' . $conex->connect_error); 4 }
- Como vemos amosamos por un lado a mensaxe de erro que devolve o xestor de bases de datos e o número de erro asociado a esa mensaxe.
- Podemos consultar os número de erro e mensaxes asociadas neste enlace.
- Por exemplo, imos modificar o password do usuario por un que non exista e veremos o resultado:
1 $conex = new mysqli('localhost','user_php','password_non_existe','PHP'); 2 if (mysqli_connect_error()){ 3 die('Erro de Conexión (' . mysqli_connect_errno() . ') ' . mysqli_connect_error()); 4 }
- Dará como resultado:
Gardando os datos de conexión nun lugar seguro
- Como é obvio os datos de base de datos, usuario e password son moi importantes e non debemos permitir que alguén poida descubrilos.
- O que faremos será o seguinte:
- Definiremos en forma de constantes ditos datos nun arquivo de include.
- Gardaremos dito arquivo fora do cartafol de acceso do noso sitio web.
- O primeiro punto, definir en forma de constante e nun arquivo de include os datos da conexión:
Arquivo: bd.inc.php:
1 <?php 2 3 define ('SERVIDOR','localhost'); 4 define ('USUARIO','user_php'); 5 define ('PASSWORD','user_php'); 6 define ('BD','PHP');
- Faremos un require deste arquivo en todas as páxinas que necesiten unha conexión á base de datos. Desta forma, se necesitamos cambiar algo soamente o cambiaríamos nun arquivo.
- O segundo punto consiste en descubrir cal é a ruta física á que apunta o noso servidor web e colocar o arquivo de include 'fora' desa ruta.
- Temos neste punto da Wiki información sobre como funciona Apache e como saber a onde apunta o servidor web no seu arquivo de configuración.
- Temos varias opcións:
- Facendo uso da constante __DIR__.
- Facendo uso do array global $_SERVER e dentro deste a entrada $_SERVER['DOCUMENT_ROOT'.
- Se facemos un echo destas variables dentro dunha páxina do noso sitio web, obteremos unha ruta, coma por exemplo:
1 /var/www/html/
- Nota: Se o facemos coa constante __DIR__ e a páxina que está a facer o echo se atopa dentro dun cartafol, tamén aparecerá o cartafol (por exemplo /var/www/html/cartafol/).
- Isto quere dicir que o servidor web (e polo tanto calquera usuario de Internet) vai poder acceder as páxinas que se atopan no cartafol /var/www/html e calquera dentro del.
- Unha medida de seguridade é colocar o arquivo de include 'fora' desta ruta. Por exemplo, podemos crear un arquivo no cartafol /var/www/confBD
- A dito cartafol ten que poder acceder o usuario que utiliza o Apache para acceder aos cartafoles a nivel do S.O. (no caso de Apache soe ser www-data, podedes miralo no punto da wiki indicado anteriormente).
- Creando o cartafol onde se vai gardar o arquivo de configuración
Cambiamos os permisos: sudo chmod -R 550 /var/www/confBD e cambiamos o propietario: sudo chown -R www-data:www-data /var/www/confBD. Nota: O usuario e grupo pode variar dependendo do S.O. En Linux podedes sabelo mirando este enlace da wiki. En Windows o podedes saber neste enlace.
- Agora, calquera páxina que faga uso destes datos terá que facer o seguinte require:
1 <?php 2 3 //error_reporting(0); // Inabilita os erros de Apache se temos activada a directiva display_erros no php.ini 4 5 6 require ('/var/www/confBD/bd.inc.php'); 7 $conex = new mysqli(SERVIDOR,USUARIO,PASSWORD,BD);
O xogo de caracteres
- Debemos ter en conta que unha páxina web está 'aberta' a todo o mundo que se conecte a ela.
- Cada persoa en diferentes países terá diferente xogos de caracteres no que cada carácter está relacionado cun código numérico.
- Se gardamos como dato dentro da base de datos unha cadea cun 'ñ' entre os seus datos, dito carácter estará asociado a un código nun xogo de caracteres. Se o usuario que vai cargar a páxina o carga cun xogo de caracteres diferente non vai poder visualizalo.
- Cando creamos aplicacións en PHP con acceso a base de datos teremos que ter en conta os seguintes xogos de caracteres:
- Xogo de caracteres da base de datos (no noso caso Mysql): É o que se coñece como Charset/Collation.
- Se vos fixades cando creamos a base de datos en Mysql, escollemos o charset (primeira columna) e o collation (segunda columna).
- Como indicamos antes, cando creamos a base de datos o charset/collation indicado foi utf8/utf8_spanish2_ci.
- O charset é como mysql garda internamente os caracteres e os relaciona cun código numérico e o collation indica como comparar e ordenar o texto. Podedes consultar esta blog para obter máis información.
- Xogo de caracteres da páxina HTML.
- Na páxina web indicamos coa etiqueta <meta> o xogo de caracteres para que o navegador web poida visualizalos correctamente.
- No caso que nos ocupa teremos que poñer: <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
- Máis información en w3schools.
- No código PHP ao conectar coa base de datos.
- Cando conectemos coa base de datos teremos que indicarlle que imos utilizar o xogo de caracteres utf8 con esta liña:
1 $conex = new mysqli(SERVIDOR,USUARIO,PASSWORD,BD); 2 $conex->set_charset('utf8');
- E FUNDAMENTAL QUE NOS TRES SITIOS ESTEA POSTO O MESMO XOGO DE CARACTERES.
Creando as táboas en Mysql
- Unha vez temos a base de datos teremos que facer o Modelo EE/R, pasalo ao Modelo Relacional e facer un Proceso de Normalización ata polo menos a forma normal de Boyce-Codd.
- Imos implementar unha base de datos para xestionar a venda de libros de segunda mano.
- O modelo EE/R é o seguinte:
Nota:
- A táboa ESTADOS podería eliminarse e crear un campo estado de tipo enum en Mysql se ditos 'estados' van ser sempre os mesmos e non van modificarse...
- O campo 'imaxe' da táboa EXEMPLARES está nesta táboa e non na táboa LIBROS, xa que a idea é amosar ao comprador unha imaxe do exemplar para amosar o seu estado.
- O modelo relacional impplementando nunha base de datos Mysql é o seguinte:
CREATE TABLE `PHP`.`LIBROS` ( `id_libro` INT NOT NULL AUTO_INCREMENT, `descripcion` VARCHAR(300) NOT NULL, PRIMARY KEY (`id_libro`)); CREATE TABLE `PHP`.`ESTADOS` ( `id_estado` INT NOT NULL AUTO_INCREMENT, `descripcion` VARCHAR(100) NOT NULL, PRIMARY KEY (`id_estado`)); CREATE TABLE `PHP`.`EXEMPLARES` ( `libro_id` INT NOT NULL, `id_exemplar` INT NOT NULL, `imaxe` VARCHAR(100) NULL, `prezo` DECIMAL(6,2) NOT NULL, `estado_id` INT NULL, INDEX `fk_EXEMPLARES_LIBROS_idx` (`libro_id` ASC), INDEX `fk_EXEMPLARES_ESTADOS_idx` (`estado_id` ASC), PRIMARY KEY ( `libro_id`,`examplar_id`), CONSTRAINT `fk_EXEMPLARES_LIBROS` FOREIGN KEY (`libro_id`) REFERENCES `PHP`.`LIBROS` (`id_libro`) ON DELETE NO ACTION ON UPDATE CASCADE, CONSTRAINT `fk_EXEMPLARES_ESTADOS` FOREIGN KEY (`estado_id`) REFERENCES `PHP`.`ESTADOS` (`id_estado`) ON DELETE NO ACTION ON UPDATE CASCADE); CREATE TABLE `PHP`.`AUTORES` ( `id_autor` INT NOT NULL, `apelido` VARCHAR(200) NOT NULL, `nome` VARCHAR(50) NOT NULL, PRIMARY KEY (`id_autor`)); CREATE TABLE `PHP`.`LIBROS_AUTORES` ( `libro_id` INT NOT NULL, `autor_id` INT NOT NULL, PRIMARY KEY (`libro_id`, `autor_id`), INDEX `fk_LIBROS_AUTORES_AUTORES_idx` (`autor_id` ASC), CONSTRAINT `fk_LIBROS_AUTORES_LIBROS` FOREIGN KEY (`libro_id`) REFERENCES `PHP`.`LIBROS` (`id_libro`) ON DELETE NO ACTION ON UPDATE CASCADE, CONSTRAINT `fk_LIBROS_AUTORES_AUTORES` FOREIGN KEY (`autor_id`) REFERENCES `PHP`.`AUTORES` (`id_autor`) ON DELETE NO ACTION ON UPDATE CASCADE);
- Para ter algún dato inicial imos a executar estas ordes:
INSERT INTO `ESTADOS` VALUES (1,'NOVO'),(2,'COMO NOVO'),(3,'DETERIODADO'),(4,'CON ANOTACIÓNS'); INSERT INTO `PHP`.`AUTORES` (`apelido`, `nome`) VALUES ('Drumont', 'Eduardo'); INSERT INTO `PHP`.`LIBROS` (`descripcion`) VALUES ('El caso Dreyfus, expresión del antisemitismo, temas, Gallica, BNF'); INSERT INTO `PHP`.`LIBROS` (`descripcion`) VALUES ('Les amis'); INSERT INTO `PHP`.`EXEMPLARES` (`libro_id`, `id_exemplar`, `imaxe`, `prezo`, `estado_id`) VALUES ('1', '1', 'dreyfus.jpg', '20,52', '2'); INSERT INTO `PHP`.`EXEMPLARES` (`libro_id`, `id_exemplar`, `imaxe`, `prezo`, `estado_id`) VALUES ('1', '2', 'dreyfus.jpg', '15,34', '3'); INSERT INTO `PHP`.`EXEMPLARES` (`libro_id`, `id_exemplar`, `imaxe`, `prezo`, `estado_id`) VALUES ('2', '1', 'amis.jpg', '35,35', '1'); INSERT INTO `PHP`.`EXEMPLARES` (`libro_id`, `id_exemplar`, `imaxe`, `prezo`, `estado_id`) VALUES ('2', '2', 'amis.jpg', '20,25', '4'); INSERT INTO `PHP`.`EXEMPLARES` (`libro_id`, `id_exemplar`, `imaxe`, `prezo`, `estado_id`) VALUES ('2', '3', 'amis.jpg', '25,34', '3');
- Agora faremos o seguinte:
- Crearemos dentro do noso sitio web (normalmente /var/www/html/) un cartafol de nome IMAXES
- Copiamos as imaxes que veñen a continuación a dito cartafol.
- Cambiaremos o propietario coa orde chown -R www-data:www-data IMAXES/
Nome: amis.jpg
Nome: dreyfus.jpg
Regras de nomeado de táboas e columnas
- Aínda que non existen 'regras' únicas sobre como nomear as táboas e campos nos imos seguir as seguintes:
- Nomes de táboas en PLURAL e con MAIÚSCULAS. Desta forma distinguiremos facilmente o nome da táboa e os campos nunha consulta SQL.
- Nomes de campos en minúscula e singular.
- Se o campo é a clave primaria terá de nome: id_nometáboa_en_singular
- Se o campo é unha clave foránea terá de nome: nometáboa_en_singular_id
- Se o nome de campo está formado por varias palabras, estarán separadas por un guión baixo ( _ )
- Non usar til nin caracteres 'raros' como espazos en branco, interrogacións,...
- As claves foráneas irán ao final da lista de columnas da táboa.
Consulta
- Nota: Na cadea de conexión xa indicamos a base de datos á que queríamos conectarnos.
- Se queremos escoller outra diferente teremos que facer uso da función mysqli::select_db.
- Por exemplo:
1 $conex = new mysqli('localhost','user_php','user_php','PHP'); 2 $conex->set_charset('utf8'); 3 4 if (!$mysqli->select_db('OutraBD')){ 5 die('Erro ao cambiar de base de datos'); 6 }
- Para conectarnos primeiro teremos que ter a consulta SQL.
- Indicar que o SQL (Structure Query Language) é a linguaxe utilizada para obter datos dunha base de datos relacional.
- Imos crear unha consulta que nos devolva todos os libros da táboa LIBROS:
- Para non ter as consultas no medio do código PHP das diferentes páxinas, imos definila no arquivo bd.inc.php creado no punto anterior.
define ('CONSULTAR_LIBROS','select id_libro,descripcion from LIBROS order by descripcion');
- Normas nos nomes das constantes:
- Comenzarán cun verbo que vai poder ser: CONSULTAR, INSERIR, MODIFICAR e ELIMINAR
- Seguirá cun guión baixo.
- En caso de consultar os datos dunha única táboa se indicará o nome da táboa. En caso de consultar datos de varias táboas se indicará con varias palabras separadas con guión baixo que indiquen o obxectivo da consulta.
- Funcións para realizar consultas a base de datos e funcións relacionadas:
- mysqli::query: Realiza a consulta
- mysqli_result: En caso de realizar unha consulta de tipo 'select' este obxecto representa o conxunto de resultados obtidos.
- int $mysqli_result->num_rows: Devolve o número de filas devoltas en caso de realizar unha consulta.
- array mysqli_result::fetch_assoc(void): Devolve nun array asociativo unha das filas do resultado da consulta e 'pasa' á fila seguinte. Cando remate e xa non teña máis filas devolve NULL.
- Aplicado ao exemplo que estamos a seguir:
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 ?> 13 14 15 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 16 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 17 <html xmlns="http://www.w3.org/1999/xhtml" lang="es" xml:lang="es"> 18 <head> 19 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 20 <title>Operacións BD</title> 21 </head> 22 23 <body> 24 <?php 25 26 $result=$conex->query(CONSULTAR_LIBROS); 27 if ($result->num_rows>0){ 28 echo "<table border='1'>"; 29 while($row = $result->fetch_assoc()) { 30 echo '<tr>'; 31 printf("<td>%s</td>",$row["descripcion"]); 32 echo '</tr>'; 33 } 34 echo '</table>'; 35 $result->free(); // Liberamos da memoria os recursos 36 } 37 else { 38 echo "Non hai datos que amosar!!!!"; 39 } 40 $conex->close(); // Pechamos a conexión 41 42 ?> 43 </body> 44 </html>
- Resultado:
- Fixarse como neste exemplo, aínda que a consulta devolve o id_libro, como non o necesitamos non o amosamos ao usuario, xa que dito dato é un código interno que utilizamos como clave primaria.
- Imos facer agora unha modificación e amosar os datos nunha combobox (<select> en html), de tal forma que cando o usuario escolla un libro, amose os exemplares do mesmo.
- Neste caso, na combo imos gardar o código do libro xa que cando escollamos un, necesitamos obter dito código para facer outra consulta buscando os exemplares dese libro...
1 <body> 2 <?php 3 4 $result=$conex->query(CONSULTAR_LIBROS); 5 if ($result->num_rows>0){ 6 echo "<select name='lstLibros'>"; 7 echo "<option value='-1'></option>"; 8 while($row = $result->fetch_assoc()) { 9 printf("<option value='%d'>%s</option>",$row["id_libro"],$row["descripcion"]); 10 } 11 echo '</select>'; 12 $result->free(); // Liberamos da memoria os recursos 13 } 14 else { 15 echo "Non hai datos que amosar!!!!"; 16 } 17 $conex->close(); // Pechamos a conexión 18 19 ?> 20 </body>
- Resultado:
- Como vemos no código (liña 7) engadimos unha entrada en branco un valor -1 no seu value, para 'obrigar' a escoller un valor e que por defecto non apareza cun libro seleccionado.
- Dependerá da aplicación, podedes ter que implementar variantes como ter unha entrada que indique 'TODAS' ou facer que por defecto estea seleccionada algunha das entradas...
Consulta enviando parámetros de tipo numérico
Nota: Lembra que no paso de datos temos que ter en conta os posibles 'ataques' que poidan intentar facerse. Repasar o dado na wiki anteriormente.
- Seguindo con exemplo, imos facer que cando o usuario seleccione un libro aparezan os exemplares do mesmo.
- Para iso teremos que:
- Crear a sentencia SQL correspondente enviando un parámetro que vai ser o código do libro seleccionado.
- Obter dito dato. Isto o faremos utilizando un formulario cun método POST.
- Facer que cando o usuario escolla un libro 'active' o formulario e polo tanto provoque o 'submit' do mesmo.
- Manter seleccionado o libro na combo.
Nota: Ao principio ides ter problema de tipo 'non amosa ningún dato'. O primeiro que tedes que descargar é que a consulta SQL estea ben e devolva datos, polo que vos aconsello que fagades un 'echo' de dita consulta e a executedes no MysqlWorkBench para ver que realmente devolve algún resultado.
- Definimos no arquivo bd.inc.php:
- A consulta que vai consultar os exemplares dun libro seleccionado:
- define ('CONSULTAR_EXEMPLARES_POR_LIBRO','select libro_id,id_exemplar,imaxe,prezo,estado_id from EXEMPLARES INNER JOIN LIBROS ON (LIBROS.id_libro=EXEMPLARES.libro_id) where id_libro=%d order by descripcion,estado_id');
- Como vemos imos enviar o código por medio dun parámetro de tipo numérico e utilizando a función sprintf.
- Definimos nunha constante onde se atopan as imaxes relacionados cos libros:
- define ('CARTAFOL_IMAXES_WEB','http://www.meusitio.es/IMAXES/');
- Teredes que cambiar a url pola vosa.
- Para facer que cando se seleccione un elemento do lista se 'active' o formulario, existen múltiples formas, unha delas pode ser:
- echo "<select name='lstLibros' onchange='this.form.submit()'>";
- O código que vai amosar os exemplares do libro seleccionado será o seguinte:
1 <?php 2 // CONSULTAMOS OS EXEMPLARES DUN LIBRO SELECCIONADO 3 if (!empty($_POST['lstLibros']) && filter_var($_POST['lstLibros'],FILTER_VALIDATE_INT) && $_POST['lstLibros']!=-1){ 4 5 $query=sprintf(CONSULTAR_EXEMPLARES_POR_LIBRO,$_POST['lstLibros']); 6 $result=$conex->query($query); 7 if ($result && ($result->num_rows>0)){ 8 echo "<table border='1'>"; 9 echo "<th>Num. Exemplar</th><th>Imaxe</th><th>Prezo</th><th>Estado</th>"; 10 while($row = $result->fetch_assoc()) { 11 echo '<tr>'; 12 printf("<td>%d</td><td><img alt='%s' src='%s' width='42' height='42' /></td><td>%s</td><td>%d</td>",$row["id_exemplar"],$row["imaxe"],CARTAFOL_IMAXES_WEB . $row["imaxe"],$row["prezo"],$row["estado_id"]); 13 echo '</tr>'; 14 } 15 echo '</table>'; 16 $result->free(); // Liberamos da memoria os recursos 17 } 18 else { 19 echo "Non hai datos que amosar!!!!"; 20 } 21 22 } 23 $conex->close(); // Pechamos a conexión 24 25 ?>
- Liña 3: Comprobamos que veñan datos no formulario (que se escollera algún exemplar da lista) e que sexa de tipo numérico. Tamén comprobamos se seleccionamos o elemento baleiro (valor -1 na combo).
- Liña 5: Definimos a consulta a realizar contra a base de datos, utilizando a constante definida e substituíndo o parámetro polo código do libro seleccionado.
- Liñas 7-17: Construímos a táboa para que amose os datos. Fixarse que na imaxe temos que definir o atributo 'alt' para que cumpra o estándar XHTML, polo que enviamos dúas veces o nome do arquivo. No dato que vai no atributo 'src' enviamos o nome do arquivo xunto coa URL onde se atopan as imaxes.
- Liña 23: Pechamos a conexión. Fixarse que esta liña debe aparecer unha vez. Se non teremos que volver a abrir a conexión á base de datos.
- Facemos que se manteña seleccionado o libro:
1 <?php 2 $result=$conex->query(CONSULTAR_LIBROS); 3 if ($result->num_rows>0){ 4 echo "<select name='lstLibros' onchange='this.form.submit()'>"; 5 echo "<option value='-1'></option>"; 6 while($row = $result->fetch_assoc()) { 7 if(isset($_POST['lstLibros']) && $row['id_libro']==$_POST['lstLibros']){ 8 $cadea="selected='selected'"; 9 } 10 else{ 11 $cadea=''; 12 } 13 printf("<option value='%d' %s>%s</option>",$row["id_libro"],$cadea,$row["descripcion"]); 14 } 15 echo '</select>'; 16 $result->free(); // Liberamos da memoria os recursos 17 } 18 else { 19 echo "Non hai datos que amosar!!!!"; 20 } 21 22 ?>
- O código completo sería o seguinte:
Arquivo: bd.inc.php:
1 <?php 2 3 define ('SERVIDOR','localhost'); 4 define ('USUARIO','user_php'); 5 define ('PASSWORD','user_php'); 6 define ('BD','PHP'); 7 8 define ('CARTAFOL_IMAXES_WEB','http://www.meusitio.es/IMAXES/'); 9 10 define ('CONSULTAR_LIBROS','select id_libro,descripcion from LIBROS order by descripcion'); 11 define ('CONSULTAR_EXEMPLARES_POR_LIBRO','select libro_id,id_exemplar,imaxe,prezo,estado_id from EXEMPLARES INNER JOIN LIBROS ON (LIBROS.id_libro=EXEMPLARES.libro_id) where id_libro=%d order by descripcion,estado_id');
Arquivo: Consultar_Libros.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 ?> 13 14 15 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 16 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 17 <html xmlns="http://www.w3.org/1999/xhtml" lang="es" xml:lang="es"> 18 <head> 19 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 20 <title>Operacións BD</title> 21 </head> 22 23 <body> 24 <form action="<?php echo $_SERVER['PHP_SELF'] ?>" method='post'> 25 26 <?php 27 $result=$conex->query(CONSULTAR_LIBROS); 28 if ($result->num_rows>0){ 29 echo "<select name='lstLibros' onchange='this.form.submit()'>"; 30 echo "<option value='-1'></option>"; 31 while($row = $result->fetch_assoc()) { 32 if(isset($_POST['lstLibros']) && $row['id_libro']==$_POST['lstLibros']){ 33 $cadea="selected='selected'"; 34 } 35 else{ 36 $cadea=''; 37 } 38 printf("<option value='%d' %s>%s</option>",$row["id_libro"],$cadea,$row["descripcion"]); 39 } 40 echo '</select>'; 41 $result->free(); // Liberamos da memoria os recursos 42 } 43 else { 44 echo "Non hai datos que amosar!!!!"; 45 } 46 47 ?> 48 </form> 49 50 51 <?php 52 // CONSULTAMOS OS EXEMPLARES DUN LIBRO SELECCIONADO 53 if (!empty($_POST['lstLibros']) && filter_var($_POST['lstLibros'],FILTER_VALIDATE_INT) && $_POST['lstLibros']!=-1){ 54 55 $query=sprintf(CONSULTAR_EXEMPLARES_POR_LIBRO,$_POST['lstLibros']); 56 $result=$conex->query($query); 57 if ($result && ($result->num_rows>0)){ 58 echo "<table border='1'>"; 59 echo "<th>Num. Exemplar</th><th>Imaxe</th><th>Prezo</th><th>Estado</th>"; 60 while($row = $result->fetch_assoc()) { 61 echo '<tr>'; 62 printf("<td>%d</td><td><img alt='%s' src='%s' width='42' height='42' /></td><td>%s</td><td>%d</td>",$row["id_exemplar"],$row["imaxe"],CARTAFOL_IMAXES_WEB . $row["imaxe"],$row["prezo"],$row["estado_id"]); 63 echo '</tr>'; 64 } 65 echo '</table>'; 66 $result->free(); // Liberamos da memoria os recursos 67 } 68 else { 69 echo "Non hai datos que amosar!!!!"; 70 } 71 72 } 73 $conex->close(); // Pechamos a conexión 74 75 ?> 76 77 78 </body> 79 </html>
- Imos realizar unha mellora nos datos que se visualizan.
- Como vemos, aparece o código do estado do libro. O que queremos amosar é a descrición, polo que teremos que facer un Join coa táboa ESTADOS.
Arquivo bd.inc.php:
1 define ('CONSULTAR_EXEMPLARES_POR_LIBRO','select libro_id,id_exemplar,imaxe,prezo,estado_id,ESTADOS.descripcion as desc_estado' 2 . ' from EXEMPLARES INNER JOIN LIBROS ON (LIBROS.id_libro=EXEMPLARES.libro_id)' 3 . ' INNER JOIN ESTADOS ON (ESTADOS.id_estado=EXEMPLARES.estado_id)' 4 . ' where id_libro=%d order by LIBROS.descripcion,desc_estado');
Arquivo: Consultar_Libros.php:
1 .................. 2 3 <?php 4 // CONSULTAMOS OS EXEMPLARES DUN LIBRO SELECCIONADO 5 if (!empty($_POST['lstLibros']) && filter_var($_POST['lstLibros'],FILTER_VALIDATE_INT) && $_POST['lstLibros']!=-1){ 6 7 $query=sprintf(CONSULTAR_EXEMPLARES_POR_LIBRO,$_POST['lstLibros']); 8 $result=$conex->query($query); 9 if ($result && ($result->num_rows>0)){ 10 echo "<table border='1'>"; 11 echo "<th>Num. Exemplar</th><th>Imaxe</th><th>Prezo</th><th>Estado</th>"; 12 while($row = $result->fetch_assoc()) { 13 echo '<tr>'; 14 printf("<td>%d</td><td><img alt='%s' src='%s' width='42' height='42' /></td><td>%s</td><td>%s</td>",$row["id_exemplar"],$row["imaxe"],CARTAFOL_IMAXES_WEB . $row["imaxe"],$row["prezo"],$row["desc_estado"]); 15 echo '</tr>'; 16 } 17 echo '</table>'; 18 $result->free(); // Liberamos da memoria os recursos 19 } 20 else { 21 echo "Non hai datos que amosar!!!!"; 22 } 23 24 } 25 $conex->close(); // Pechamos a conexión 26 27 ?> 28 29 ..................
- Liña 14: Modificamos o tipo de parámetro que pasa de ser numérico (%d) a cadea (%s) e amosamos a descrición do estado (as dúas columnas do select non deben ter o mesmo nome, descrición do libro e descrición do estado).
Consulta enviando parámetros de tipo cadea
- Cando utilicemos datos de tipo cadea, debemos lembrar poñelos entre comillas simples ('dato') na orde SQL.
- Imos a aplicalo ao noso exemplo e imos crear unha páxina no que buscaremos libros en base a un nome do autor. A busca farase utilizando a orde SQL like, que busca patróns de cadea.
- O dato a recoller será unha cadea de texto.
- Nota: Lembra que no paso de datos temos que ter en conta os posibles 'ataques' que poidan intentar facerse. Repasar o dado na wiki anteriormente.
- Mysql incorpora tamén unha función para codificar os caracteres (como espazos en branco, saltos de liña,...Función string mysqli::real_escape_string ( string $escapestr ). Devolve a cadea 'codificada'.
- Por exemplo:
1 $ciudad = "'s Hertogenbosch"; 2 3 /* esta consulta fallará debido a que no escapa $ciudad */ 4 if (!$mysqli->query("INSERT into miCiudad (Name) VALUES ('$ciudad')")) { 5 printf("Error: %s\n", $mysqli->sqlstate); 6 } 7 8 $ciudad = $mysqli->real_escape_string($ciudad); 9 10 /* esta consulta con $ciudad escapada funcionará */ 11 if ($mysqli->query("INSERT into miCiudad (Name) VALUES ('$ciudad')")) { 12 printf("%d fila insertada.\n", $mysqli->affected_rows); 13 }
- Exemplo obtido de php.net
Alta
Baixa
Modificación
Procedementos almacenados
Permisos mínimos
-- Ángel D. Fernández González -- (2016).
