PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 4.13.3
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v4.13.3
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 / classes / WpMatomo / Db / WordPressTracker.php
matomo / classes / WpMatomo / Db Last commit date
Settings.php 4 years ago WordPress.php 4 years ago WordPressDbStatement.php 4 years ago WordPressTracker.php 4 years ago
WordPressTracker.php
278 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 * @package matomo
8 */
9
10 namespace Piwik\Tracker\Db;
11
12 use Piwik\Db\Adapter\WordPressDbStatement;
13
14 if ( ! defined( 'ABSPATH' ) ) {
15 exit; // if accessed directly
16 }
17
18 class WordPress extends Mysqli {
19
20 private $old_suppress_errors_value = null;
21
22 public function disconnect() {
23 // we do not want to disconnect WordPress DB ever as it breaks eg the tests where it loses all
24 // temporary tables... also we should leave it up to WordPress whether it wants to close db or not
25 // global $wpdb;
26 // $wpdb->close();
27 // if ($this->connection) {
28 // parent::disconnect();
29 // }
30 }
31
32 public function connect() {
33 // do not connect to DB
34 }
35
36 public function lastInsertId( $tableName = null, $primaryKey = null ) {
37 global $wpdb;
38
39 if ( empty( $wpdb->insert_id ) ) {
40 return $this->fetchOne( 'SELECT LAST_INSERT_ID()' );
41 }
42
43 return $wpdb->insert_id;
44 }
45
46 /**
47 * @param \wpdb $wpdb
48 *
49 * @throws \Zend_Db_Statement_Exception
50 */
51 private function after_execute_query( $wpdb ) {
52 $lastError = $wpdb->last_error;
53
54 if ( $lastError && !$this->getErrorNumberFromMessage($lastError) ) {
55 // see #174 mysqli message usually doesn't include the error code so we need to add it for isErrNo to work
56 // we want to execute this while errors are suppressed
57 $row = $wpdb->get_row('SHOW ERRORS', ARRAY_A);
58 if (!empty($row['Code'])) {
59 $lastError = '['.$row['Code'].'] ' . $lastError;
60 }
61 }
62
63 if ( isset( $this->old_suppress_errors_value ) ) {
64 $wpdb->suppress_errors( $this->old_suppress_errors_value );
65 $this->old_suppress_errors_value = null;
66 }
67
68 if ( $lastError ) {
69 throw new \Zend_Db_Statement_Exception( $lastError );
70 }
71 }
72
73 /**
74 * @param \wpdb $wpdb
75 * @param $sql
76 */
77 private function before_execute_query( $wpdb, $sql ) {
78 if ( ! $wpdb->suppress_errors
79 && defined( 'WP_DEBUG' )
80 && WP_DEBUG
81 && defined( 'WP_DEBUG_DISPLAY' )
82 && WP_DEBUG_DISPLAY ) {
83 // we want to prevent showing these notices
84 if ( defined( 'MATOMO_SUPPRESS_DB_ERRORS' ) ) {
85 if ( MATOMO_SUPPRESS_DB_ERRORS === true ) {
86 $this->old_suppress_errors_value = $wpdb->suppress_errors( true );
87 }
88
89 // any other value than false and we will not supproess
90 return;
91 }
92
93 $this->old_suppress_errors_value = $wpdb->suppress_errors( true );
94 return;
95 }
96
97 if ( ! $wpdb->suppress_errors ) {
98 if ( ( stripos( $sql, '/* WP IGNORE ERROR */' ) !== false )
99 || stripos( $sql, 'SELECT @@TX_ISOLATION' ) !== false
100 || stripos( $sql, 'SELECT @@transaction_isolation' ) !== false ) {
101 // see {@link WordPress::before_execute_query() }
102 $this->old_suppress_errors_value = $wpdb->suppress_errors( true );
103
104 return;
105 }
106 }
107 }
108
109 private function getErrorNumberFromMessage( $message ) {
110 if ( preg_match( '/(?:\[|\s)([0-9]{4})(?:\]|\s)/', $message, $match ) ) {
111 return $match[1];
112 }
113 }
114
115 /**
116 * Test error number
117 *
118 * @param \Exception $e
119 * @param string $errno
120 *
121 * @return bool
122 */
123 public function isErrNo( $e, $errno ) {
124 $errorCode = $this->getErrorNumberFromMessage($e->getMessage());
125 return !empty($errorCode) && $errorCode == $errno;
126 }
127
128 public function rowCount( $queryResult ) {
129 return $queryResult->rowCount();
130 }
131
132 private function prepareWp( $sql, $bind = array() ) {
133 global $wpdb;
134
135 // fix some queries
136 $sql = str_replace( '%', '%%', $sql ); // eg when "value like 'done%'"
137
138 if ( is_array( $bind ) && empty( $bind ) ) {
139 return $sql;
140 }
141 if ( ! is_array( $bind ) ) {
142 $bind = array( $bind );
143 }
144
145 $has_replaced_null = false;
146 $null_placeholder = '_#__###NULL###_' . rand(1, PHP_INT_MAX) . ' __#_';
147 // random number not really needed but may prevent random issues that someone could somehow inject easily something
148
149 foreach ($bind as $index => $val) {
150 if (is_object($val) && method_exists($val, '__toString')) {
151 $bind[$index] = $val->__toString();
152 }
153
154 if (is_null($val)) {
155 $bind[$index] = $null_placeholder;
156 $has_replaced_null = true;
157 } elseif (is_string($val) && strpos($val, $null_placeholder) !== false) {
158 throw new \Exception('unexpected bind param'); // preventing random injections or something
159 }
160 }
161
162 $sql = str_replace( '?', '%s', $sql );
163
164 $query = $wpdb->prepare( $sql, $bind );
165
166 if ($has_replaced_null) {
167 $query = str_replace("'$null_placeholder'", 'NULL', $query);
168 }
169
170 return $query;
171 }
172
173 public function query( $query, $parameters = array() ) {
174 global $wpdb;
175
176 $test_query = trim( $query );
177 if ( strpos( $test_query, '/*' ) === 0 ) {
178 // remove eg "/* trigger = CronArchive */"
179 $startPos = strpos( $test_query, '*/' );
180 $test_query = substr( $test_query, $startPos + strlen( '*/' ) );
181 $test_query = trim( $test_query );
182 }
183
184 if ( preg_match( '/^\s*(select)\s/i', $test_query ) ) {
185 // WordPress does not fetch any result when doing a select... it's only supposed to be used for things like
186 // insert / update / drop ...
187 $result = $this->fetchAll( $query, $parameters );
188 } else {
189 $query = $this->prepareWp( $query, $parameters );
190 $this->before_execute_query( $wpdb, $query );
191 $result = $wpdb->query( $query );
192 $this->after_execute_query( $wpdb );
193 }
194
195 return new WordPressDbStatement( $this, $query, $result );
196 }
197
198 public function beginTransaction() {
199 global $wpdb;
200 if ( ! $this->activeTransaction === false ) {
201 return;
202 }
203
204 $wpdb->query( 'START TRANSACTION' );
205 $this->activeTransaction = uniqid();
206
207 return $this->activeTransaction;
208 }
209
210 /**
211 * Commit Transaction
212 *
213 * @param $xid
214 *
215 * @throws DbException
216 * @internal param TransactionID $string from beginTransaction
217 */
218 public function commit( $xid ) {
219 global $wpdb;
220
221 if ( $this->activeTransaction != $xid || $this->activeTransaction === false ) {
222 return;
223 }
224
225 $this->activeTransaction = false;
226
227 $wpdb->query( 'COMMIT' );
228 }
229
230 /**
231 * Rollback Transaction
232 *
233 * @param $xid
234 *
235 * @throws DbException
236 * @internal param TransactionID $string from beginTransaction
237 */
238 public function rollBack( $xid ) {
239 global $wpdb;
240
241 if ( $this->activeTransaction != $xid || $this->activeTransaction === false ) {
242 return;
243 }
244
245 $this->activeTransaction = false;
246
247 $wpdb->query( 'ROLLBACK' );
248 }
249
250 public function fetch( $query, $parameters = array() ) {
251 global $wpdb;
252 $prepare = $this->prepareWp( $query, $parameters );
253
254 $this->before_execute_query( $wpdb, $query );
255
256 $row = $wpdb->get_row( $prepare, ARRAY_A );
257
258 $this->after_execute_query( $wpdb );
259
260 return $row;
261 }
262
263 public function fetchAll( $query, $parameters = array() ) {
264 global $wpdb;
265 $prepare = $this->prepareWp( $query, $parameters );
266
267 $this->before_execute_query( $wpdb, $query );
268
269 $results = $wpdb->get_results( $prepare, ARRAY_A );
270
271 $this->after_execute_query( $wpdb );
272
273 return $results;
274 }
275
276
277 }
278