PluginProbe
Redirection / 2.10.1
Redirection v2.10.1
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 2.10.1, at models/redirect.php

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