PluginProbe
Redirection / 3.7
Redirection v3.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
redirection / models / htaccess.php

htaccess.php in Redirection 3.7, at models/htaccess.php

269 lines 7.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_Htaccess {
4 private $items = array();
5 const INSERT_REGEX = '@\n?# Created by Redirection(?:.*?)# End of Redirection\n?@sm';
6
7 private function encode_from( $url ) {
8 $url = $this->encode( $url );
9
10 // Apache 2 does not need a leading slashing
11 $url = ltrim( $url, '/' );
12
13 // Exactly match the URL
14 return '^' . $url . '$';
15 }
16
17 // URL encode some things, but other things can be passed through
18 private function encode2nd( $url ) {
19 $allowed = [
20 '%2F' => '/',
21 '%3F' => '?',
22 '%3A' => ':',
23 '%3D' => '=',
24 '%26' => '&',
25 '%25' => '%',
26 '+' => '%20',
27 '%24' => '$',
28 '%23' => '#',
29 ];
30
31 $url = urlencode( $url );
32 return $this->replace_encoding( $url, $allowed );
33 }
34
35 private function replace_encoding( $str, $allowed ) {
36 foreach ( $allowed as $before => $after ) {
37 $str = str_replace( $before, $after, $str );
38 }
39
40 return $str;
41 }
42
43 private function encode( $url ) {
44 $allowed = [
45 '%2F' => '/',
46 '%3F' => '?',
47 '+' => '%20',
48 '.' => '\\.',
49 ];
50
51 return $this->replace_encoding( urlencode( $url ), $allowed );
52 }
53
54 private function encode_regex( $url ) {
55 // Remove any newlines
56 $url = preg_replace( "/[\r\n\t].*?$/s", '', $url );
57
58 // Remove invalid characters
59 $url = preg_replace( '/[^\PC\s]/u', '', $url );
60
61 // Make sure spaces are quoted
62 $url = str_replace( ' ', '%20', $url );
63 $url = str_replace( '%24', '$', $url );
64
65 // No leading slash
66 $url = ltrim( $url, '/' );
67
68 // If pattern has a ^ at the start then ensure we don't have a slash immediatley after
69 $url = preg_replace( '@^\^/@', '^', $url );
70
71 return $url;
72 }
73
74 private function add_referrer( $item, $match ) {
75 $from = $this->encode_from( ltrim( $item->get_url(), '/' ) );
76 if ( $item->is_regex() ) {
77 $from = $this->encode_regex( ltrim( $item->get_url(), '/' ) );
78 }
79
80 if ( ( $match->url_from || $match->url_notfrom ) && $match->referrer ) {
81 $this->items[] = sprintf( 'RewriteCond %%{HTTP_REFERER} %s [NC]', ( $match->regex ? $this->encode_regex( $match->referrer ) : $this->encode_from( $match->referrer ) ) );
82
83 if ( $match->url_from ) {
84 $to = $this->target( $item->get_action_type(), $match->url_from, $item->get_action_code(), $item->is_regex() );
85 $this->items[] = sprintf( 'RewriteRule %s %s', $from, $to );
86 }
87
88 if ( $match->url_notfrom ) {
89 $to = $this->target( $item->get_action_type(), $match->url_notfrom, $item->get_action_code(), $item->is_regex() );
90 $this->items[] = sprintf( 'RewriteRule %s %s', $from, $to );
91 }
92 }
93 }
94
95 private function add_agent( $item, $match ) {
96 $from = $this->encode( ltrim( $item->get_url(), '/' ) );
97 if ( $item->is_regex() ) {
98 $from = $this->encode_regex( ltrim( $item->get_url(), '/' ) );
99 }
100
101 if ( ( $match->url_from || $match->url_notfrom ) && $match->user_agent ) {
102 $this->items[] = sprintf( 'RewriteCond %%{HTTP_USER_AGENT} %s [NC]', ( $match->regex ? $this->encode_regex( $match->user_agent ) : $this->encode2nd( $match->user_agent ) ) );
103
104 if ( $match->url_from ) {
105 $to = $this->target( $item->get_action_type(), $match->url_from, $item->get_action_code(), $item->is_regex() );
106 $this->items[] = sprintf( 'RewriteRule %s %s', $from, $to );
107 }
108
109 if ( $match->url_notfrom ) {
110 $to = $this->target( $item->get_action_type(), $match->url_notfrom, $item->get_action_code(), $item->is_regex() );
111 $this->items[] = sprintf( 'RewriteRule %s %s', $from, $to );
112 }
113 }
114 }
115
116 private function add_server( $item, $match ) {
117 $match->url = $match->url_from;
118 $this->items[] = sprintf( 'RewriteCond %%{HTTP_HOST} ^%s$ [NC]', preg_quote( $match->server ) );
119 $this->add_url( $item, $match );
120 }
121
122 private function add_url( $item, $match ) {
123 $url = $item->get_url();
124
125 if ( $item->is_regex() === false && strpos( $url, '?' ) !== false || strpos( $url, '&' ) !== false ) {
126 $url_parts = wp_parse_url( $url );
127 $url = $url_parts['path'];
128 $query = isset( $url_parts['query'] ) ? $url_parts['query'] : '';
129 $this->items[] = sprintf( 'RewriteCond %%{QUERY_STRING} ^%s$', $query );
130 }
131
132 $to = $this->target( $item->get_action_type(), $match->url, $item->get_action_code(), $item->is_regex() );
133 $from = $this->encode_from( $url );
134
135 if ( $item->is_regex() ) {
136 $from = $this->encode_regex( $item->get_url() );
137 }
138
139 if ( $to ) {
140 $this->items[] = sprintf( 'RewriteRule %s %s', $from, $to );
141 }
142 }
143
144 private function action_random( $data, $code, $regex ) {
145 // Pick a WP post at random
146 global $wpdb;
147
148 $post = $wpdb->get_var( "SELECT ID FROM {$wpdb->posts} ORDER BY RAND() LIMIT 0,1" );
149 $url = wp_parse_url( get_permalink( $post ) );
150
151 return sprintf( '%s [R=%d,L]', $this->encode( $url['path'] ), $code );
152 }
153
154 private function action_pass( $data, $code, $regex ) {
155 if ( $regex ) {
156 return sprintf( '%s [L]', $this->encode2nd( $data ), $code );
157 }
158 return sprintf( '%s [L]', $this->encode2nd( $data ), $code );
159 }
160
161 private function action_error( $data, $code, $regex ) {
162 if ( $code === 410 ) {
163 return '/ [G]';
164 }
165 return '/ [F]';
166 }
167
168 private function action_url( $data, $code, $regex ) {
169 if ( $regex ) {
170 return sprintf( '%s [R=%d,L]', $this->encode2nd( $data ), $code );
171 }
172 return sprintf( '%s [R=%d,L]', $this->encode2nd( $data ), $code );
173 }
174
175 private function target( $action, $data, $code, $regex ) {
176 $target = 'action_' . $action;
177
178 if ( method_exists( $this, $target ) ) {
179 return $this->$target( $data, $code, $regex );
180 }
181 return '';
182 }
183
184 private function generate() {
185 $version = red_get_plugin_data( dirname( dirname( __FILE__ ) ) . '/redirection.php' );
186
187 if ( count( $this->items ) === 0 ) {
188 return '';
189 }
190
191 $text[] = '# Created by Redirection';
192 $text[] = '# ' . date( 'r' );
193 $text[] = '# Redirection ' . trim( $version['Version'] ) . ' - https://redirection.me';
194 $text[] = '';
195
196 // mod_rewrite section
197 $text[] = '<IfModule mod_rewrite.c>';
198
199 // Add http => https option
200 $options = red_get_options();
201 if ( $options['https'] ) {
202 $text[] = 'RewriteCond %{HTTPS} off';
203 $text[] = 'RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI}';
204 }
205
206 // Add redirects
207 $text = array_merge( $text, array_filter( array_map( [ $this, 'sanitize_redirect' ], $this->items ) ) );
208
209 // End of mod_rewrite
210 $text[] = '</IfModule>';
211 $text[] = '';
212
213 // End of redirection section
214 $text[] = '# End of Redirection';
215
216 $text = implode( "\n", $text );
217 return "\n" . $text . "\n";
218 }
219
220 public function add( $item ) {
221 $target = 'add_' . $item->get_match_type();
222
223 if ( method_exists( $this, $target ) && $item->is_enabled() ) {
224 $this->$target( $item, $item->match );
225 }
226 }
227
228 public function get( $existing = false ) {
229 $text = $this->generate();
230
231 if ( $existing ) {
232 if ( preg_match( self::INSERT_REGEX, $existing ) > 0 ) {
233 $text = preg_replace( self::INSERT_REGEX, str_replace( '$', '\\$', $text ), $existing );
234 } else {
235 $text = $text . "\n" . trim( $existing );
236 }
237 }
238
239 return trim( $text );
240 }
241
242 public function sanitize_redirect( $text ) {
243 return str_replace( [ '<?', '>' ], '', $text );
244 }
245
246 public function sanitize_filename( $filename ) {
247 return str_replace( '.php', '', $filename );
248 }
249
250 public function save( $filename, $content_to_save = false ) {
251 $existing = false;
252 $filename = $this->sanitize_filename( $filename );
253
254 if ( file_exists( $filename ) ) {
255 $existing = file_get_contents( $filename );
256 }
257
258 $file = @fopen( $filename, 'w' );
259 if ( $file ) {
260 $result = fwrite( $file, $this->get( $existing ) );
261 fclose( $file );
262
263 return $result !== false;
264 }
265
266 return false;
267 }
268 }
269