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