参考:使用MySQL扩展的完美代码示例是什么?

|                                                                                                                       
已邀请:
        我的刺。试图使其尽可能简单,同时仍保留一些实际的便利。 处理unicode并使用松散比较以提高可读性。对人好点 ;-)
<?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);
}
    
        我决定跳开枪,放些东西。首先要开始。在错误上引发异常。
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();
}
    
        
/**
 * 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);
和一些注释的解释:
//1. using `dbname`. is better than using mysql_select_db()
使用mysql_select_db可以创建错误,查找和修复错误并非易事。 例如,在某些脚本中,您将db1设置为数据库,但是在某些功能中,您需要将db2设置为数据库。 调用此函数后,将切换数据库,并且脚本中的所有后续查询将被破坏,或者将破坏错误数据库中的某些数据(如果表和列的名称重合)。
//2. names of tables and columns should be quoted by \"`\" symbol 
列的某些名称也可以是SQL关键字,使用\“`\”符号将对此有所帮助。 同样,插入查询的所有字符串值都应用\'符号引起来。
//always use htmlspecialchars() to sanitize user\'s data in output
这将帮助您防止XSS攻击。     
        
<?  
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\' ?>
    
        看来我的其他答案错过了问题的目的。 (这也不满足某些要求,但是可以看出,如果不实现处理占位符的功能,这是安全查询的基础,那么就无法实现安全的解决方案) 因此,这是发布简洁解决方案以使mysql查询安全又方便的另一种尝试。 我很久以前写的一个函数,在我转向基于OOP的企业标准解决方案之前一直很好用。 有两个目标要追求:安全性和易用性。 第一个通过实现占位符来实现。 第二个是通过实现占位符和不同的结果类型来实现的。 该功能肯定不理想。一些缺点是: 使用printf语法时,不必直接在查询中放置任何“ 9”个字符。 不支持多个连接。 没有标识符的占位符(以及许多其他方便的占位符)。 再次,没有标识符占位符!。
\"ORDER BY $field\"
箱必须手动处理! 当然,OOP实现将更加灵活,它具有简洁的独特方法,而不是丑陋的“ mode”变量以及其他必要的方法。 但是,它很好,安全且简洁,无需安装整个库。
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;
}
?>
使用范例
$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);
从以上示例可以看出,与Stackoverflow中发布的所有代码的主要区别在于,安全代码和数据检索例程都封装在功能代码中。因此,没有手动绑定,转义/引用或强制转换,也没有手动数据检索。 结合其他辅助功能
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); 
}
这样使用
$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
}
它可以满足几乎所有需求,包括OP中的示例案例。     

要回复问题请先登录注册