PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 4.0.2
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v4.0.2
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 / classes / WpMatomo / Db / WordPressTracker.php
matomo / classes / WpMatomo / Db Last commit date
Settings.php 5 years ago WordPress.php 5 years ago WordPressDbStatement.php 6 years ago WordPressTracker.php 5 years ago
WordPressTracker.php
262 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 private function before_execute_query( $wpdb ) {
74 if ( ! $wpdb->suppress_errors
75 && defined( 'WP_DEBUG' )
76 && WP_DEBUG
77 && defined( 'WP_DEBUG_DISPLAY' )
78 && WP_DEBUG_DISPLAY ) {
79 // we want to prevent showing these notices
80 if ( defined( 'MATOMO_SUPPRESS_DB_ERRORS' ) ) {
81 if ( MATOMO_SUPPRESS_DB_ERRORS === true ) {
82 $this->old_suppress_errors_value = $wpdb->suppress_errors( true );
83 }
84
85 // any other value than false and we will not supproess
86 return;
87 }
88
89 $this->old_suppress_errors_value = $wpdb->suppress_errors( true );
90 }
91 }
92
93 private function getErrorNumberFromMessage( $message ) {
94 if ( preg_match( '/(?:\[|\s)([0-9]{4})(?:\]|\s)/', $message, $match ) ) {
95 return $match[1];
96 }
97 }
98
99 /**
100 * Test error number
101 *
102 * @param \Exception $e
103 * @param string $errno
104 *
105 * @return bool
106 */
107 public function isErrNo( $e, $errno ) {
108 $errorCode = $this->getErrorNumberFromMessage($e->getMessage());
109 return !empty($errorCode) && $errorCode == $errno;
110 }
111
112 public function rowCount( $queryResult ) {
113 return $queryResult->rowCount();
114 }
115
116 private function prepareWp( $sql, $bind = array() ) {
117 global $wpdb;
118
119 // fix some queries
120 $sql = str_replace( '%', '%%', $sql ); // eg when "value like 'done%'"
121
122 if ( is_array( $bind ) && empty( $bind ) ) {
123 return $sql;
124 }
125 if ( ! is_array( $bind ) ) {
126 $bind = array( $bind );
127 }
128
129 $has_replaced_null = false;
130 $null_placeholder = '_#__###NULL###_' . rand(1, PHP_INT_MAX) . ' __#_';
131 // random number not really needed but may prevent random issues that someone could somehow inject easily something
132
133 foreach ($bind as $index => $val) {
134 if (is_object($val) && method_exists($val, '__toString')) {
135 $bind[$index] = $val->__toString();
136 }
137
138 if (is_null($val)) {
139 $bind[$index] = $null_placeholder;
140 $has_replaced_null = true;
141 } elseif (is_string($val) && strpos($val, $null_placeholder) !== false) {
142 throw new \Exception('unexpected bind param'); // preventing random injections or something
143 }
144 }
145
146 $sql = str_replace( '?', '%s', $sql );
147
148 $query = $wpdb->prepare( $sql, $bind );
149
150 if ($has_replaced_null) {
151 $query = str_replace("'$null_placeholder'", 'NULL', $query);
152 }
153
154 return $query;
155 }
156
157 public function query( $query, $parameters = array() ) {
158 global $wpdb;
159
160 $test_query = trim( $query );
161 if ( strpos( $test_query, '/*' ) === 0 ) {
162 // remove eg "/* trigger = CronArchive */"
163 $startPos = strpos( $test_query, '*/' );
164 $test_query = substr( $test_query, $startPos + strlen( '*/' ) );
165 $test_query = trim( $test_query );
166 }
167
168 if ( preg_match( '/^\s*(select)\s/i', $test_query ) ) {
169 // WordPress does not fetch any result when doing a select... it's only supposed to be used for things like
170 // insert / update / drop ...
171 $result = $this->fetchAll( $query, $parameters );
172 } else {
173 $query = $this->prepareWp( $query, $parameters );
174 $this->before_execute_query( $wpdb );
175 $result = $wpdb->query( $query );
176 $this->after_execute_query( $wpdb );
177 }
178
179 return new WordPressDbStatement( $this, $query, $result );
180 }
181
182 public function beginTransaction() {
183 global $wpdb;
184 if ( ! $this->activeTransaction === false ) {
185 return;
186 }
187
188 $wpdb->query( 'START TRANSACTION' );
189 $this->activeTransaction = uniqid();
190
191 return $this->activeTransaction;
192 }
193
194 /**
195 * Commit Transaction
196 *
197 * @param $xid
198 *
199 * @throws DbException
200 * @internal param TransactionID $string from beginTransaction
201 */
202 public function commit( $xid ) {
203 global $wpdb;
204
205 if ( $this->activeTransaction != $xid || $this->activeTransaction === false ) {
206 return;
207 }
208
209 $this->activeTransaction = false;
210
211 $wpdb->query( 'COMMIT' );
212 }
213
214 /**
215 * Rollback Transaction
216 *
217 * @param $xid
218 *
219 * @throws DbException
220 * @internal param TransactionID $string from beginTransaction
221 */
222 public function rollBack( $xid ) {
223 global $wpdb;
224
225 if ( $this->activeTransaction != $xid || $this->activeTransaction === false ) {
226 return;
227 }
228
229 $this->activeTransaction = false;
230
231 $wpdb->query( 'ROLLBACK' );
232 }
233
234 public function fetch( $query, $parameters = array() ) {
235 global $wpdb;
236 $prepare = $this->prepareWp( $query, $parameters );
237
238 $this->before_execute_query( $wpdb );
239
240 $row = $wpdb->get_row( $prepare, ARRAY_A );
241
242 $this->after_execute_query( $wpdb );
243
244 return $row;
245 }
246
247 public function fetchAll( $query, $parameters = array() ) {
248 global $wpdb;
249 $prepare = $this->prepareWp( $query, $parameters );
250
251 $this->before_execute_query( $wpdb );
252
253 $results = $wpdb->get_results( $prepare, ARRAY_A );
254
255 $this->after_execute_query( $wpdb );
256
257 return $results;
258 }
259
260
261 }
262