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