参考:什么是使用MySQL扩展的完美代码示例?
这是为了创建一个社区学习资源 。 我们的目标是要有好的代码示例,它们不会重复在复制/粘贴的PHP代码中经常发现的可怕错误。 我已经要求它成为社区Wiki。
这并不意味着编码比赛。 这不是要找到最快或最简单的方式来进行查询,而是为新手提供一个很好的,可读的参考。
每天,使用Stack Overflow上的mysql_*
系列函数都会产生大量问题,并带有非常糟糕的代码片段。 尽管通常最好将这些人引导到PDO,但有时候这是不可能的(例如继承遗留软件),也不是现实的期望(用户已经在他们的项目中使用它)。
使用mysql_*
库的代码的常见问题包括:
我们来编写一个PHP代码示例,它使用mySQL_ *系列函数执行以下操作:
id
(数字)和name
(字符串) tablename
执行UPDATE查询,使用ID id
更改行中的name
列 trigger_error()
就足够了; 或者使用您选择的方法 $name
updated”。 并没有显示上面列出的任何弱点。
它应该尽可能简单 。 它理想情况下不包含任何函数或类。 目标不是创建复制/可粘贴的库,而是要显示为确保数据库查询安全所需完成的工作。
奖励积分以获得好评。
目标是让这个问题成为一个资源,用户在遇到问题提问者时可以链接到一个代码错误的代码(尽管它根本不是问题的焦点),或者遇到失败的查询并且不会知道如何解决它。
为了抢先进行PDO讨论:
是的,最好指示将这些问题写入PDO的人员。 当它是一种选择时,我们应该这样做。 然而,这并不总是可行的 - 有时候,问题提供者正在处理遗留代码,或者已经对这个库有很长的路要走,现在不太可能改变它。 另外,如果正确使用, mysql_*
系列函数是完全安全的。 所以请不要在这里使用PDO。
我刺伤它。 试图尽可能保持简单,同时仍然保持一些现实世界的便利。
处理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攻击。
上一篇: Reference: What is a perfect code sample using the MySQL extension?