2

Mediante este código PHP obtengo el id numérico del identificador del producto obteniendo de la url producto/pintura/ el siguiente resultado 4

  if (isset($_GET['id'])){
    $id = $_GET['id'];
    $sql = "SELECT * FROM productos WHERE url='".$id."'";
    $result = mysqli_query($con, $sql);

    if(mysqli_num_rows($result) > 0){
        while ($row = mysqli_fetch_array($result)) {
            $id = $row['id_productos'];
        }
    }
  }

Si a una consulta le añado una function dato(){} Ejemplo:

function dato(){
  $get_imagenes = "SELECT * FROM imagenes WHERE id_imagen='".$id."'"; //Error 24
  $run_imagenes = mysqli_query($con, $get_imagenes); //Error 25
  if(mysqli_num_rows($run_imagenes) >0){ //Error 26
    while ($row_imagenes = mysqli_fetch_array($run_imagenes)) {
        echo '<div>'.$row_imagenes['multimedia'].'<div>';
  }
 }
}

<?php dato();?>

Me muestra los siguientes mensajes de errores


Notice: Undefined variable: id in C:\xampp\htdocs\imagenes\detalle.php on line 24

Notice: Undefined variable: con in C:\xampp\htdocs\imagenes\detalle.php on line 25

Warning: mysqli_query() expects parameter 1 to be mysqli, null given in C:\xampp\htdocs\imagenes\detalles.php on line 25

Warning: mysqli_num_rows() expects parameter 1 to be mysqli_result, null given in C:\xampp\htdocs\imagenes\detalles.php on line 26

Sí le quito la function a la consulta, la consulta se ejecuta sin ningún error.

Al crear una function a la consulta esto hace como una barrera, evita que el valor del $id llegue a la consulta de la function

¿Cómo puedo crear un identificador global, mediante una function obteniendo el id de la Url para así poder añadir a mis consultas con function?

function IdGlobal(){}

Para ende así evitar que mis consultas con fucntion muestre los mensajes de errores.

Josues
  • 177
  • 1
  • 3
  • 13
  • Las variables globales son en general una mala práctica. Creo que lo que quieres hacer se resolvería: 1. Agregando parámetros a tu función: `function dato($id, $con){...` 2. Cuando llames la función le pasas los parámetros: `dato($id, $con);` De ese modo, `$id` y `$con` se encontrarán dentro del ámbito de la función y te evitas el uso de globales. Vistos los mensajes de error, tienes más problemas en tu código que tendrás que resolver. – A. Cedano Aug 26 '17 at 03:42
  • @A.Cedano Es exactamente lo indicado, **Dudas** ¿porque las variables globales son una mala práctica? Yo se que está duda sale del tema de mi pregunta, también es una mala practica utilizar `global $con;` dentro de la `function` sobre los errores amigo, los errores sólo se muestra al utilizar la `function` en mis consulta pero si quito la `function` los errores ya no se muestran y se ejecuta correctamente. – Josues Aug 26 '17 at 04:06
  • @A.Cedano Amigo podrías crear tu respuesta con la solución, adicional a ello como recomendaciones ya sea de seguridad podrías explicar porque no el uso de variables globales. El uso de `function` ayuda mucho cuando existe consulta de un mismo producto con el identificador `4` enlazadas con varias tablas adicionales ejemplo de producto con el id `4` enlazadas a otras tablas se muestra de la tabla imágenes todas las imágenes que estén identificados con producto del id 4 y así otros datos de otras tablas, o existirá algún otro método más correcto. – Josues Aug 26 '17 at 04:16
  • @A.Cedano Disculpa si mi comentario sobre sale de mi pregunta, gracias amigo :) ¡Saludos! – Josues Aug 26 '17 at 04:17

2 Answers2

2

Las variables globales son en general una mala práctica. Sobre el por qué, puedes consultar: ¿Por qué es considerado una mala práctica utilizar variables globales?, hay varias respuestas interesantes en esa pregunta.

Creo que lo que quieres hacer se resolvería:

  1. Agregando parámetros a tu función:

    function dato($id, $con){... 
    
       // Código
    }
    
  2. Cuando llames la función le pasas los parámetros:

    dato($id, $con); 
    

De ese modo, $id y $con se encontrarán dentro del ámbito de la función y te evitas el uso de globales.

Vistos los mensajes de error, tienes más problemas en tu código que tendrás que resolver.

En cuanto a la seguridad, evita pasar consultas a la base de datos así:

$sql = "SELECT * FROM productos WHERE url='".$id."'";

ya que puedes ser víctima de la Inyección SQL.

Para evitarlo:

a. Escribe una consultas preparadas, en las cuales, se sustituyen los datos externos por signos de interrogación

b. Pasas los datos aparte

c. Ejecutas

d. Obtienes los resultados

   // a
   $sql = "SELECT * FROM productos WHERE url= ? ";
   $stmt=$mysqli->prepare($sql);

   // b
   $stmt->bind_param("i", $id);

   // c
   $stmt->execute();

   // d Obtener y leer los datos usando los métodos disponibles en MySQLi

Aquí tienes un ejemplo completo de consulta preparada usando MySQLi.

