如何解决参考:使用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,-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中的示例案例。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。