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