variable todas pasar las juntos insertar imprimir formulario etiquetas ejemplos dentro combinar codigo php mysql security sql-injection

todas - pasar variable php a html



Referencia: ¿Qué es un ejemplo de código perfecto con la extensión MySQL? (5)

Decidí saltar el arma y solo poner algo. Es algo para empezar. Lanza una excepción por error.

function executeQuery($query, $args) { $cleaned = array_map(''mysql_real_escape_string'', $args); if($result = mysql_query(vsprintf($query, $cleaned))) { return $result; } else { throw new Exception(''MySQL Query Error: '' . mysql_error()); } } function updateTablenameName($id, $name) { $query = "UPDATE tablename SET name = ''%s'' WHERE id = %d"; return executeQuery($query, array($name, $id)); } try { updateTablenameName($_POST[''id''], $_POST[''name'']); } catch(Exception $e) { echo $e->getMessage(); exit(); }

Esto es para crear un recurso de aprendizaje comunitario . El objetivo es tener ejemplos de buenos códigos que no repitan los terribles errores que a menudo se encuentran en el código PHP copiado / pegado. He solicitado que se haga Wiki de la comunidad.

Esto no pretende ser un concurso de codificación. No se trata de encontrar la forma más rápida o más compacta de hacer una consulta: es proporcionar una buena referencia legible, especialmente para los novatos.

Todos los días, hay una gran afluencia de preguntas con fragmentos de código realmente malos usando la familia de funciones mysql_* en Stack Overflow. Si bien generalmente es mejor orientar a esas personas hacia la DOP, a veces no es posible (por ejemplo, un software heredado heredado) ni una expectativa realista (los usuarios ya lo están utilizando en su proyecto).

Los problemas comunes con el código que usa la biblioteca mysql_* incluyen:

  • Inyección SQL en valores
  • Inyección SQL en cláusulas LIMIT y nombres dinámicos de tablas
  • No hay informes de errores ("¿Por qué esta consulta no funciona?")
  • Informes de errores rotos (es decir, los errores siempre ocurren incluso cuando el código se pone en producción)
  • Inyección de scripts entre sitios (XSS) en salida de valor

Vamos a escribir un ejemplo de código PHP que haga lo siguiente usando la familia de funciones mySQL_ * :

  • Acepte dos valores POST, id (numérico) y name (una cadena)
  • Realice una consulta de ACTUALIZACIÓN sobre una tabla nombre de tablename , cambiando la columna de name en la fila con la ID id
  • En caso de falla, salga graciosamente, pero muestre el error detallado solo en modo de producción. trigger_error() será suficiente; alternativamente use un método de su elección
  • Envía el mensaje " $name updated".

Y no muestra ninguna de las debilidades listadas arriba.

Debe ser lo más simple posible . Lo ideal es que no contenga ninguna función o clase. El objetivo no es crear una biblioteca de copiar / pegar, sino mostrar el mínimo de lo que se debe hacer para garantizar la seguridad de la consulta de la base de datos.

Puntos de bonificación por buenos comentarios.

El objetivo es hacer de esta pregunta un recurso al que un usuario puede vincular cuando se encuentra con un preguntador que tiene un código incorrecto (aunque no sea el centro de la pregunta) o se enfrenta a una consulta que falla y no lo hace. saber cómo solucionarlo

Para adelantarse a la discusión de PDO:

Sí, a menudo será preferible dirigir a las personas que escriben esas preguntas a PDO. Cuando es una opción, debemos hacerlo. Sin embargo, no siempre es posible; a veces, la persona que pregunta está trabajando en el código heredado, o ya ha recorrido un largo camino con esta biblioteca, y es poco probable que la cambie ahora. Además, la familia de funciones mysql_* es perfectamente segura si se usa correctamente. Así que no hay respuestas "use PDO" aquí por favor.


Mi puñalada. Intenté mantenerlo lo más simple posible, manteniendo al mismo tiempo algunas comodidades del mundo real.

Maneja unicode y usa comparación suelta para facilitar la lectura. Se bueno ;-)

