PluginProbe
Redirection / 3.0
Redirection v3.0
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.0, at models/redirect.php

546 lines 15.4 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'] = isset( $details['status'] ) && $details['status'] === 'disabled' ? 'disabled' : 'enabled';
163
164 if ( ! isset( $details['position'] ) || $details['position'] === 0 ) {
165 $data['position'] = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$wpdb->prefix}redirection_items WHERE group_id=%d", $data['group_id'] ) );
166 }
167
168 $data = apply_filters( 'redirection_create_redirect', $data );
169
170 // Create
171 if ( $wpdb->insert( $wpdb->prefix.'redirection_items', $data ) !== false ) {
172 Red_Module::flush( $data['group_id'] );
173
174 $redirect = self::get_by_id( $wpdb->insert_id );
175 do_action( 'redirection_redirect_updated', $wpdb->insert_id, $redirect );
176
177 return $redirect;
178 }
179
180 return new WP_Error( 'redirect', __( 'Unable to add new redirect' ) );
181 }
182
183 public function update( $details ) {
184 global $wpdb;
185
186 $sanitizer = new Red_Item_Sanitize();
187 $data = $sanitizer->get( $details );
188
189 if ( is_wp_error( $data ) ) {
190 return $data;
191 }
192
193 $old_group = false;
194 if ( $data['group_id'] !== $this->group_id ) {
195 $old_group = $this->group_id;
196 }
197
198 // Save this
199 $data = apply_filters( 'redirection_update_redirect', $data );
200
201 $wpdb->update( $wpdb->prefix.'redirection_items', $data, array( 'id' => $this->id ) );
202 do_action( 'redirection_redirect_updated', $this, self::get_by_id( $this->id) );
203
204 $this->load_from_data( (object) $data );
205
206 Red_Module::flush( $this->group_id );
207
208 if ( $old_group !== $this->group_id ) {
209 Red_Module::flush( $old_group );
210 }
211
212 return true;
213 }
214
215 public function matches( $url ) {
216 if ( ! $this->is_enabled() ) {
217 return false;
218 }
219
220 $this->url = str_replace( ' ', '%20', $this->url );
221 $matches = false;
222
223 // Check if we match the URL
224 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) ) {
225 // Check if our match wants this URL
226 $target = $this->match->get_target( $url, $this->url, $this->regex );
227 $target = apply_filters( 'redirection_url_target', $target, $this->url );
228 $target = $this->action->process_before( $this->action_code, $target );
229
230 if ( $target ) {
231 do_action( 'redirection_visit', $this, $url, $target );
232 return $this->action->process_after( $this->action_code, $target );
233 }
234
235 return true;
236 }
237
238 return false;
239 }
240
241 public function visit( $url, $target ) {
242 global $wpdb;
243
244 $options = red_get_options();
245
246 // Update the counters
247 $this->last_count++;
248 $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->prefix}redirection_items SET last_count=last_count+1, last_access=NOW() WHERE id=%d", $this->id ) );
249
250 if ( isset( $options['expire_redirect'] ) && $options['expire_redirect'] !== -1 && $target ) {
251 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 ) );
252 }
253 }
254
255 public function is_enabled() {
256 return $this->status === 'enabled';
257 }
258
259 public function reset() {
260 global $wpdb;
261
262 $this->last_count = 0;
263 $this->last_access = '0000-00-00 00:00:00';
264
265 $wpdb->update( $wpdb->prefix.'redirection_items', array( 'last_count' => 0, 'last_access' => $this->last_access ), array( 'id' => $this->id ) );
266 }
267
268 public function enable() {
269 global $wpdb;
270
271 $this->status = 'enabled';
272 $wpdb->update( $wpdb->prefix.'redirection_items', array( 'status' => $this->status ), array( 'id' => $this->id ) );
273 }
274
275 public function disable() {
276 global $wpdb;
277
278 $this->status = 'disabled';
279 $wpdb->update( $wpdb->prefix.'redirection_items', array( 'status' => $this->status ), array( 'id' => $this->id ) );
280 }
281
282 public function get_id() {
283 return intval( $this->id, 10 );
284 }
285
286 public function get_position() {
287 return intval( $this->position, 10 );
288 }
289
290 public function get_group_id() {
291 return intval( $this->group_id, 10 );
292 }
293
294 public function get_url() {
295 return $this->url;
296 }
297
298 public function get_title() {
299 return $this->title ? $this->title : '';
300 }
301
302 public function get_hits() {
303 return intval( $this->last_count, 10 );
304 }
305
306 public function get_last_hit() {
307 return intval( $this->last_access, 10 );
308 }
309
310 public function is_regex() {
311 return $this->regex ? true : false;
312 }
313
314 public function get_match_type() {
315 return $this->match_type;
316 }
317
318 public function get_action_type() {
319 return $this->action_type;
320 }
321
322 public function get_action_code() {
323 return intval( $this->action_code, 10 );
324 }
325
326 public function get_action_data() {
327 return $this->action_data ? $this->action_data : '';
328 }
329
330 public static function get_filtered( array $params ) {
331 global $wpdb;
332
333 $orderby = 'id';
334 $direction = 'DESC';
335 $limit = RED_DEFAULT_PER_PAGE;
336 $offset = 0;
337 $where = '';
338
339 if ( isset( $params['orderby'] ) && in_array( $params['orderby'], array( 'url', 'last_count', 'last_access', 'position' ), true ) ) {
340 $orderby = $params['orderby'];
341 }
342
343 if ( isset( $params['direction'] ) && in_array( $params['direction'], array( 'asc', 'desc' ), true ) ) {
344 $direction = strtoupper( $params['direction'] );
345 }
346
347 if ( isset( $params['filter'] ) && strlen( $params['filter'] ) > 0 && $params['filter'] !== '0' ) {
348 if ( isset( $params['filterBy'] ) && $params['filterBy'] === 'group' ) {
349 $where = $wpdb->prepare( "WHERE group_id=%d", intval( $params['filter'], 10 ) );
350 } else {
351 $where = $wpdb->prepare( 'WHERE url LIKE %s', '%'.$wpdb->esc_like( trim( $params['filter'] ) ).'%' );
352 }
353 }
354
355 if ( isset( $params['per_page'] ) ) {
356 $limit = intval( $params['per_page'], 10 );
357 $limit = min( RED_MAX_PER_PAGE, $limit );
358 $limit = max( 5, $limit );
359 }
360
361 if ( isset( $params['page'] ) ) {
362 $offset = intval( $params['page'], 10 );
363 $offset = max( 0, $offset );
364 $offset *= $limit;
365 }
366
367 $table = $wpdb->prefix.'redirection_items';
368 $sql = trim( "SELECT * FROM {$table} $where " ).$wpdb->prepare( " ORDER BY $orderby $direction LIMIT %d,%d", $offset, $limit );
369
370 $rows = $wpdb->get_results( $sql );
371 $total_items = intval( $wpdb->get_var( "SELECT COUNT(*) FROM {$table} ".$where ) );
372 $items = array();
373
374 foreach ( $rows as $row ) {
375 $group = new Red_Item( $row );
376 $items[] = $group->to_json();
377 }
378
379 return array(
380 'items' => $items,
381 'total' => intval( $total_items, 10 ),
382 );
383 }
384
385 public function to_json() {
386 return array(
387 'id' => $this->get_id(),
388 'url' => $this->get_url(),
389 'action_code' => $this->get_action_code(),
390 'action_type' => $this->get_action_type(),
391 'action_data' => $this->match->get_data(),
392 'match_type' => $this->get_match_type(),
393 'title' => $this->get_title(),
394 'hits' => $this->get_hits(),
395 'regex' => $this->is_regex(),
396 'group_id' => $this->get_group_id(),
397 'position' => $this->get_position(),
398 'last_access' => $this->get_last_hit() > 0 ? date_i18n( get_option( 'date_format' ), $this->get_last_hit() ) : '-',
399 'enabled' => $this->is_enabled(),
400 );
401 }
402 }
403
404 class Red_Item_Sanitize {
405 private function clean_array( $array ) {
406 foreach ( $array as $name => $value ) {
407 if ( is_array( $value ) ) {
408 $array[ $name ] = $this->clean_array( $value );
409 } else {
410 $value = trim( $value );
411 $array[ $name ] = $value;
412 }
413 };
414
415 return $array;
416 }
417
418 public function get( array $details ) {
419 $data = array();
420 $details = $this->clean_array( $details );
421
422 $data['regex'] = isset( $details['regex'] ) && intval( $details['regex'], 10 ) === 1 ? 1 : 0;
423 $data['title'] = isset( $details['title'] ) ? $details['title'] : null;
424 $data['url'] = $this->get_url( empty( $details['url'] ) ? $this->auto_generate() : $details['url'], $data['regex'] );
425 $data['group_id'] = $this->get_group( isset( $details['group_id'] ) ? $details['group_id'] : 0 );
426 $data['position'] = $this->get_position( $details );
427
428 if ( $data['title'] ) {
429 $data['title'] = substr( $data['title'], 0, 500 );
430 }
431
432 $matcher = Red_Match::create( isset( $details['match_type'] ) ? $details['match_type'] : false );
433 if ( ! $matcher ) {
434 return new WP_Error( 'redirect', __( 'Invalid redirect matcher', 'redirection' ) );
435 }
436
437 $action_code = isset( $details['action_code'] ) ? intval( $details['action_code'], 10 ) : 0;
438 $action = Red_Action::create( isset( $details['action_type'] ) ? $details['action_type'] : false, $action_code );
439 if ( ! $action ) {
440 return new WP_Error( 'redirect', __( 'Invalid redirect action', 'redirection' ) );
441 }
442
443 $data['action_type'] = $details['action_type'];
444 $data['action_code'] = $this->get_code( $details['action_type'], $action_code );
445 $data['match_type'] = $details['match_type'];
446
447 if ( isset( $details['action_data'] ) ) {
448 $match_data = $matcher->save( $details['action_data'] ? $details['action_data'] : array(), ! $this->is_url_type( $data['action_type'] ) );
449 $data['action_data'] = is_array( $match_data ) ? serialize( $match_data ) : $match_data;
450 }
451
452 // Any errors?
453 foreach ( $data as $value ) {
454 if ( is_wp_error( $value ) ) {
455 return $value;
456 }
457 }
458
459 return apply_filters( 'redirection_validate_redirect', $data );
460 }
461
462 protected function get_position( $details ) {
463 if ( isset( $details['position'] ) ) {
464 return max( 0, intval( $details['position'], 10 ) );
465 }
466
467 return 0;
468 }
469
470 protected function is_url_type( $type ) {
471 if ( $type === 'url' || $type === 'pass' ) {
472 return true;
473 }
474
475 return false;
476 }
477
478 protected function get_code( $action_type, $code ) {
479 if ( $action_type === 'url' || $action_type === 'random' ) {
480 if ( in_array( $code, array( 301, 302, 307, 308 ), true ) ) {
481 return $code;
482 }
483 }
484
485 if ( $action_type === 'error' ) {
486 if ( in_array( $code, array( 401, 404, 410 ), true ) ) {
487 return $code;
488 }
489 }
490
491 return 0;
492 }
493
494 protected function get_group( $group_id ) {
495 $group_id = intval( $group_id, 10 );
496
497 if ( ! Red_Group::get( $group_id ) ) {
498 return new WP_Error( 'redirect', __( 'Invalid group when creating redirect', 'redirection' ) );
499 }
500
501 return $group_id;
502 }
503
504 protected function get_url( $url, $regex ) {
505 $url = self::sanitize_url( $url, $regex );
506
507 if ( $url === '' ) {
508 return new WP_Error( 'redirect', __( 'Invalid source URL', 'redirection' ) );
509 }
510
511 return $url;
512 }
513
514 protected function auto_generate() {
515 $options = red_get_options();
516 $url = '';
517
518 if ( isset( $options['auto_target'] ) && $options['auto_target'] ) {
519 $id = time();
520 $url = str_replace( '$dec$', $id, $options['auto_target'] );
521 $url = str_replace( '$hex$', sprintf( '%x', $id ), $url );
522 }
523
524 return $url;
525 }
526
527 public function sanitize_url( $url, $regex = false ) {
528 // Make sure that the old URL is relative
529 $url = preg_replace( '@^https?://(.*?)/@', '/', $url );
530 $url = preg_replace( '@^https?://(.*?)$@', '/', $url );
531
532 // No new lines
533 $url = preg_replace( "/[\r\n\t].*?$/s", '', $url );
534
535 // Clean control codes
536 $url = preg_replace( '/[^\PC\s]/u', '', $url );
537
538 // Ensure a slash at start
539 if ( substr( $url, 0, 1 ) !== '/' && $regex === false ) {
540 $url = '/'.$url;
541 }
542
543 return $url;
544 }
545 }
546