Skip to content

Commit

Permalink
Merge pull request #9045 from roland-d/utf8mb4-drivers
Browse files Browse the repository at this point in the history
Add UTF8MB4 support to the database drivers.
  • Loading branch information
wilsonge committed Feb 18, 2016
2 parents 984544a + dbaaa2a commit e7aaae9
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 33 deletions.
18 changes: 13 additions & 5 deletions libraries/joomla/database/driver/mysql.php
Expand Up @@ -512,16 +512,24 @@ private function hasProfiling()
private function serverClaimsUtf8mb4Support()
{
$client_version = mysql_get_client_info();
$server_version = $this->getVersion();

if (strpos($client_version, 'mysqlnd') !== false)
if (version_compare($server_version, '5.5.3', '<'))
{
$client_version = preg_replace('/^\D+([\d.]+).*/', '$1', $client_version);

return version_compare($client_version, '5.0.9', '>=');
return false;
}
else
{
return version_compare($client_version, '5.5.3', '>=');
if (strpos($client_version, 'mysqlnd') !== false)
{
$client_version = preg_replace('/^\D+([\d.]+).*/', '$1', $client_version);

return version_compare($client_version, '5.0.9', '>=');
}
else
{
return version_compare($client_version, '5.5.3', '>=');
}
}
}

Expand Down
18 changes: 13 additions & 5 deletions libraries/joomla/database/driver/mysqli.php
Expand Up @@ -954,16 +954,24 @@ private function hasProfiling()
private function serverClaimsUtf8mb4Support()
{
$client_version = mysqli_get_client_info();
$server_version = $this->getVersion();

if (strpos($client_version, 'mysqlnd') !== false)
if (version_compare($server_version, '5.5.3', '<'))
{
$client_version = preg_replace('/^\D+([\d.]+).*/', '$1', $client_version);

return version_compare($client_version, '5.0.9', '>=');
return false;
}
else
{
return version_compare($client_version, '5.5.3', '>=');
if (strpos($client_version, 'mysqlnd') !== false)
{
$client_version = preg_replace('/^\D+([\d.]+).*/', '$1', $client_version);

return version_compare($client_version, '5.0.9', '>=');
}
else
{
return version_compare($client_version, '5.5.3', '>=');
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion libraries/joomla/database/driver/pdo.php
Expand Up @@ -325,7 +325,7 @@ public function disconnect()
}

$this->freeResult();
unset($this->connection);
$this->connection = null;
}

/**
Expand Down
56 changes: 34 additions & 22 deletions libraries/joomla/database/driver/pdomysql.php
Expand Up @@ -72,24 +72,21 @@ class JDatabaseDriverPdomysql extends JDatabaseDriverPdo
*/
public function __construct($options)
{
/**
* Pre-populate the UTF-8 Multibyte compatibility flag. Unfortuantely PDO won't report the server version
* unless we're connected to it and we cannot connect to it unless we know if it supports utf8mb4 which requires
* us knowing the server version. Between this chicken and egg issue we _assume_ it's supported and we'll just
* catch any problems at connection time.
*/
$this->utf8mb4 = true;

// Get some basic values from the options.
$options['driver'] = 'mysql';
$options['charset'] = (isset($options['charset'])) ? $options['charset'] : 'utf8';

if ($this->utf8mb4 && ($options['charset'] == 'utf8'))
if (!isset($options['charset']) || $options['charset'] == 'utf8')
{
$options['charset'] = 'utf8mb4';
}

$this->charset = $options['charset'];
/**
* Pre-populate the UTF-8 Multibyte compatibility flag. Unfortunately PDO won't report the server version
* unless we're connected to it, and we cannot connect to it unless we know if it supports utf8mb4, which requires
* us knowing the server version. Because of this chicken and egg issue, we _assume_ it's supported and we'll just
* catch any problems at connection time.
*/
$this->utf8mb4 = ($options['charset'] == 'utf8mb4');

// Finalize initialisation.
parent::__construct($options);
Expand All @@ -112,27 +109,42 @@ public function connect()
}
catch (\RuntimeException $e)
{
// If the connection failed but not because of the wrong character set bubble up the exception
if (!$this->utf8mb4 || ($this->options['charset'] != 'utf8mb4'))
// If the connection failed, but not because of the wrong character set, then bubble up the exception.
if (!$this->utf8mb4)
{
throw $e;
}

/**
* If the connection failed and I was trying to use the utf8mb4 charset then it is likely that the server
* doesn't support utf8mb4 despite claiming otherwise.
*
* This happens on old MySQL server versions (less than 5.5.3) using the mysqlnd PHP driver. Since mysqlnd
* masks the server version and reports only its own we can not be sure if the server actually does support
* UTF-8 Multibyte (i.e. it's MySQL 5.5.3 or later). Since the utf8mb4 charset is undefined in this case we
* catch the error and determine that utf8mb4 is not supported!
*/
/*
* Otherwise, try connecting again without using
* utf8mb4 and see if maybe that was the problem. If the
* connection succeeds, then we will have learned that the
* client end of the connection does not support utf8mb4.
*/
$this->utf8mb4 = false;
$this->options['charset'] = 'utf8';

parent::connect();
}

if ($this->utf8mb4)
{
/*
* At this point we know the client supports utf8mb4. Now
* we must check if the server supports utf8mb4 as well.
*/
$serverVersion = $this->connection->getAttribute(PDO::ATTR_SERVER_VERSION);
$this->utf8mb4 = version_compare($serverVersion, '5.5.3', '>=');

if (!$this->utf8mb4)
{
// Reconnect with the utf8 character set.
parent::disconnect();
$this->options['charset'] = 'utf8';
parent::connect();
}
}

$this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
}
Expand Down

0 comments on commit e7aaae9

Please sign in to comment.