PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 4.3.0
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v4.3.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 / Tracker / Db / Pdo / Mysql.php
matomo / app / core / Tracker / Db / Pdo Last commit date
Mysql.php 5 years ago Pgsql.php 5 years ago
Mysql.php
330 lines
1 <?php
2 /**
3 * Matomo - 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\Tracker\Db\Pdo;
10
11 use Exception;
12 use PDO;
13 use PDOException;
14 use PDOStatement;
15 use Piwik\Config;
16 use Piwik\Tracker\Db;
17 use Piwik\Tracker\Db\DbException;
18
19 /**
20 * PDO MySQL wrapper
21 *
22 */
23 class Mysql extends Db
24 {
25 /**
26 * @var PDO
27 */
28 protected $connection = null;
29 protected $dsn;
30 protected $username;
31 protected $password;
32 protected $charset;
33
34 protected $mysqlOptions = array();
35
36
37 protected $activeTransaction = false;
38
39 /**
40 * Builds the DB object
41 *
42 * @param array $dbInfo
43 * @param string $driverName
44 */
45 public function __construct($dbInfo, $driverName = 'mysql')
46 {
47 if (isset($dbInfo['unix_socket']) && substr($dbInfo['unix_socket'], 0, 1) == '/') {
48 $this->dsn = $driverName . ':dbname=' . $dbInfo['dbname'] . ';unix_socket=' . $dbInfo['unix_socket'];
49 } elseif (!empty($dbInfo['port']) && substr($dbInfo['port'], 0, 1) == '/') {
50 $this->dsn = $driverName . ':dbname=' . $dbInfo['dbname'] . ';unix_socket=' . $dbInfo['port'];
51 } else {
52 $this->dsn = $driverName . ':dbname=' . $dbInfo['dbname'] . ';host=' . $dbInfo['host'] . ';port=' . $dbInfo['port'];
53 }
54
55 $this->username = $dbInfo['username'];
56 $this->password = $dbInfo['password'];
57
58 if (isset($dbInfo['charset'])) {
59 $this->charset = $dbInfo['charset'];
60 $this->dsn .= ';charset=' . $this->charset;
61 }
62
63
64 if (isset($dbInfo['enable_ssl']) && $dbInfo['enable_ssl']) {
65
66 if (!empty($dbInfo['ssl_key'])) {
67 $this->mysqlOptions[PDO::MYSQL_ATTR_SSL_KEY] = $dbInfo['ssl_key'];
68 }
69 if (!empty($dbInfo['ssl_cert'])) {
70 $this->mysqlOptions[PDO::MYSQL_ATTR_SSL_CERT] = $dbInfo['ssl_cert'];
71 }
72 if (!empty($dbInfo['ssl_ca'])) {
73 $this->mysqlOptions[PDO::MYSQL_ATTR_SSL_CA] = $dbInfo['ssl_ca'];
74 }
75 if (!empty($dbInfo['ssl_ca_path'])) {
76 $this->mysqlOptions[PDO::MYSQL_ATTR_SSL_CAPATH] = $dbInfo['ssl_ca_path'];
77 }
78 if (!empty($dbInfo['ssl_cipher'])) {
79 $this->mysqlOptions[PDO::MYSQL_ATTR_SSL_CIPHER] = $dbInfo['ssl_cipher'];
80 }
81 if (!empty($dbInfo['ssl_no_verify']) && defined('PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT')) {
82 $this->mysqlOptions[PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = false;
83 }
84 }
85
86 }
87
88 public function __destruct()
89 {
90 $this->connection = null;
91 }
92
93 /**
94 * Connects to the DB
95 *
96 * @throws Exception if there was an error connecting the DB
97 */
98 public function connect()
99 {
100 if (self::$profiling) {
101 $timer = $this->initProfiler();
102 }
103
104 // Make sure MySQL returns all matched rows on update queries including
105 // rows that actually didn't have to be updated because the values didn't
106 // change. This matches common behaviour among other database systems.
107 // See #6296 why this is important in tracker
108 $this->mysqlOptions[PDO::MYSQL_ATTR_FOUND_ROWS] = true;
109 $this->mysqlOptions[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
110
111 $this->connection = @new PDO($this->dsn, $this->username, $this->password, $this->mysqlOptions);
112
113 // we may want to setAttribute(PDO::ATTR_TIMEOUT ) to a few seconds (default is 60) in case the DB is locked
114 // the matomo.php would stay waiting for the database... bad!
115 // we delete the password from this object "just in case" it could be printed
116 $this->password = '';
117
118 /*
119 * Lazy initialization via MYSQL_ATTR_INIT_COMMAND depends
120 * on mysqlnd support, PHP version, and OS.
121 * see ZF-7428 and http://bugs.php.net/bug.php?id=47224
122 */
123 if (!empty($this->charset)) {
124 $sql = "SET NAMES '" . $this->charset . "'";
125 $this->connection->exec($sql);
126 }
127
128 if (self::$profiling && isset($timer)) {
129 $this->recordQueryProfile('connect', $timer);
130 }
131 }
132
133 /**
134 * Disconnects from the server
135 */
136 public function disconnect()
137 {
138 $this->connection = null;
139 }
140
141 /**
142 * Returns an array containing all the rows of a query result, using optional bound parameters.
143 *
144 * @param string $query Query
145 * @param array $parameters Parameters to bind
146 * @return array|bool
147 * @see query()
148 * @throws Exception|DbException if an exception occurred
149 */
150 public function fetchAll($query, $parameters = array())
151 {
152 try {
153 $sth = $this->query($query, $parameters);
154 if ($sth === false) {
155 return false;
156 }
157 return $sth->fetchAll(PDO::FETCH_ASSOC);
158 } catch (PDOException $e) {
159 throw new DbException("Error query: " . $e->getMessage());
160 }
161 }
162
163 /**
164 * Fetches the first column of all SQL result rows as an array.
165 *
166 * @param string $sql An SQL SELECT statement.
167 * @param mixed $bind Data to bind into SELECT placeholders.
168 * @throws \Piwik\Tracker\Db\DbException
169 * @return string
170 */
171 public function fetchCol($sql, $bind = array())
172 {
173 try {
174 $sth = $this->query($sql, $bind);
175 if ($sth === false) {
176 return false;
177 }
178 $result = $sth->fetchAll(PDO::FETCH_COLUMN, 0);
179 return $result;
180 } catch (PDOException $e) {
181 throw new DbException("Error query: " . $e->getMessage());
182 }
183 }
184
185 /**
186 * Returns the first row of a query result, using optional bound parameters.
187 *
188 * @param string $query Query
189 * @param array $parameters Parameters to bind
190 * @return bool|mixed
191 * @see query()
192 * @throws Exception|DbException if an exception occurred
193 */
194 public function fetch($query, $parameters = array())
195 {
196 try {
197 $sth = $this->query($query, $parameters);
198 if ($sth === false) {
199 return false;
200 }
201 return $sth->fetch(PDO::FETCH_ASSOC);
202 } catch (PDOException $e) {
203 throw new DbException("Error query: " . $e->getMessage());
204 }
205 }
206
207 /**
208 * Executes a query, using optional bound parameters.
209 *
210 * @param string $query Query
211 * @param array|string $parameters Parameters to bind array('idsite'=> 1)
212 * @return PDOStatement|bool PDOStatement or false if failed
213 * @throws DbException if an exception occurred
214 */
215 public function query($query, $parameters = array())
216 {
217 if (is_null($this->connection)) {
218 return false;
219 }
220
221 try {
222 if (self::$profiling) {
223 $timer = $this->initProfiler();
224 }
225
226 if (!is_array($parameters)) {
227 $parameters = array($parameters);
228 }
229 $sth = $this->connection->prepare($query);
230 $sth->execute($parameters);
231
232 if (self::$profiling && isset($timer)) {
233 $this->recordQueryProfile($query, $timer);
234 }
235 return $sth;
236 } catch (PDOException $e) {
237 $message = $e->getMessage() . " In query: $query Parameters: " . var_export($parameters, true);
238 throw new DbException("Error query: " . $message, (int) $e->getCode());
239 }
240 }
241
242 /**
243 * Returns the last inserted ID in the DB
244 * Wrapper of PDO::lastInsertId()
245 *
246 * @return int
247 */
248 public function lastInsertId()
249 {
250 return $this->connection->lastInsertId();
251 }
252
253 /**
254 * Test error number
255 *
256 * @param Exception $e
257 * @param string $errno
258 * @return bool
259 */
260 public function isErrNo($e, $errno)
261 {
262 return \Piwik\Db\Adapter\Pdo\Mysql::isPdoErrorNumber($e, $errno);
263 }
264
265 /**
266 * Return number of affected rows in last query
267 *
268 * @param mixed $queryResult Result from query()
269 * @return int
270 */
271 public function rowCount($queryResult)
272 {
273 return $queryResult->rowCount();
274 }
275
276 /**
277 * Start Transaction
278 * @return string TransactionID
279 */
280 public function beginTransaction()
281 {
282 if (!$this->activeTransaction === false) {
283 return;
284 }
285
286 if ($this->connection->beginTransaction()) {
287 $this->activeTransaction = uniqid();
288 return $this->activeTransaction;
289 }
290 }
291
292 /**
293 * Commit Transaction
294 * @param $xid
295 * @throws DbException
296 * @internal param TransactionID $string from beginTransaction
297 */
298 public function commit($xid)
299 {
300 if ($this->activeTransaction != $xid || $this->activeTransaction === false) {
301 return;
302 }
303
304 $this->activeTransaction = false;
305
306 if (!$this->connection->commit()) {
307 throw new DbException("Commit failed");
308 }
309 }
310
311 /**
312 * Rollback Transaction
313 * @param $xid
314 * @throws DbException
315 * @internal param TransactionID $string from beginTransaction
316 */
317 public function rollBack($xid)
318 {
319 if ($this->activeTransaction != $xid || $this->activeTransaction === false) {
320 return;
321 }
322
323 $this->activeTransaction = false;
324
325 if (!$this->connection->rollBack()) {
326 throw new DbException("Rollback failed");
327 }
328 }
329 }
330