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

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