PluginProbe
Redirection / 3.2
Redirection v3.2
5.10.0 5.9.0 5.8.1 5.8.0 3.7.2 3.7.3 4.0 4.0.1 4.1 4.1.1 4.2 4.2.1 4.2.2 4.2.3 4.3 4.3.1 4.3.2 4.3.3 4.4 4.4.1 4.4.2 4.5 4.5.1 4.6.2 4.7.1 All 130 releases
redirection / models / redirect.php

redirect.php in Redirection 3.2, at models/redirect.php

549 lines 15.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 class Red_Item {
4 private $id = null;
5 private $url = null;
6 private $regex = false;
7 private $action_data = null;
8 private $action_code = 0;
9 private $action_type;
10 private $match_type;
11 private $title;
12 private $last_access = null;
13 private $last_count = 0;
14 private $status;
15 private $position;
16 private $group_id;
17
18 function __construct( $values, $type = '', $match = '' ) {
19 if ( is_object( $values ) ) {
20 $this->load_from_data( $values );
21
22 if ( $this->last_access === '0000-00-00 00:00:00' ) {
23 $this->last_access = 0;
24 } else {
25 $this->last_access = mysql2date( 'U', $this->last_access );
26 }
27 }
28 }
29
30 private function load_from_data( stdClass $values ) {
31 foreach ( $values as $key => $value ) {
32 $this->$key = $value;
33 }
34
35 if ( $this->match_type === '' ) {
36 $this->match_type = 'url';
37 }
38
39 $this->regex = (bool)$this->regex;
40 $this->match = Red_Match::create( $this->match_type, $this->action_data );
41 $this->match->id = $this->id;
42 $this->match->action_code = $this->action_code;
43
44 $action = false;
45
46 if ( $this->action_type ) {
47 $action = Red_Action::create( $this->action_type, $this->action_code );
48 }
49
50 if ( $action ) {
51 $this->action = $action;
52 $this->match->action = $this->action;
53 }
54 else {
55 $this->action = Red_Action::create( 'nothing', 0 );
56 }
57 }
58
59 static function get_all_for_module( $module ) {
60 global $wpdb;
61
62 $sql = $wpdb->prepare( "SELECT {$wpdb->prefix}redirection_items.* FROM {$wpdb->prefix}redirection_items
63 INNER JOIN {$wpdb->prefix}redirection_groups ON {$wpdb->prefix}redirection_groups.id={$wpdb->prefix}redirection_items.group_id
64 AND {$wpdb->prefix}redirection_groups.status='enabled' AND {$wpdb->prefix}redirection_groups.module_id=%d
65 WHERE {$wpdb->prefix}redirection_items.status='enabled'
66 ORDER BY {$wpdb->prefix}redirection_groups.position,{$wpdb->prefix}redirection_items.position", $module );
67
68 $rows = $wpdb->get_results( $sql );
69 $items = array();
70
71 foreach ( (array) $rows as $row ) {
72 $items[] = new Red_Item( $row );
73 }
74
75 return $items;
76 }
77
78 static function get_for_url( $url ) {
79 global $wpdb;
80
81 $sql = $wpdb->prepare( "SELECT {$wpdb->prefix}redirection_items.*,{$wpdb->prefix}redirection_groups.position AS group_pos
82 FROM {$wpdb->prefix}redirection_items INNER JOIN {$wpdb->prefix}redirection_groups ON
83 {$wpdb->prefix}redirection_groups.id={$wpdb->prefix}redirection_items.group_id AND {$wpdb->prefix}redirection_groups.status='enabled'
84 AND {$wpdb->prefix}redirection_groups.module_id=%d WHERE ({$wpdb->prefix}redirection_items.regex=1
85 OR {$wpdb->prefix}redirection_items.url=%s)", WordPress_Module::MODULE_ID, $url );
86
87 $rows = $wpdb->get_results( $sql );
88 $items = array();
89 if ( count( $rows ) > 0 ) {
90 foreach ( $rows as $row ) {
91 $items[] = array( 'position' => ( $row->group_pos * 1000 ) + $row->position, 'item' => new Red_Item( $row ) );
92 }
93 }
94
95 usort( $items, array( 'Red_Item', 'sort_urls' ) );
96 $items = array_map( array( 'Red_Item', 'reduce_sorted_items' ), $items );
97
98 // Sort it in PHP
99 ksort( $items );
100 $items = array_values( $items );
101 return $items;
102 }
103
104 static function get_all() {
105 global $wpdb;
106
107 $rows = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}redirection_items" );
108 $items = array();
109
110 foreach ( (array) $rows as $row ) {
111 $items[] = new Red_Item( $row );
112 }
113
114 return $items;
115 }
116
117 static function sort_urls( $first, $second ) {
118 if ( $first['position'] === $second['position'] ) {
119 return 0;
120 }
121
122 return ($first['position'] < $second['position']) ? -1 : 1;
123 }
124
125 static function reduce_sorted_items( $item ) {
126 return $item['item'];
127 }
128
129 static function get_by_id( $id ) {
130 global $wpdb;
131
132 $row = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}redirection_items WHERE id=%d", $id ) );
133 if ( $row )
134 return new Red_Item( $row );
135 return false;
136 }
137
138 public static function disable_where_matches( $url ) {
139 global $wpdb;
140
141 $wpdb->update( $wpdb->prefix.'redirection_items', array( 'status' => 'disabled' ), array( 'url' => $url ) );
142 }
143
144 public function delete() {
145 global $wpdb;
146
147 $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}redirection_items WHERE id=%d", $this->id ) );
148 do_action( 'redirection_redirect_deleted', $this );
149
150 Red_Module::flush( $this->group_id );
151 }
152
153 static function create( array $details ) {
154 global $wpdb;
155
156 $sanitizer = new Red_Item_Sanitize();
157 $data = $sanitizer->get( $details );
158 if ( is_wp_error( $data ) ) {
159 return $data;
160 }
161
162 $data['status'] = 'enabled';
163 if ( ( isset( $details['enabled'] ) && $details['enabled'] === 'disabled' ) || ( isset( $details['status'] ) && $details['status'] === 'disabled' ) ) {
164 $data['status'] = 'disabled';
165 }
166
167 if ( ! isset( $details['position'] ) || $details['position'] === 0 ) {
168 $data['position'] = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$wpdb->prefix}redirection_items WHERE group_id=%d", $data['group_id'] ) );
169 }
170
171 $data = apply_filters( 'redirection_create_redirect', $data );
172
173 // Create
174 if ( $wpdb->insert( $wpdb->prefix.'redirection_items', $data ) !== false ) {
175 Red_Module::flush( $data['group_id'] );
176
177 $redirect = self::get_by_id( $wpdb->insert_id );
178 do_action( 'redirection_redirect_updated', $wpdb->insert_id, $redirect );
179
180 return $redirect;
181 }
182
183 return new WP_Error( 'redirect', __( 'Unable to add new redirect' ) );
184 }
185
186 public function update( $details ) {
187 global $wpdb;
188
189 $sanitizer = new Red_Item_Sanitize();
190 $data = $sanitizer->get( $details );
191
192 if ( is_wp_error( $data ) ) {
193 return $data;
194 }
195
196 $old_group = false;
197 if ( $data['group_id'] !== $this->group_id ) {
198 $old_group = $this->group_id;
199 }
200
201 // Save this
202 $data = apply_filters( 'redirection_update_redirect', $data );
203
204 $wpdb->update( $wpdb->prefix.'redirection_items', $data, array( 'id' => $this->id ) );
205 do_action( 'redirection_redirect_updated', $this, self::get_by_id( $this->id) );
206
207 $this->load_from_data( (object) $data );
208
209 Red_Module::flush( $this->group_id );
210
211 if ( $old_group !== $this->group_id ) {
212 Red_Module::flush( $old_group );
213 }
214
215 return true;
216 }
217
218 public function matches( $url ) {
219 if ( ! $this->is_enabled() ) {
220 return false;
221 }
222
223 $this->url = str_replace( ' ', '%20', $this->url );
224 $matches = false;
225
226 // Check if we match the URL
227 if ( ( $this->regex === false && ( $this->url === $url || $this->url === rtrim( $url, '/' ) || $this->url === urldecode( $url ) ) ) || ( $this->regex === true && @preg_match( '@'.str_replace( '@', '\\@', $this->url ).'@', $url, $matches ) > 0) || ( $this->regex === true && @preg_match( '@'.str_replace( '@', '\\@', $this->url ).'@', urldecode( $url ), $matches ) > 0) ) {
228 // Check if our match wants this URL
229 $target = $this->match->get_target( $url, $this->url, $this->regex );
230 $target = apply_filters( 'redirection_url_target', $target, $this->url );
231 $target = $this->action->process_before( $this->action_code, $target );
232
233 if ( $target ) {
234 do_action( 'redirection_visit', $this, $url, $target );
235 return $this->action->process_after( $this->action_code, $target );
236 }
237
238 return true;
239 }
240
241 return false;
242 }
243
244 public function visit( $url, $target ) {
245 global $wpdb;
246
247 $options = red_get_options();
248
249 // Update the counters
250 $this->last_count++;
251 $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->prefix}redirection_items SET last_count=last_count+1, last_access=NOW() WHERE id=%d", $this->id ) );
252
253 if ( isset( $options['expire_redirect'] ) && $options['expire_redirect'] !== -1 && $target ) {
254 RE_Log::create( $url, $target, Redirection_Request::get_user_agent(), Redirection_Request::get_ip(), Redirection_Request::get_referrer(), array( 'redirect_id' => $this->id, 'group_id' => $this->group_id ) );
255 }
256 }
257
258 public function is_enabled() {
259 return $this->status === 'enabled';
260 }
261
262 public function reset() {
263 global $wpdb;
264
265 $this->last_count = 0;
266 $this->last_access = '0000-00-00 00:00:00';
267
268 $wpdb->update( $wpdb->prefix.'redirection_items', array( 'last_count' => 0, 'last_access' => $this->last_access ), array( 'id' => $this->id ) );
269 }
270
271 public function enable() {
272 global $wpdb;
273
274 $this->status = 'enabled';
275 $wpdb->update( $wpdb->prefix.'redirection_items', array( 'status' => $this->status ), array( 'id' => $this->id ) );
276 }
277
278 public function disable() {
279 global $wpdb;
280
281 $this->status = 'disabled';
282 $wpdb->update( $wpdb->prefix.'redirection_items', array( 'status' => $this->status ), array( 'id' => $this->id ) );
283 }
284
285 public function get_id() {
286 return intval( $this->id, 10 );
287 }
288
289 public function get_position() {
290 return intval( $this->position, 10 );
291 }
292
293 public function get_group_id() {
294 return intval( $this->group_id, 10 );
295 }
296
297 public function get_url() {
298 return $this->url;
299 }
300
301 public function get_title() {
302 return $this->title ? $this->title : '';
303 }
304
305 public function get_hits() {
306 return intval( $this->last_count, 10 );
307 }
308
309 public function get_last_hit() {
310 return intval( $this->last_access, 10 );
311 }
312
313 public function is_regex() {
314 return $this->regex ? true : false;
315 }
316
317 public function get_match_type() {
318 return $this->match_type;
319 }
320
321 public function get_action_type() {
322 return $this->action_type;
323 }
324
325 public function get_action_code() {
326 return intval( $this->action_code, 10 );
327 }
328
329 public function get_action_data() {
330 return $this->action_data ? $this->action_data : '';
331 }
332
333 public static function get_filtered( array $params ) {
334 global $wpdb;
335
336 $orderby = 'id';
337 $direction = 'DESC';
338 $limit = RED_DEFAULT_PER_PAGE;
339 $offset = 0;
340 $where = '';
341
342 if ( isset( $params['orderby'] ) && in_array( $params['orderby'], array( 'url', 'last_count', 'last_access', 'position' ), true ) ) {
343 $orderby = $params['orderby'];
344 }
345
346 if ( isset( $params['direction'] ) && in_array( $params['direction'], array( 'asc', 'desc' ), true ) ) {
347 $direction = strtoupper( $params['direction'] );
348 }
349
350 if ( isset( $params['filter'] ) && strlen( $params['filter'] ) > 0 && $params['filter'] !== '0' ) {
351 if ( isset( $params['filterBy'] ) && $params['filterBy'] === 'group' ) {
352 $where = $wpdb->prepare( "WHERE group_id=%d", intval( $params['filter'], 10 ) );
353 } else {
354 $where = $wpdb->prepare( 'WHERE url LIKE %s', '%'.$wpdb->esc_like( trim( $params['filter'] ) ).'%' );
355 }
356 }
357
358 if ( isset( $params['per_page'] ) ) {
359 $limit = intval( $params['per_page'], 10 );
360 $limit = min( RED_MAX_PER_PAGE, $limit );
361 $limit = max( 5, $limit );
362 }
363
364 if ( isset( $params['page'] ) ) {
365 $offset = intval( $params['page'], 10 );
366 $offset = max( 0, $offset );
367 $offset *= $limit;
368 }
369
370 $table = $wpdb->prefix.'redirection_items';
371 $sql = trim( "SELECT * FROM {$table} $where " ).$wpdb->prepare( " ORDER BY $orderby $direction LIMIT %d,%d", $offset, $limit );
372
373 $rows = $wpdb->get_results( $sql );
374 $total_items = intval( $wpdb->get_var( "SELECT COUNT(*) FROM {$table} ".$where ) );
375 $items = array();
376
377 foreach ( $rows as $row ) {
378 $group = new Red_Item( $row );
379 $items[] = $group->to_json();
380 }
381
382 return array(
383 'items' => $items,
384 'total' => intval( $total_items, 10 ),
385 );
386 }
387
388 public function to_json() {
389 return array(
390 'id' => $this->get_id(),
391 'url' => $this->get_url(),
392 'action_code' => $this->get_action_code(),
393 'action_type' => $this->get_action_type(),
394 'action_data' => $this->match->get_data(),
395 'match_type' => $this->get_match_type(),
396 'title' => $this->get_title(),
397 'hits' => $this->get_hits(),
398 'regex' => $this->is_regex(),
399 'group_id' => $this->get_group_id(),
400 'position' => $this->get_position(),
401 'last_access' => $this->get_last_hit() > 0 ? date_i18n( get_option( 'date_format' ), $this->get_last_hit() ) : '-',
402 'enabled' => $this->is_enabled(),
403 );
404 }
405 }
406
407 class Red_Item_Sanitize {
408 private function clean_array( $array ) {
409 foreach ( $array as $name => $value ) {
410 if ( is_array( $value ) ) {
411 $array[ $name ] = $this->clean_array( $value );
412 } else {
413 $value = trim( $value );
414 $array[ $name ] = $value;
415 }
416 };
417
418 return $array;
419 }
420
421 public function get( array $details ) {
422 $data = array();
423 $details = $this->clean_array( $details );
424
425 $data['regex'] = isset( $details['regex'] ) && intval( $details['regex'], 10 ) === 1 ? 1 : 0;
426 $data['title'] = isset( $details['title'] ) ? $details['title'] : null;
427 $data['url'] = $this->get_url( empty( $details['url'] ) ? $this->auto_generate() : $details['url'], $data['regex'] );
428 $data['group_id'] = $this->get_group( isset( $details['group_id'] ) ? $details['group_id'] : 0 );
429 $data['position'] = $this->get_position( $details );
430
431 if ( $data['title'] ) {
432 $data['title'] = substr( $data['title'], 0, 500 );
433 }
434
435 $matcher = Red_Match::create( isset( $details['match_type'] ) ? $details['match_type'] : false );
436 if ( ! $matcher ) {
437 return new WP_Error( 'redirect', __( 'Invalid redirect matcher', 'redirection' ) );
438 }
439
440 $action_code = isset( $details['action_code'] ) ? intval( $details['action_code'], 10 ) : 0;
441 $action = Red_Action::create( isset( $details['action_type'] ) ? $details['action_type'] : false, $action_code );
442 if ( ! $action ) {
443 return new WP_Error( 'redirect', __( 'Invalid redirect action', 'redirection' ) );
444 }
445
446 $data['action_type'] = $details['action_type'];
447 $data['action_code'] = $this->get_code( $details['action_type'], $action_code );
448 $data['match_type'] = $details['match_type'];
449
450 if ( isset( $details['action_data'] ) ) {
451 $match_data = $matcher->save( $details['action_data'] ? $details['action_data'] : array(), ! $this->is_url_type( $data['action_type'] ) );
452 $data['action_data'] = is_array( $match_data ) ? serialize( $match_data ) : $match_data;
453 }
454
455 // Any errors?
456 foreach ( $data as $value ) {
457 if ( is_wp_error( $value ) ) {
458 return $value;
459 }
460 }
461
462 return apply_filters( 'redirection_validate_redirect', $data );
463 }
464
465 protected function get_position( $details ) {
466 if ( isset( $details['position'] ) ) {
467 return max( 0, intval( $details['position'], 10 ) );
468 }
469
470 return 0;
471 }
472
473 protected function is_url_type( $type ) {
474 if ( $type === 'url' || $type === 'pass' ) {
475 return true;
476 }
477
478 return false;
479 }
480
481 protected function get_code( $action_type, $code ) {
482 if ( $action_type === 'url' || $action_type === 'random' ) {
483 if ( in_array( $code, array( 301, 302, 307, 308 ), true ) ) {
484 return $code;
485 }
486 }
487
488 if ( $action_type === 'error' ) {
489 if ( in_array( $code, array( 401, 404, 410 ), true ) ) {
490 return $code;
491 }
492 }
493
494 return 0;
495 }
496
497 protected function get_group( $group_id ) {
498 $group_id = intval( $group_id, 10 );
499
500 if ( ! Red_Group::get( $group_id ) ) {
501 return new WP_Error( 'redirect', __( 'Invalid group when creating redirect', 'redirection' ) );
502 }
503
504 return $group_id;
505 }
506
507 protected function get_url( $url, $regex ) {
508 $url = self::sanitize_url( $url, $regex );
509
510 if ( $url === '' ) {
511 return new WP_Error( 'redirect', __( 'Invalid source URL', 'redirection' ) );
512 }
513
514 return $url;
515 }
516
517 protected function auto_generate() {
518 $options = red_get_options();
519 $url = '';
520
521 if ( isset( $options['auto_target'] ) && $options['auto_target'] ) {
522 $id = time();
523 $url = str_replace( '$dec$', $id, $options['auto_target'] );
524 $url = str_replace( '$hex$', sprintf( '%x', $id ), $url );
525 }
526
527 return $url;
528 }
529
530 public function sanitize_url( $url, $regex = false ) {
531 // Make sure that the old URL is relative
532 $url = preg_replace( '@^https?://(.*?)/@', '/', $url );
533 $url = preg_replace( '@^https?://(.*?)$@', '/', $url );
534
535 // No new lines
536 $url = preg_replace( "/[\r\n\t].*?$/s", '', $url );
537
538 // Clean control codes
539 $url = preg_replace( '/[^\PC\s]/u', '', $url );
540
541 // Ensure a slash at start
542 if ( substr( $url, 0, 1 ) !== '/' && $regex === false ) {
543 $url = '/'.$url;
544 }
545
546 return $url;
547 }
548 }
549