【问题标题】:PHP PDO: charset, set names?PHP PDO:字符集,设置名称?
【发布时间】:2011-05-20 16:10:49
【问题描述】:

我以前在正常的 mysql_* 连接中就有这个:

mysql_set_charset("utf8",$link);
mysql_query("SET NAMES 'UTF8'");

PDO 需要它吗?我应该在哪里拥有它?

$connect = new PDO("mysql:host=$host;dbname=$db", $user, $pass, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));

【问题讨论】:

  • 由于 SQL 注入,应避免 "SET NAMES utf8"。详情请见php.net/manual/en/mysqlinfo.concepts.charset.php
  • 如果您有字符集问题,那么您可能别无选择,只能设置为 utf8。我认为应该使用下面的connection string as shown by Cobra_Fast。使用 PDO::prepare 准备带有绑定参数的 SQL 语句。
  • @masakielastic,那么我们应该如何将排序规则指定为“SET NAMES utf8 COLLATE utf8_unicode_ci”

标签: php mysql pdo


【解决方案1】:

您将在连接字符串中包含它,例如:

"mysql:host=$host;dbname=$db;charset=utf8mb4"

但是,在 PHP 5.3.6 之前,字符集选项被忽略了。如果你运行的是旧版本的 PHP,你必须这样做:

$dbh = new PDO("mysql:host=$host;dbname=$db",  $user, $password);
$dbh->exec("set names utf8mb4");

【讨论】:

  • 值得注意的是,这种行为在 5.3.6 中发生了变化,现在可以正常工作了。
  • 应该是 utf8 而不是 UTF-8 "mysql:host=$host;dbname=$db;charset=utf8"
  • 如果您使用的是最新版本的 PHP,请忽略以下答案:它在 php 5.3.8 中运行良好。
  • 在这种情况下我是否还必须指定排序规则?比如'SET NAMES utf8 COLLATE utf8_unicode_ci'?
  • 从 utf8 切换到 utf8mb4。
【解决方案2】:

我认为您需要额外查询,因为 DSN 中的字符集选项实际上被忽略了。请参阅其他答案的评论中发布的链接。

http://api.drupal.org/api/drupal/includes--database--mysql--database.inc/function/DatabaseConnection_mysql%3A%3A__construct/7 中查看 Drupal 7 是如何做到的:

// Force MySQL to use the UTF-8 character set. Also set the collation, if a
// certain one has been set; otherwise, MySQL defaults to 'utf8_general_ci'
// for UTF-8.
if (!empty($connection_options['collation'])) {
  $this->exec('SET NAMES utf8 COLLATE ' . $connection_options['collation']);
}
else {
  $this->exec('SET NAMES utf8');
}

