用引号包围字符串

9

PHP中是否有一个函数可以给字符串添加引号?

例如"'".str."'"

这是为了在SQL查询中使用varchar。我进行了一些搜索,但没有结果...

我正在执行以下操作:

$id = "NULL";
$company_name = $_POST['company_name'];         
$country = $_POST['country'];
$chat_language = $_POST['chat_language'];
$contact_firstname = $_POST['contact_firstname'];
$contact_lastname = $_POST['contact_lastname'];
$email = $_POST['email'];
$tel_fix = $_POST['tel_fix'];
$tel_mob = $_POST['tel_mob'];       
$address = $_POST['address'];       
$rating = $_POST['rating'];

$company_name = "'".mysql_real_escape_string(stripslashes($company_name))."'";
$country = "'".mysql_real_escape_string(stripslashes($country))."'";
$chat_language = "'".mysql_real_escape_string(stripslashes($chat_language))."'";
$contact_firstname = "'".mysql_real_escape_string(stripslashes($contact_firstname))."'";
$contact_lastname = "'".mysql_real_escape_string(stripslashes($contact_lastname))."'";
$email = "'".mysql_real_escape_string(stripslashes($email))."'";
$tel_fix = "'".mysql_real_escape_string(stripslashes($tel_fix))."'";
$tel_mob = "'".mysql_real_escape_string(stripslashes($tel_mob))."'";
$address = "'".mysql_real_escape_string(stripslashes($address))."'";
$rating = mysql_real_escape_string(stripslashes($rating));

$array = array($id, $company_name, $country, $chat_language, $contact_firstname, 
$contact_lastname, $email, $tel_fix, $tel_mob, $address, $rating);
$values = implode(", ", $array);

$query = "insert into COMPANIES values(".$values.");";

4
通用提示:始终为插入值的每个列命名,仅使用"insert into COMPANIES values(".$values.")"将导致您的查询在更改表结构、以错误顺序放置参数或未放置足够参数时中断。 - chelmertz
1
这是一个关于PDO的绝佳资源:http://www.kitebird.com/articles/php-pdo.html。我同意其他帖子中提到的,预处理语句在所有方面都是组合查询的一种更优越的方式。 - JAL
1
不要在没有检查魔术引号 gpc 设置的情况下使用 stripslashes()。你可以很容易地将其包装在自定义的 get_string() 函数中。 - BalusC
6个回答

11

不要直接将值插入查询中,而是使用预处理语句和参数,这样就不会受到SQL注入的影响。

$query = $db->prepare('SELECT name,location FROM events WHERE date >= ?');
$query->execute(array($startDate));

$insertContact = $db->prepare('INSERT INTO companies (company_name, country, ...) VALUES (?, ?, ...)');
$insertContact->execute(array('SMERSH', 'USSR', ...));

创建一个PDO对象(也连接到数据库,因此是mysql_connect的对应项)很简单:
$db = new PDO('mysql:host=localhost;dbname=db', 'user', 'passwd');

你不应该在每个需要数据库连接的脚本中都散布这些代码。首先,这样做会增加安全风险。其次,你的代码容易出现拼写错误。解决方案是创建一个函数或方法来设置数据库连接。例如:

function localDBconnect($dbName='...') {
    static $db = array();
    if (is_null($db[$dbName])) {
        $db[$dbName] = new PDO("mysql:host=localhost;dbname=$dbName", 'user', 'passwd');
        $db[$dbName]->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    }
    return $db[$dbName];
}

如果你使用的是超过两三个元素的数组,应该使用循环或数组函数而不是一长串类似语句,就像示例代码中所做的那样。例如,大多数示例可以替换为:
$array = array();
foreach ($_POST as $key => $val) {
    $array[$key] = "'" . mysql_real_escape_string(stripslashes($val)) . "'";
}

这里是一个更全面的创建插入查询的示例。它还远未准备好用于生产,但它阐明了基础知识。

$db = localDBconnect();

