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 / classes / WpMatomo / Db / WordPressTracker.php
matomo / classes / WpMatomo / Db Last commit date
Settings.php 6 years ago WordPress.php 6 years ago WordPressDbStatement.php 6 years ago WordPressTracker.php 6 years ago
WordPressTracker.php
258 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_null($val)) {
135 $bind[$index] = $null_placeholder;
136 $has_replaced_null = true;
137 } elseif (is_string($val) && strpos($val, $null_placeholder) !== false) {
138 throw new \Exception('unexpected bind param'); // preventing random injections or something
139 }
140 }
141
142 $sql = str_replace( '?', '%s', $sql );
143
144 $query = $wpdb->prepare( $sql, $bind );
145
146 if ($has_replaced_null) {
147 $query = str_replace("'$null_placeholder'", 'NULL', $query);
148 }
149
150 return $query;
151 }
152
153 public function query( $query, $parameters = array() ) {
154 global $wpdb;
155
156 $test_query = trim( $query );
157 if ( strpos( $test_query, '/*' ) === 0 ) {
158 // remove eg "/* trigger = CronArchive */"
159 $startPos = strpos( $test_query, '*/' );
160 $test_query = substr( $test_query, $startPos + strlen( '*/' ) );
161 $test_query = trim( $test_query );
162 }
163
164 if ( preg_match( '/^\s*(select)\s/i', $test_query ) ) {
165 // WordPress does not fetch any result when doing a select... it's only supposed to be used for things like
166 // insert / update / drop ...
167 $result = $this->fetchAll( $query, $parameters );
168 } else {
169 $query = $this->prepareWp( $query, $parameters );
170 $this->before_execute_query( $wpdb );
171 $result = $wpdb->query( $query );
172 $this->after_execute_query( $wpdb );
173 }
174
175 return new WordPressDbStatement( $this, $query, $result );
176 }
177
178 public function beginTransaction() {
179 global $wpdb;
180 if ( ! $this->activeTransaction === false ) {
181 return;
182 }
183
184 $wpdb->query( 'START TRANSACTION' );
185 $this->activeTransaction = uniqid();
186
187 return $this->activeTransaction;
188 }
189
190 /**
191 * Commit Transaction
192 *
193 * @param $xid
194 *
195 * @throws DbException
196 * @internal param TransactionID $string from beginTransaction
197 */
198 public function commit( $xid ) {
199 global $wpdb;
200
201 if ( $this->activeTransaction != $xid || $this->activeTransaction === false ) {
202 return;
203 }
204
205 $this->activeTransaction = false;
206
207 $wpdb->query( 'COMMIT' );
208 }
209
210 /**
211 * Rollback Transaction
212 *
213 * @param $xid
214 *
215 * @throws DbException
216 * @internal param TransactionID $string from beginTransaction
217 */
218 public function rollBack( $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( 'ROLLBACK' );
228 }
229
230 public function fetch( $query, $parameters = array() ) {
231 global $wpdb;
232 $prepare = $this->prepareWp( $query, $parameters );
233
234 $this->before_execute_query( $wpdb );
235
236 $row = $wpdb->get_row( $prepare, ARRAY_A );
237
238 $this->after_execute_query( $wpdb );
239
240 return $row;
241 }
242
243 public function fetchAll( $query, $parameters = array() ) {
244 global $wpdb;
245 $prepare = $this->prepareWp( $query, $parameters );
246
247 $this->before_execute_query( $wpdb );
248
249 $results = $wpdb->get_results( $prepare, ARRAY_A );
250
251 $this->after_execute_query( $wpdb );
252
253 return $results;
254 }
255
256
257 }
258