PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / trunk
Matomo Analytics – Powerful, Privacy-First Insights for WordPress vtrunk
5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / app / core / Db / Adapter / Pdo / Mysql.php
matomo / app / core / Db / Adapter / Pdo Last commit date
Mysql.php 2 months ago
Mysql.php
269 lines
1 <?php
2
3 /**
4 * Matomo - free/libre analytics platform
5 *
6 * @link https://matomo.org
7 * @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
8 */
9 namespace Piwik\Db\Adapter\Pdo;
10
11 use Exception;
12 use PDO;
13 use PDOException;
14 use Piwik\Config;
15 use Piwik\Db;
16 use Piwik\Db\AdapterInterface;
17 use Piwik\Db\Schema;
18 use Piwik\Piwik;
19 use Zend_Config;
20 use Zend_Db_Adapter_Pdo_Mysql;
21 class Mysql extends Zend_Db_Adapter_Pdo_Mysql implements AdapterInterface
22 {
23 use Db\TransactionalDatabaseDynamicTrait;
24 /**
25 * @param array|Zend_Config $config database configuration
26 */
27 public function __construct($config)
28 {
29 // Enable LOAD DATA INFILE
30 if (defined('PDO::MYSQL_ATTR_LOCAL_INFILE')) {
31 $config['driver_options'][PDO::MYSQL_ATTR_LOCAL_INFILE] = \true;
32 }
33 if ($config['enable_ssl']) {
34 if (!empty($config['ssl_key'])) {
35 $config['driver_options'][PDO::MYSQL_ATTR_SSL_KEY] = $config['ssl_key'];
36 }
37 if (!empty($config['ssl_cert'])) {
38 $config['driver_options'][PDO::MYSQL_ATTR_SSL_CERT] = $config['ssl_cert'];
39 }
40 if (!empty($config['ssl_ca'])) {
41 $config['driver_options'][PDO::MYSQL_ATTR_SSL_CA] = $config['ssl_ca'];
42 }
43 if (!empty($config['ssl_ca_path'])) {
44 $config['driver_options'][PDO::MYSQL_ATTR_SSL_CAPATH] = $config['ssl_ca_path'];
45 }
46 if (!empty($config['ssl_cipher'])) {
47 $config['driver_options'][PDO::MYSQL_ATTR_SSL_CIPHER] = $config['ssl_cipher'];
48 }
49 if (!empty($config['ssl_no_verify']) && defined('PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT')) {
50 $config['driver_options'][PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = \false;
51 }
52 }
53 parent::__construct($config);
54 }
55 /**
56 * Returns connection handle
57 *
58 * @return resource
59 */
60 public function getConnection()
61 {
62 if ($this->_connection) {
63 return $this->_connection;
64 }
65 $this->_connect();
66 /**
67 * Before MySQL 5.1.17, server-side prepared statements
68 * do not use the query cache.
69 * @see https://dev.mysql.com/doc/refman/5.1/en/query-cache-operation.html
70 *
71 * MySQL also does not support preparing certain DDL and SHOW
72 * statements.
73 * @see https://framework.zend.com/issues/browse/ZF-1398
74 */
75 $this->_connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, \true);
76 return $this->_connection;
77 }
78 protected function _connect()
79 {
80 if ($this->_connection) {
81 return;
82 }
83 $sql = 'SET sql_mode = "' . Db::SQL_MODE . '"';
84 try {
85 parent::_connect();
86 $this->_connection->exec($sql);
87 } catch (Exception $e) {
88 if ($this->isErrNo($e, \Piwik\Updater\Migration\Db::ERROR_CODE_MYSQL_SERVER_HAS_GONE_AWAY)) {
89 // mysql may return a MySQL server has gone away error when trying to establish the connection.
90 // in that case we want to retry establishing the connection once after a short sleep
91 $this->_connection = null;
92 // we need to unset, otherwise parent connect won't retry
93 usleep(400 * 1000);
94 parent::_connect();
95 $this->_connection->exec($sql);
96 } else {
97 throw $e;
98 }
99 }
100 }
101 /**
102 * Reset the configuration variables in this adapter.
103 */
104 public function resetConfig()
105 {
106 $this->_config = array();
107 }
108 /**
109 * Return default port.
110 *
111 * @deprecated Use Schema::getDefaultPortForSchema instead
112 * @return int
113 */
114 public static function getDefaultPort()
115 {
116 return 3306;
117 }
118 /**
119 * Check MySQL version
120 *
121 * @throws Exception
122 */
123 public function checkServerVersion()
124 {
125 $requiredVersion = Schema::getInstance()->getMinimumSupportedVersion();
126 $serverVersion = $this->getServerVersion();
127 if (version_compare($serverVersion, $requiredVersion) === -1) {
128 throw new Exception(Piwik::translate('General_ExceptionDatabaseVersion', array('MySQL', $serverVersion, $requiredVersion)));
129 }
130 }
131 /**
132 * Returns the MySQL server version
133 *
134 * @return null|string
135 */
136 public function getServerVersion()
137 {
138 // prioritizing SELECT @@VERSION in case the connection version string is incorrect (which can
139 // occur on Azure)
140 $versionInfo = $this->fetchAll('SELECT @@VERSION');
141 if (count($versionInfo)) {
142 return $versionInfo[0]['@@VERSION'];
143 }
144 return parent::getServerVersion();
145 }
146 /**
147 * Check client version compatibility against database server
148 *
149 * @throws Exception
150 */
151 public function checkClientVersion()
152 {
153 $serverVersion = $this->getServerVersion();
154 $clientVersion = $this->getClientVersion();
155 // incompatible change to DECIMAL implementation in 5.0.3
156 if (version_compare($serverVersion, '5.0.3') >= 0 && version_compare($clientVersion, '5.0.3') < 0) {
157 throw new Exception(Piwik::translate('General_ExceptionIncompatibleClientServerVersions', array('MySQL', $clientVersion, $serverVersion)));
158 }
159 }
160 /**
161 * Returns true if this adapter's required extensions are enabled
162 *
163 * @return bool
164 */
165 public static function isEnabled()
166 {
167 return extension_loaded('PDO') && extension_loaded('pdo_mysql') && in_array('mysql', PDO::getAvailableDrivers());
168 }
169 /**
170 * Returns true if this adapter supports blobs as fields
171 *
172 * @return bool
173 */
174 public function hasBlobDataType()
175 {
176 return \true;
177 }
178 /**
179 * Returns true if this adapter supports bulk loading
180 *
181 * @return bool
182 */
183 public function hasBulkLoader()
184 {
185 return \true;
186 }
187 /**
188 * Test error number
189 *
190 * @param Exception $e
191 * @param string $errno
192 * @return bool
193 */
194 public function isErrNo($e, $errno)
195 {
196 return self::isPdoErrorNumber($e, $errno);
197 }
198 /**
199 * Test error number
200 *
201 * @param Exception $e
202 * @param string $errno
203 * @return bool
204 */
205 public static function isPdoErrorNumber($e, $errno)
206 {
207 if (preg_match('/(?:\\[|\\s)([0-9]{4})(?:\\]|\\s)/', $e->getMessage(), $match)) {
208 return $match[1] == $errno;
209 }
210 return \false;
211 }
212 /**
213 * Is the connection character set equal to utf8?
214 *
215 * @return bool
216 */
217 public function isConnectionUTF8()
218 {
219 $charsetInfo = $this->fetchAll('SHOW VARIABLES LIKE ?', array('character_set_connection'));
220 if (empty($charsetInfo)) {
221 return \false;
222 }
223 $charset = $charsetInfo[0]['Value'];
224 return strpos($charset, 'utf8') === 0;
225 }
226 /**
227 * Return number of affected rows in last query
228 *
229 * @param mixed $queryResult Result from query()
230 * @return int
231 */
232 public function rowCount($queryResult)
233 {
234 return $queryResult->rowCount();
235 }
236 /**
237 * Retrieve client version in PHP style
238 *
239 * @return string
240 */
241 public function getClientVersion()
242 {
243 $this->_connect();
244 try {
245 $version = $this->_connection->getAttribute(PDO::ATTR_CLIENT_VERSION);
246 $matches = null;
247 if (preg_match('/((?:[0-9]{1,2}\\.){1,3}[0-9]{1,2})/', $version, $matches)) {
248 return $matches[1];
249 }
250 } catch (PDOException $e) {
251 // In case of the driver doesn't support getting attributes
252 }
253 return null;
254 }
255 /**
256 * Override _dsn() to ensure host and port to not be passed along
257 * if unix_socket is set since setting both causes unexpected behaviour
258 * @see https://php.net/manual/en/ref.pdo-mysql.connection.php
259 */
260 protected function _dsn()
261 {
262 if (!empty($this->_config['unix_socket'])) {
263 unset($this->_config['host']);
264 unset($this->_config['port']);
265 }
266 return parent::_dsn();
267 }
268 }
269