A. Cedano
  • 86,578
  • 19
  • 122
  • 221
  • La respuesta esta bien, solo añadir que para este caso concreto, si el `$id` es un entero (que es lo mas probable) lo mas óptimo sería forzar a int, **$id = (int) $_GET['id'];** y realizar la consulta directa en lugar de usar preparadas ya que con consultas tipo SELECT las consultas preparadas son menos eficientes. – Xerif Aug 26 '17 at 07:40
  • @Xerif Amigo podrías crear una respuesta a mi pregunta aclarando lo índicas a pesar de existir una respuesta a mi pregunta lo comentado sería como un refuerzo... Seguro mucho +1. Explícame porque sería menos eficiente, sobre lo que indicas si es un número entero en el detallé de cada producto desde la Url obtengo el Id del producto, mediante aquello nuestro referencias desde otras tablas enlazadas del mismo producto como la tabla actual del producto. – Josues Aug 26 '17 at 09:54
  • 1
    @Xerif me sorprende que afirmes alto que es falso, confuso y peligroso. ¿De dónde sacas que cuando se trata de enteros las consultas preparadas son menos eficientes y que conviene en esos casos crear la consulta directamente? Si tú recoges en un formulario el valor `id` y lo pasas directamente podrías tener inyección igual, sólo con que alguien escriba: `1; DELETE FROM productos;` – A. Cedano Aug 26 '17 at 15:24
  • @A.Cedano Disculpa la curiosidad en el ejemplo de sentencias preparadas cual de estás dos `$mysqli` $ `$stmt` variables tiene la conexión de la base de datos. – Josues Aug 26 '17 at 16:18
  • @A.Cedano Disculpa ya observe el ejemplo :) $mysqli tiene la conexión. – Josues Aug 26 '17 at 16:19
  • 1
    Correcto @Josues , el objeto conexión se almacena en `$mysqli`, mientras que `$stmt` sirve para verificar el estado de la consulta preparada y pasarle los demás datos a dicha consulta. – A. Cedano Aug 26 '17 at 16:22
  • @A. Cedano creo que no me entendiste. Para consultas **SELECT** repito **SELECT** las consultas preparadas son más lentas solo tienes que leer la documentación de mysql o php. ¿Comprobaste qué resultado da esto que me dices cuando lo **conviertes/fuerzas** a **int**? `$user = (int) "1; DELETE FROM productos;"` ¿ahora me explicas como va hacer esto inyección y más en el contexto del op? – Xerif Aug 26 '17 at 20:24
  • @Xerif creo que te confundes con respecto a lo que dice el Manual al respecto. Lo que se dice es que la sentencia preparada ocupa más recursos que una sentencia no preparada cuando la 1ª se ejecuta **sólo una vez**. Luego pone un ejemplo de consulta del tipo `SELECT` en la cual no intervienen datos desde el exterior y **ese es el principal motivo** por el cual el ejemplo del manual **en ese caso** no usa sentencias preparadas. Si la consulta, del tipo que sea, se ejecuta más de una vez, es más eficaz usar consultas preparadas. Y el segundo punto por el cual usarla es por la **seguridad**. – A. Cedano Aug 27 '17 at 03:47
  • Si tú conviertes el dato a `int` por ti mismo, @Xerif estás re-inventando la rueda y renunciando a la seguridad y, en muchos casos a la eficacia: _Las variables vinculadas son enviadas desde la consulta al servidor **por separado**, por lo que no se puede interferir. El servidor usa estos valores directamente en el momento de la ejecución. Los parámetros vinculados no necesitan ser escapados porque nunca son sustituidos directamente dentro del string de consulta. Se puede proporcionar una sugerencia al servidor para el tipo de variable vinculada, para crear una **conversión apropiada**._ – A. Cedano Aug 27 '17 at 03:52
  • No tiene nada que ver que la sentencias tenga o no parametros (en el manual en ninguno de los ejemplos se utilizan datos externos), aqui lo que prima es si se vas a ejecutar mas de una vez la sentencia y en el caso del OP se ejecuta una sola vez. Las sentencias preparadas requieren minimo 2 viajes de ida y vuleta, mientras que las directas solo 1, esto las hace mas eficientes. **re-inventando la rueda y renunciando a la seguridad** ¿desde cuando sanitizar los datos es reinventar la rueda? ¿y desde cuando esto te hace renunciar a la seguridad y en muchos caso a la eficacia? – Xerif Aug 27 '17 at 10:31
  • No comparto tu criterio @Xerif , pues lo que que prima es la **seguridad**. En ese sentido, lo recomendado a todas luces es el uso de sentencias preparadas, como bien lo explica el [Manual](http://php.net/manual/es/mysqli.quickstart.prepared-statements.php): _las sentencias preparadas son sencillamente una estrategia más conveniente y menos propensa a errores para este elemetno de seguridad de bases de datos._ La parte en cursiva de mi anterior comentario está tomada también del Manual. Propones re-inventar la rueda cuando hablas de convertir a `int` el dato, ya la sentencia preparada lo hace. – A. Cedano Aug 28 '17 at 00:02
  • Del mismo enlace que me envias: A veces, tal separación es considerada como la única característica de seguridad para evitar inyecciones SQL, **pero se puede alcanzar el mismo grado de seguridad con sentencias no preparadas, si todos los valores están formateados correctamente**. Debería observarse que el formateo correcto no es lo mismo que usar escapes, y que involucra más lógica que simplemente usar escapes... **No reinvento nada** piensa que esto ha existido mucho antes que las preparadas y sigue siendo una forma tan válida como cualquier otra. @A. Cedano – Xerif Aug 28 '17 at 08:09
0

Un ejemplo de como obtener el valor del $id es utilizar una de las palabras reservadas de PHP con global

Le he añadido un valor al $id y con global obtenemos el valor globalmente dentro de la function añadimos de la siguiente manera:

global $id;

Ejemplo:

$id = 1;

function dato(){
  global $id; //si comentas está linea, no funcionara
  echo '<div>'.$id.'<div>';
}

 echo dato();

Cómo resultado obtendremos: 1

Puedes probar el funcionamiento aquí

Otto
  • 632
  • 5
  • 22
  • 48