【讨论】:

    【解决方案3】:

    在 PHP 5.3.6 之前,字符集选项被忽略。如果你运行的是旧版本的 PHP,你必须这样做:

    <?php
    
        $dbh = new PDO("mysql:$connstr",  $user, $password);
    
        $dbh -> exec("set names utf8");
    
    ?>
    

    【讨论】:

    • mods 注意:这是正确的答案,它是在接受的答案编辑此信息之前一年发布的。
    【解决方案4】:

    这可能是最优雅的方式。
    就在 PDO 构造函数调用中,但要避免错误的字符集选项(如上所述):

    $connect = new PDO(
      "mysql:host=$host;dbname=$db", 
      $user, 
      $pass, 
      array(
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"
      )
    );
    

    非常适合我。

    【讨论】:

    • 我的理解是这对于 php 5.3.0 也是错误的。在这种情况下,您需要通过引用其编号而不是其名称来在数组中输入选项,如下所示:array(1002 =&gt; 'SET NAMES utf8',...)
    • 感谢您的提示!我在多个运行不同 5.3.X 版本 PHP 的生产系统上成功使用了上述代码,但实际上它们都不是 5.3.0。
    • 我认为没有数据库特定选项会更优雅
    • 没错,MYSQL_ATTR_INIT_COMMAND 仅适用于 MySQL 数据库(有关每种数据库类型的可用命令,请参见 php.net/manual/de/pdo.drivers.php 的子页面)。但这正是 OP 所要求的。
    • 在 dsn 字符串中传递 charset=utf8 有效!我试图在groups.google.com/d/msg/auraphp/syMS26Rz-q8/9laQr9tR4EoJ 解决这个问题
    【解决方案5】:

    为了完整起见,当从 PDO 连接到 MySQL 时,实际上有 三种 方法来设置编码,哪些可用取决于您的 PHP 版本。优先顺序是:

    1. charset DSN 字符串中的参数
    2. 使用PDO::MYSQL_ATTR_INIT_COMMAND 连接选项运行SET NAMES utf8
    3. 手动运行SET NAMES utf8

    此示例代码实现了所有三个:

    <?php
    
    define('DB_HOST', 'localhost');
    define('DB_SCHEMA', 'test');
    define('DB_USER', 'test');
    define('DB_PASSWORD', 'test');
    define('DB_ENCODING', 'utf8');
    
    
    $dsn = 'mysql:host=' . DB_HOST . ';dbname=' . DB_SCHEMA;
    $options = array(
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    );
    
    if( version_compare(PHP_VERSION, '5.3.6', '<') ){
        if( defined('PDO::MYSQL_ATTR_INIT_COMMAND') ){
            $options[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES ' . DB_ENCODING;
        }
    }else{
        $dsn .= ';charset=' . DB_ENCODING;
    }
    
    $conn = @new PDO($dsn, DB_USER, DB_PASSWORD, $options);
    
    if( version_compare(PHP_VERSION, '5.3.6', '<') && !defined('PDO::MYSQL_ATTR_INIT_COMMAND') ){
        $sql = 'SET NAMES ' . DB_ENCODING;
        $conn->exec($sql);
    }
    

    同时做这三个可能是大材小用(除非你正在编写一个你打算分发或重用的类)。

    【讨论】:

    • 是否有等效的 ODBC/Access?我现在有一个工作的 Oracle 和 MySQL PHP PDO UTF8 连接,但我无法让它为 ODBC/Access 工作。
    • 哦,永远不要定义您的数据库密码。它们与超全局变量一样具有全局性,当您使用密码时,这不是一件好事。
    • 我使用的是 PHP 7.4,但仍然需要运行单独的查询,以便在获取数据 SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci 时显示非拉丁字符。 dsn 中的 utf8mb4 不够
    【解决方案6】:

    我只想补充一点,您必须确保您的数据库是使用 COLLATE utf8_general_ci 或您要使用的任何排序规则创建的,否则您最终可能会得到另一个超出预期的排序规则。

    在 phpmyadmin 中,您可以通过单击数据库并选择操作来查看排序规则。如果您尝试使用数据库之外的其他排序规则创建表,则无论如何您的表最终都会使用数据库排序规则。

    因此,在创建表之前,请确保您的数据库的排序规则是正确的。希望这可以为某人节省几个小时哈哈

    【讨论】:

    • “如果您尝试使用与数据库不同的排序规则创建表,那么无论如何您的表最终都会使用数据库排序规则” - 我认为这是不正确的。表排序规则优先于数据库的排序规则。 dev.mysql.com/doc/refman/5.5/en/charset-table.html
    【解决方案7】:
    $con="";
    $MODE="";
    $dbhost = "localhost";
    $dbuser = "root";
    $dbpassword = "";
    $database = "name";
    
    $con = new PDO ( "mysql:host=$dbhost;dbname=$database", "$dbuser", "$dbpassword", array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
    $con->setAttribute ( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );   
    

    【讨论】:

      【解决方案8】:

      我测试了这段代码

      $db=new PDO('mysql:host=localhost;dbname=cwDB','root','',
      array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
      $sql="select * from products  ";
      $stmt=$db->prepare($sql);
      $stmt->execute();
      while($result=$stmt->fetch(PDO::FETCH_ASSOC)){                  
          $id=$result['id'];
      }
      

      【讨论】:

      • 虽然此代码可能会回答问题,但提供有关此代码为何和/或如何回答问题的额外上下文可提高其长期价值。
      【解决方案9】:
      $conn = new PDO("mysql:host=$host;dbname=$db;charset=utf8", $user, $pass);
      

      【讨论】:

      • 虽然这个答案可能是正确且有用的,但最好在其中附上一些解释来解释它如何帮助解决问题。如果有更改(可能不相关)导致它停止工作并且用户需要了解它曾经是如何工作的,这在未来变得特别有用。
      【解决方案10】:

      就我而言,我必须添加这一行:

      $conn->exec("set names utf8"); //Support utf8
      

      它的外观:

      $conn = new PDO("mysql:host=$servername;dbname=$db", $username, $password);
      $conn->exec("set names utf8"); //Support utf8
      

      【讨论】:

        猜你喜欢
        • 2015-12-26
        • 2012-10-17
        • 2015-06-13
        • 1970-01-01
        • 2019-07-28
        • 1970-01-01
        • 2012-06-22
        • 2018-01-15
        • 1970-01-01
        相关资源
        最近更新 更多