<?php header(''Content-type: text/html; charset=utf-8''); error_reporting(E_ALL | E_STRICT); ini_set(''display_errors'', 1); // display_errors can be changed to 0 in production mode to // suppress PHP''s error messages /* Can be used for testing $_POST[''id''] = 1; $_POST[''name''] = ''Markus''; */ $config = array( ''host'' => ''127.0.0.1'', ''user'' => ''my_user'', ''pass'' => ''my_pass'', ''db'' => ''my_database'' ); # Connect and disable mysql error output $connection = @mysql_connect($config[''host''], $config[''user''], $config[''pass'']); if (!$connection) { trigger_error(''Unable to connect to database: '' . mysql_error(), E_USER_ERROR); } if (!mysql_select_db($config[''db''])) { trigger_error(''Unable to select db: '' . mysql_error(), E_USER_ERROR); } if (!mysql_set_charset(''utf8'')) { trigger_error(''Unable to set charset for db connection: '' . mysql_error(), E_USER_ERROR); } $result = mysql_query( ''UPDATE tablename SET name = "'' . mysql_real_escape_string($_POST[''name'']) . ''" WHERE id = "'' . mysql_real_escape_string($_POST[''id'']) . ''"'' ); if ($result) { echo htmlentities($_POST[''name''], ENT_COMPAT, ''utf-8'') . '' updated.''; } else { trigger_error(''Unable to update db: '' . mysql_error(), E_USER_ERROR); }


Parece que mi otra respuesta se perdió el objetivo de la pregunta.
(este tampoco cumple algunos requisitos, pero como se puede ver, no se puede lograr una solución segura sin implementar una función para procesar marcadores de posición, que son la piedra angular de las consultas seguras)

Entonces, aquí hay otro intento de publicar una solución concisa para hacer que las consultas de mysql sean seguras ya la vez prácticas.

Una función que escribí hace mucho tiempo y que me sirvió bien hasta que pasé a la solución corporativa estándar basada en OOP.
Había 2 objetivos a perseguir: seguridad y facilidad de uso .

Primero se logró implementando marcadores de posición.
Segundo logrado mediante la implementación de marcadores de posición y diferentes tipos de resultados.

La función seguramente no es la ideal. Algunos inconvenientes son:

  • no se deben colocar % caracteres en la consulta directamente ya que está utilizando la sintaxis de printf.
  • no hay conexiones múltiples compatibles.
  • sin marcador de posición para los identificadores (así como muchos otros marcadores de posición útiles).
  • de nuevo, ¡ sin marcador de posición identificador! . "ORDER BY $field" debe manejarse de forma manual.
  • por supuesto, una implementación de OOP sería mucho más flexible, con métodos bien definidos distintos en lugar de feos "modo" variable, así como otros métodos necesarios.

Sin embargo, es bueno, seguro y conciso, no es necesario instalar una biblioteca completa.

function dbget() { /* usage: dbget($mode, $query, $param1, $param2,...); $mode - "dimension" of result: 0 - resource 1 - scalar 2 - row 3 - array of rows */ $args = func_get_args(); if (count($args) < 2) { trigger_error("dbget: too few arguments"); return false; } $mode = array_shift($args); $query = array_shift($args); $query = str_replace("%s","''%s''",$query); foreach ($args as $key => $val) { $args[$key] = mysql_real_escape_string($val); } $query = vsprintf($query, $args); if (!$query) return false; $res = mysql_query($query); if (!$res) { trigger_error("dbget: ".mysql_error()." in ".$query); return false; } if ($mode === 0) return $res; if ($mode === 1) { if ($row = mysql_fetch_row($res)) return $row[0]; else return NULL; } $a = array(); if ($mode === 2) { if ($row = mysql_fetch_assoc($res)) return $row; } if ($mode === 3) { while($row = mysql_fetch_assoc($res)) $a[]=$row; } return $a; } ?>

ejemplos de uso

$name = dbget(1,"SELECT name FROM users WHERE id=%d",$_GET[''id'']); $news = dbget(3,"SELECT * FROM news WHERE title LIKE %s LIMIT %d,%d", "%$_GET[search]%",$start,$per_page);

Como puede verse a partir de los ejemplos anteriores, la principal diferencia de todos los códigos publicados en , las rutinas de seguridad y recuperación de datos están encapsuladas en el código de función. Por lo tanto, no hay encuadernación manual, escapado / cotización o lanzamiento, así como no hay recuperación manual de datos.

combinado con otra función auxiliar