// map input fields to table fields
$fields = array(
  'company' => 'company_name',
  'country' => 'country',
  'lang' => 'chat_language',
  'fname' => 'contact_firstname',
  'lname' => 'contact_lastname',
  'email' => 'email',
  'land' => 'tel_fix',
  'mobile' => 'tel_mob',
  'addr' => 'address',
  'rating' => 'rating',
);
if ($missing = array_diff_key($fields, $_POST)) {
    // Form is missing some fields, or request doesn't come from the form.
    ...
} else {
    $registration = array_intersect_key($_POST, $fields);

    $stmt = 'INSERT INTO `dbname`.`Companies` (`' 
        . implode('`, `', $fields) . '`) VALUES (' 
        . implode(', ', array_fill(0, count($registration), '?')) . ')';
    try {
        $query = $db->prepare($stmt);
        $query->execute(array_values($registration));
    } catch (PDOException $exc) {
        // log an 
        error_log($exc);
        echo "An error occurred. It's been logged, and we'll look into it.";
    }
}

为了使其具备生产就绪能力,代码应该重构为函数或类,将与数据库有关的所有内容隐藏起来,这称为“数据访问层”。使用$fields展示了一种编写适用于任意表结构的代码的方法。查找“模型-视图-控制器”架构以获取更多信息。此外,应进行验证。

你如何创建 $db 对象?我尝试了,但出现了“致命错误:在……上调用成员函数 prepare()”。 - serhio
你有点击帖子中的链接吗?那个蓝色文字写着“预处理语句”? - Marius
1
@Marius:是的,“蓝色文本” :) 我在 PHP 方面是新手,但不是在这个论坛 :) - serhio
@outis。当我连接时,我收到以下错误信息:Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY000] [2005] Unknown MySQL server host 'localhost,dbname=mydbname'...,但是使用mysql_connect($host, $username, $password)可以正常工作... - serhio
@serhio: 将DSN中的逗号改为分号(代码已更新以反映此更改)。这展示了阅读文档(http://www.php.net/manual/en/ref.pdo-mysql.connection.php)的价值。 - outis
显示剩余2条评论

9
首先,我看到您正在使用stripslashes()。这意味着您开启了魔术引号。建议关闭该功能。
您可能想要将其中一些内容放入函数中:
function post($name, $string = true) {
  $ret = mysql_real_escape_string(stripslashes($_POST[$name]));
  return $string ? "'" . $ret . "'" : $ret;
}

然后:

$company_name = post('company_name');

然而,所有这些只是稍微减少了您需要编写的样板代码量。

有人建议使用PDO或mysqli来实现这个目的,以便您可以使用预处理语句。虽然它们可能很有用,但这绝对不是必需的。您正在转义字段,因此关于SQL注入漏洞的指责(至少在这段代码的情况下)是错误的。

最后,我不会以这种方式构造查询。首先,它依赖于公司表中列的特定类型和顺序。更好的方法是明确说明这一点。通常我会这样做:

$name = mysql_real_escape_string($_POST['name']);
// etc
$sql = <<<END
INSERT INTO companies
(name, country, chat_language)
VALUES
($name, $country, $language)
END;

这将足以完成任务。当然,你可以调查使用mysqli或PDO,但这并不是必要的。


并不是OP的代码容易受到SQL注入攻击,而是对于预处理语句参数而言,SQL注入根本不是问题。 - outis
这里出现了一个小的“未填充”字段问题,它在插入 aValue, , otherValue 时出现,但是可以正常工作。 - serhio

9

我想提供一个选项来回答“PHP中是否有一个函数可以给字符串加引号”的问题 - 是的,你可以使用str_pad(),虽然手动添加可能更容易。

使用此函数的好处是,你还可以在PHP内部原生地传递一个字符来包装变量:

function str_wrap($string = '', $char = '"')
{
    return str_pad($string, strlen($string) + 2, $char, STR_PAD_BOTH);
}

echo str_wrap('hello world');      // "hello world"
echo str_wrap('hello world', '@'); // @hello world@

6
创建你自己的。
function addQuotes($str){
    return "'$str'";
}

2
或者为了让这个函数更好,也可以在其中加入mysql_real_escape_string。 - Marius

3
不要这样做。相反,请使用参数化查询,例如使用PDO

1
我是一个初学者,PDO 这个东西很复杂。在我的具体情况下,我该如何使用 PDO 呢(我贴了一些代码)?谢谢。 - serhio
outis的回答涉及到一些低级细节。 - Ignacio Vazquez-Abrams

2

这不是一个函数 - 但当你在谷歌搜索“php用引号包裹字符串”时,它会作为第一个帖子出现。如果有人只想将现有的字符串用引号括起来,而不必先运行它通过函数,那么这里是正确的语法:

echo $var   // hello

$var = '"'.$var.'"';

echo $var   // "hello"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接