首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >参考:使用MySQL扩展的完美代码示例是什么?

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

Stack Overflow用户
提问于 2011-06-01 16:09:04
回答 5查看 2.7K关注 0票数 60

这是一个创建社区学习资源。我们的目标是拥有好的代码示例,这些代码不会重复复制/粘贴PHP代码中经常出现的可怕错误。我已经要求它成为社区维基。

这不是一个编码竞赛,它不是关于寻找最快或最紧凑的方式来做查询-它是提供一个很好的,可读的参考,特别是对于新手。

每天,都有大量的问题涌入,其中包含使用堆栈溢出上的mysql_*系列函数的非常糟糕的代码片段。虽然通常最好的做法是将这些人引向PDO,但有时这既不可能(例如,继承的遗留软件),也不是一个现实的期望(用户已经在他们的项目中使用它)。

使用mysql_*库的代码的常见问题包括:

值中的

  • SQL注入限制子句和动态表名中的
  • SQL注入
  • 无错误报告(“
  • query
  • error reporting (即,即使将代码放入值输出

中的脚本(XSS)注入中,也始终发生错误

让我们编写一个PHP代码示例,它使用mySQL_* family of functions执行以下操作

失败失败接受两个POST值id (数字)和name (字符串)

  • 对表tablename执行更新查询,更改ID为
  • 的行中的name列,正常退出,但仅在生产模式下显示详细的错误。更新就足够了;或者使用choosing
  • Output的方法来更新消息"$name trigger_error()“。

没有显示出上面列出的任何弱点吗?

它应该是尽可能简单的。理想情况下,它不包含任何函数或类。我们的目标不是创建一个copy/pasteable库,而是向展示使数据库查询安全所需的最低限度。

好的评论会被加分。

目标是使这个问题成为用户在遇到具有糟糕代码(即使它根本不是问题的焦点)的提问者时可以链接到的资源,或者遇到失败的查询而不知道如何修复它。

先发制人的讨论:

是的,将这些问题提交给PDO往往更可取。当这是一种选择时,我们应该这样做。然而,这并不总是可能的-有时,提问者正在处理遗留代码,或者已经在这个库中走了很长的路,现在不太可能改变它。此外,如果使用得当,mysql_*系列函数是完全安全的。所以请不要在这里回答“使用PDO”。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2011-06-01 17:10:10

我对它的尝试。尽量保持简单,同时仍然保持一些现实世界的便利性。

处理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);
}
票数 12
EN

Stack Overflow用户

发布于 2011-06-01 16:39:10

我决定抢先一步做点什么。这是一个开始的东西。在出错时引发异常。

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();
}
票数 7
EN

Stack Overflow用户

发布于 2011-06-01 16:55:21

/**
 * 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-attacks

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6198104

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档