function dbSet($fields,$source=array()) { $set = ''''; if (!$source) $source = &$_POST; foreach ($fields as $field) { if (isset($source[$field])) { $set.="`$field`=''".mysql_real_escape_string($source[$field])."'', "; } } return substr($set, 0, -2); }

usado así

$fields = explode(" ","name surname lastname address zip phone regdate"); $_POST[''regdate''] = $_POST[''y'']."-".$_POST[''m'']."-".$_POST[''d'']; $sql = "UPDATE $table SET ".dbSet($fields).", stamp=NOW() WHERE id=%d"; $res = dbget(0,$sql, $_POST[''id'']); if (!$res) { _503;//calling generic 503 error function }

puede cubrir casi todas las necesidades, incluido el caso de ejemplo del PO.


<? mysql_connect(); mysql_select_db("new"); $table = "test"; if($_SERVER[''REQUEST_METHOD'']==''POST'') { $name = mysql_real_escape_string($_POST[''name'']); if ($id = intval($_POST[''id''])) { $query="UPDATE $table SET name=''$name'' WHERE id=$id"; } else { $query="INSERT INTO $table SET name=''$name''"; } mysql_query($query) or trigger_error(mysql_error()." in ".$query); header("Location: http://".$_SERVER[''HTTP_HOST''].$_SERVER[''PHP_SELF'']); exit; } if (!isset($_GET[''id''])) { $LIST=array(); $query="SELECT * FROM $table"; $res=mysql_query($query); while($row=mysql_fetch_assoc($res)) $LIST[]=$row; include ''list.php''; } else { if ($id=intval($_GET[''id''])) { $query="SELECT * FROM $table WHERE id=$id"; $res=mysql_query($query); $row=mysql_fetch_assoc($res); foreach ($row as $k => $v) $row[$k]=htmlspecialchars($v); } else { $row[''name'']=''''; $row[''id'']=0; } include ''form.php''; } ?>

form.php

<? include ''tpl_top.php'' ?> <form method="POST"> <input type="text" name="name" value="<?=$row[''name'']?>"><br> <input type="hidden" name="id" value="<?=$row[''id'']?>"> <input type="submit"><br> <a href="?">Return to the list</a> </form> <? include ''tpl_bottom.php'' ?>

list.php

<? include ''tpl_top.php'' ?> <a href="?id=0">Add item</a> <? foreach ($LIST as $row): ?> <li><a href="?id=<?=$row[''id'']?>"><?=$row[''name'']?></a> <? endforeach ?> <? include ''tpl_bottom.php'' ?>


/** * Rule #0: never trust users input! */ //sanitize integer value $id = intval($_GET[''id'']); //sanitize string value; $name = mysql_real_escape_string($_POST[''name'']); //1. using `dbname`. is better than using mysql_select_db() //2. names of tables and columns should be quoted by "`" symbol //3. each variable should be sanitized (even in LIMIT clause) $q = mysql_query("UPDATE `dbname`.`tablename` SET `name`=''".$name."'' WHERE `id`=''".$id."'' LIMIT 0,1 "); if ($q===false) { trigger_error(''Error in query: ''.mysql_error(), E_USER_WARNING); } else { //be careful! $name contains user''s data, remember Rule #0 //always use htmlspecialchars() to sanitize user''s data in output print htmlspecialchars($name).'' updated''; } ######################################################################## //Example, how easily is to use set_error_handler() and trigger_error() //to control error reporting in production and dev-code //Do NOT use error_reporting(0) or error_reporting(~E_ALL) - each error //should be fixed, not muted function err_handler($errno, $errstr, $errfile, $errline) { $hanle_errors_print = E_ALL & ~E_NOTICE; //if we want to print this type of errors (other types we can just write in log-file) if ($errno & $hanle_errors_print) { //$errstr can contain user''s data, so... Rule #0 print PHP_EOL.''Error [''.$errno.''] in file ''.$errfile.'' in line ''.$errline .'': ''.htmlspecialchars($errstr).PHP_EOL; } //here you can write error into log-file } set_error_handler(''err_handler'', E_ALL & ~E_NOTICE & E_USER_NOTICE & ~E_STRICT & ~E_DEPRECATED);

Y alguna explicación de los comentarios:

//1. using `dbname`. is better than using mysql_select_db()

Al usar mysql_select_db puede crear errores, y no será tan fácil encontrarlos y corregirlos.
Por ejemplo, en algunas secuencias de comandos configurará db1 como base de datos, pero en alguna función necesita establecer db2 como base de datos.
Después de llamar a esta función, la base de datos cambiará, y todas las consultas siguientes en el script se romperán o romperán algunos datos en la base de datos incorrecta (si los nombres de tablas y columnas coincidirán).

//2. names of tables and columns should be quoted by "`" symbol

Algunos nombres de columnas también pueden ser palabras clave SQL, y usar el símbolo " ` "ayudará con eso.
Además, todos los valores de cadena, insertados para consultar, deben ser citados por '' símbolo.

//always use htmlspecialchars() to sanitize user''s data in output
Te ayudará a prevenir XSS-attacks .