简体   繁体   中英

PDO + MySQL and broken UTF-8 encoding

I use the PDO library with a MySQL database in PHP, but if I insert any data encoded in UTF-8, like Arabic words, it's inserted into the database, but as ????????? .

In my own framework, after I create the PDO connection, I send two queries – SET NAMES utf8 and SET CHARACTER SET utf8 . It still doesn't work.

Example:

loadclass('PDO', array(
    sprintf(
        'mysql:host=%s;port=%s;dbname=%s',
        confitem('database', 'host'),
        confitem('database', 'port'),
        confitem('database', 'name')
    ),
    confitem('database', 'username'),
    confitem('database', 'password'),
    array('PDO::ATTR_PERSISTENT' => confitem('database', 'pconnect'))
));
$this->query('SET NAMES ' . confitem('database', 'charset'));
$this->query('SET CHARACTER SET ' . confitem('database', 'charset'));

Workaround: Use the json_encode function to convert data before inserting it to the database, and use json_decode to decode it after fetching. This is how I do it now.

Warning: This answer applies to PHP 5.3.5 and lower. Do not use it for PHP version 5.3.6 (released in March 2011) or later.

Compare with Palec's answer here .


Use:

$pdo = new PDO( 
    'mysql:host=hostname;dbname=defaultDbName', 
    'username', 
    'password', 
    array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8") 
); 

It forces UTF-8 on the PDO connection. It worked for me.

You have to set the correct character set for the connection. Add the charset=utf8 option to the DSN (this is MySQL-specific!)

$pdo = new PDO(
    'mysql:host=hostname;dbname=defaultDbName;charset=utf8',
    'username',
    'password'
);

However, in PHP versions before 5.3.6 (released in March 2011), you must use a workaround as the charset option in the DSN is not supported.

$pdo = new PDO(
    'mysql:host=hostname;dbname=defaultDbName',
    'username',
    'password',
    array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8")
);

All attempts like:

PDO::MYSQL_ATTR_INIT_COMMAND =>"SET NAMES 'utf8mb4' COLLATE 'utf8mb4_unicode_ci' "

or

$this->connection = new PDO('mysql:host='.DBHOST.';dbname='.DBNAME.';charset=utf8', DBUSER, DBPASS, self::$opt);

or

$this->connection->exec("set names utf8");

still generated unreadable text mess.

In my case, the cause of the problem was: htmlentities used prior to inserting data into a database. Cyrillic letters were destroyed completely.

Try setting the default_charset value in php.ini to UTF-8. Or you can set it using the ini_set function.

Also, if the input is coming through form submissions, make sure your web pages are set to UTF-8 using the meta tag.

When interacting with mysql or mariadb, charset 'utf8' is not correct. You need to use utf8mb4. Due to historical issues, utf8 in mysql/mariadb is an alias to utf8mb3 which can only contain a subset of utf8 (3 bytes instead of 4) So adding 'charset=utf8mb4' to your PDO DSN connection string is the correct thing to do for recent PHP versions, NOT charset=utf8.

For example, the poop emoji in full color: cannot be stored if the column and PDO are not utf8mb4.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM