PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 1.3.1
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v1.3.1
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
Mssql.php 6 years ago Mysql.php 6 years ago Pgsql.php 6 years ago
Mysql.php
329 lines
1 <?php
2 /**
3 * Piwik - free/libre analytics platform
4 *
5 * @link https://matomo.org
6 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
7 *
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 use Zend_Db_Select;
21 use Zend_Db_Statement_Interface;
22
23 /**
24 */
25 class Mysql extends Zend_Db_Adapter_Pdo_Mysql implements AdapterInterface
26 {
27 /**
28 * Constructor
29 *
30 * @param array|Zend_Config $config database configuration
31 */
32 public function __construct($config)
33 {
34 // Enable LOAD DATA INFILE
35 if (defined('PDO::MYSQL_ATTR_LOCAL_INFILE')) {
36 $config['driver_options'][PDO::MYSQL_ATTR_LOCAL_INFILE] = true;
37 }
38 if ($config['enable_ssl']) {
39 if (!empty($config['ssl_key'])) {
40 $config['driver_options'][PDO::MYSQL_ATTR_SSL_KEY] = $config['ssl_key'];
41 }
42 if (!empty($config['ssl_cert'])) {
43 $config['driver_options'][PDO::MYSQL_ATTR_SSL_CERT] = $config['ssl_cert'];
44 }
45 if (!empty($config['ssl_ca'])) {
46 $config['driver_options'][PDO::MYSQL_ATTR_SSL_CA] = $config['ssl_ca'];
47 }
48 if (!empty($config['ssl_ca_path'])) {
49 $config['driver_options'][PDO::MYSQL_ATTR_SSL_CAPATH] = $config['ssl_ca_path'];
50 }
51 if (!empty($config['ssl_cipher'])) {
52 $config['driver_options'][PDO::MYSQL_ATTR_SSL_CIPHER] = $config['ssl_cipher'];
53 }
54 if (!empty($config['ssl_no_verify'])
55 && defined('PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT')
56 ) {
57 $config['driver_options'][PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = false;
58 }
59 }
60 parent::__construct($config);
61 }
62
63 /**
64 * Returns connection handle
65 *
66 * @return resource
67 */
68 public function getConnection()
69 {
70 if ($this->_connection) {
71 return $this->_connection;
72 }
73
74 $this->_connect();
75
76 /**
77 * Before MySQL 5.1.17, server-side prepared statements
78 * do not use the query cache.
79 * @see http://dev.mysql.com/doc/refman/5.1/en/query-cache-operation.html
80 *
81 * MySQL also does not support preparing certain DDL and SHOW
82 * statements.
83 * @see http://framework.zend.com/issues/browse/ZF-1398
84 */
85 $this->_connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
86
87 return $this->_connection;
88 }
89
90 protected function _connect()
91 {
92 if ($this->_connection) {
93 return;
94 }
95
96 parent::_connect();
97
98 // MYSQL_ATTR_USE_BUFFERED_QUERY will use more memory when enabled
99 // $this->_connection->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
100
101 $this->_connection->exec('SET sql_mode = "' . Db::SQL_MODE . '"');
102 }
103
104 /**
105 * Reset the configuration variables in this adapter.
106 */
107 public function resetConfig()
108 {
109 $this->_config = array();
110 }
111
112 /**
113 * Return default port.
114 *
115 * @return int
116 */
117 public static function getDefaultPort()
118 {
119 return 3306;
120 }
121
122 /**
123 * Check MySQL version
124 *
125 * @throws Exception
126 */
127 public function checkServerVersion()
128 {
129 $serverVersion = $this->getServerVersion();
130 $requiredVersion = Config::getInstance()->General['minimum_mysql_version'];
131
132 if (version_compare($serverVersion, $requiredVersion) === -1) {
133 throw new Exception(Piwik::translate('General_ExceptionDatabaseVersion', array('MySQL', $serverVersion, $requiredVersion)));
134 }
135 }
136
137 /**
138 * Returns the MySQL server version
139 *
140 * @return null|string
141 */
142 public function getServerVersion()
143 {
144 // prioritizing SELECT @@VERSION in case the connection version string is incorrect (which can
145 // occur on Azure)
146 $versionInfo = $this->fetchAll('SELECT @@VERSION');
147
148 if (count($versionInfo)) {
149 return $versionInfo[0]['@@VERSION'];
150 }
151
152 return parent::getServerVersion();
153 }
154
155 /**
156 * Check client version compatibility against database server
157 *
158 * @throws Exception
159 */
160 public function checkClientVersion()
161 {
162 $serverVersion = $this->getServerVersion();
163 $clientVersion = $this->getClientVersion();
164
165 // incompatible change to DECIMAL implementation in 5.0.3
166 if (version_compare($serverVersion, '5.0.3') >= 0
167 && version_compare($clientVersion, '5.0.3') < 0
168 ) {
169 throw new Exception(Piwik::translate('General_ExceptionIncompatibleClientServerVersions', array('MySQL', $clientVersion, $serverVersion)));
170 }
171 }
172
173 /**
174 * Returns true if this adapter's required extensions are enabled
175 *
176 * @return bool
177 */
178 public static function isEnabled()
179 {
180 return extension_loaded('PDO') && extension_loaded('pdo_mysql') && in_array('mysql', PDO::getAvailableDrivers());
181 }
182
183 /**
184 * Returns true if this adapter supports blobs as fields
185 *
186 * @return bool
187 */
188 public function hasBlobDataType()
189 {
190 return true;
191 }
192
193 /**
194 * Returns true if this adapter supports bulk loading
195 *
196 * @return bool
197 */
198 public function hasBulkLoader()
199 {
200 return true;
201 }
202
203 /**
204 * Test error number
205 *
206 * @param Exception $e
207 * @param string $errno
208 * @return bool
209 */
210 public function isErrNo($e, $errno)
211 {
212 return self::isPdoErrorNumber($e, $errno);
213 }
214
215
216 /**
217 * Test error number
218 *
219 * @param Exception $e
220 * @param string $errno
221 * @return bool
222 */
223 public static function isPdoErrorNumber($e, $errno)
224 {
225 if (preg_match('/(?:\[|\s)([0-9]{4})(?:\]|\s)/', $e->getMessage(), $match)) {
226 return $match[1] == $errno;
227 }
228
229 return false;
230 }
231
232 /**
233 * Is the connection character set equal to utf8?
234 *
235 * @return bool
236 */
237 public function isConnectionUTF8()
238 {
239 $charsetInfo = $this->fetchAll('SHOW VARIABLES LIKE ?', array('character_set_connection'));
240
241 if (empty($charsetInfo)) {
242 return false;
243 }
244
245 $charset = $charsetInfo[0]['Value'];
246 return $charset === 'utf8';
247 }
248
249 /**
250 * Return number of affected rows in last query
251 *
252 * @param mixed $queryResult Result from query()
253 * @return int
254 */
255 public function rowCount($queryResult)
256 {
257 return $queryResult->rowCount();
258 }
259
260 /**
261 * Retrieve client version in PHP style
262 *
263 * @return string
264 */
265 public function getClientVersion()
266 {
267 $this->_connect();
268 try {
269 $version = $this->_connection->getAttribute(PDO::ATTR_CLIENT_VERSION);
270 $matches = null;
271 if (preg_match('/((?:[0-9]{1,2}\.){1,3}[0-9]{1,2})/', $version, $matches)) {
272 return $matches[1];
273 }
274 } catch (PDOException $e) {
275 // In case of the driver doesn't support getting attributes
276 }
277 return null;
278 }
279
280 /**
281 * @var \Zend_Db_Statement_Pdo[]
282 */
283 private $cachePreparedStatement = array();
284
285 /**
286 * Prepares and executes an SQL statement with bound data.
287 * Caches prepared statements to avoid preparing the same query more than once
288 *
289 * @param string|Zend_Db_Select $sql The SQL statement with placeholders.
290 * @param array $bind An array of data to bind to the placeholders.
291 * @return Zend_Db_Statement_Interface
292 */
293 public function query($sql, $bind = array())
294 {
295 if (!is_string($sql)) {
296 return parent::query($sql, $bind);
297 }
298
299 if (isset($this->cachePreparedStatement[$sql])) {
300 if (!is_array($bind)) {
301 $bind = array($bind);
302 }
303
304 $stmt = $this->cachePreparedStatement[$sql];
305 $stmt->execute($bind);
306 return $stmt;
307 }
308
309 $stmt = parent::query($sql, $bind);
310 $this->cachePreparedStatement[$sql] = $stmt;
311 return $stmt;
312 }
313
314 /**
315 * Override _dsn() to ensure host and port to not be passed along
316 * if unix_socket is set since setting both causes unexpected behaviour
317 * @see http://php.net/manual/en/ref.pdo-mysql.connection.php
318 */
319 protected function _dsn()
320 {
321 if (!empty($this->_config['unix_socket'])) {
322 unset($this->_config['host']);
323 unset($this->_config['port']);
324 }
325
326 return parent::_dsn();
327 }
328 }
329