Joan Joan - 2 months ago 14
PHP Question

PDO connection : UTF-8 declaration with SET NAMES / CHARACTER SET?

According to php.net, StackOverflow and other sources of trust, I can find 4 different ways to set UTF-8 on PDO connection, but can't find wich one is the better to choose.

A PDO connection code (and some inits) :

$localhost = $_SERVER['SERVER_NAME'] == 'localhost';
error_reporting(-1); ini_set('display_errors', $localhost); // Old : error_reporting($localhost ? -1 : 0); see answer above
date_default_timezone_set('Europe/Paris');

$pdo_db = 'mysql:host=localhost;dbname=local_db;charset=utf8'; // METHOD #1
$pdo_login = 'root';
$pdo_pass = 'localpass';

try {
$db = new PDO($pdo_db, $pdo_login, $pdo_pass, array(
PDO::ATTR_ERRMODE => $localhost ? PDO::ERRMODE_EXCEPTION : PDO::ERRMODE_SILENT,
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8', // METHOD #2
));
$db -> exec('SET NAMES utf8'); // METHOD #3
$db -> exec('SET CHARACTER SET utf8'); // METHOD #4
$db -> exec('SET time_zone = \''.date_default_timezone_get().'\'');
} catch (PDOException $error) {
die($error -> getMessage());
}


So, what I understood, is that the Method 1 only work with PHP 5.3+ (but it seems that it's a bit buggy), and method 2 is for MySQL only.
Differences between method 3 and 4 is MySQL thing, but I still don't know wich one is better. And is there a way to call SET NAMES in PDO attributes, but not for MySQL only?

Thanks!

Answer

Setting it in DSN is the only proper way (although it is only supported since 5.3).
You can this one and SET NAMES at the same time.

All the other ways will make infamous half-fictional GBK injection possible.

Please note that your setting for error_reporting() is utterly wrong. it have to be unconditional -1. If you concerned about displaying errors - there is a proper ini setting for this, called display_errors, can be set at runtime.
While error_reporting sets level of the error and should be at max all the time.