PluginProbe
Redirection / 5.9.0
Redirection v5.9.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 / match.php

match.php in Redirection 5.9.0, at models/match.php

258 lines 6.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 require_once dirname( __DIR__ ) . '/matches/from-notfrom.php';
4 require_once dirname( __DIR__ ) . '/matches/from-url.php';
5
6 /**
7 * Matches a URL and some other condition
8 *
9 * @phpstan-template TSaveDetails of array<string, mixed>
10 * @phpstan-template-covariant TSaveResult of (array<string, mixed>|string)
11 *
12 * @phpstan-type RedMatchUrlData array{
13 * url: string
14 * }
15 * @phpstan-type RedMatchAgentData array{
16 * agent: string,
17 * regex: bool,
18 * url_from: string,
19 * url_notfrom: string
20 * }
21 * @phpstan-type RedMatchReferrerData array{
22 * referrer: string,
23 * regex: bool,
24 * url_from: string,
25 * url_notfrom: string
26 * }
27 * @phpstan-type RedMatchHeaderData array{
28 * name: string,
29 * value: string,
30 * regex: bool,
31 * url_from: string,
32 * url_notfrom: string
33 * }
34 * @phpstan-type RedMatchCookieData array{
35 * name: string,
36 * value: string,
37 * regex: bool,
38 * url_from: string,
39 * url_notfrom: string
40 * }
41 * @phpstan-type RedMatchCustomData array{
42 * filter: string,
43 * url_from: string,
44 * url_notfrom: string
45 * }
46 * @phpstan-type RedMatchRoleData array{
47 * role: string,
48 * url_from: string,
49 * url_notfrom: string
50 * }
51 * @phpstan-type RedMatchServerData array{
52 * server: string,
53 * url_from: string,
54 * url_notfrom: string
55 * }
56 * @phpstan-type RedMatchIpData array{
57 * ip: string[],
58 * url_from: string,
59 * url_notfrom: string
60 * }
61 * @phpstan-type RedMatchPageData array{
62 * page: string,
63 * url: string
64 * }
65 * @phpstan-type RedMatchLanguageData array{
66 * language: string,
67 * url_from: string,
68 * url_notfrom: string
69 * }
70 * @phpstan-type RedMatchLoginData array{
71 * logged_in: string,
72 * logged_out: string
73 * }
74 * @phpstan-type RedMatchData RedMatchUrlData|RedMatchAgentData|RedMatchReferrerData|RedMatchHeaderData|RedMatchCookieData|RedMatchCustomData|RedMatchRoleData|RedMatchServerData|RedMatchIpData|RedMatchPageData|RedMatchLanguageData|RedMatchLoginData
75 */
76 abstract class Red_Match {
77 /**
78 * Match type
79 *
80 * @var string
81 */
82 protected $type = '';
83
84 /**
85 * Constructor
86 *
87 * @param RedMatchData|string $values Initial values.
88 */
89 public function __construct( $values = '' ) {
90 if ( $values !== '' ) {
91 $this->load( $values );
92 }
93 }
94
95 /**
96 * Get match type
97 *
98 * @return string
99 */
100 public function get_type() {
101 return $this->type;
102 }
103
104 /**
105 * Save the match
106 *
107 * @phpstan-param TSaveDetails $details Details to save.
108 * @param array<string, mixed> $details Details to save.
109 * @param boolean $no_target_url The URL when no target.
110 * @phpstan-return TSaveResult|null
111 * @return array<string, mixed>|string|null
112 */
113 abstract public function save( array $details, $no_target_url = false );
114
115 /**
116 * Get the match name
117 *
118 * @return string
119 */
120 abstract public function name();
121
122 /**
123 * Match the URL against the specific matcher conditions
124 *
125 * @param string $url Requested URL.
126 * @return boolean
127 */
128 abstract public function is_match( $url );
129
130 /**
131 * Get the target URL for this match. Some matches may have a matched/unmatched target.
132 *
133 * @param string $original_url The client URL (not decoded).
134 * @param string $matched_url The URL in the redirect.
135 * @param Red_Source_Flags $flag Source flags.
136 * @param boolean $is_matched Was the match successful.
137 * @return string|false
138 */
139 abstract public function get_target_url( $original_url, $matched_url, Red_Source_Flags $flag, $is_matched );
140
141 /**
142 * Get the match data
143 *
144 * @return RedMatchData|null
145 */
146 abstract public function get_data();
147
148 /**
149 * Load the match data into this instance.
150 *
151 * @param RedMatchData|string $values Match values, as read from the database (plain text or serialized PHP).
152 * @return void
153 */
154 abstract public function load( $values );
155
156 /**
157 * Sanitize a match URL
158 *
159 * @param string $url URL.
160 * @return string
161 */
162 public function sanitize_url( $url ) {
163 // No new lines
164 $url = (string) preg_replace( "/[\r\n\t].*?$/s", '', $url );
165
166 // Clean control codes
167 $url = (string) preg_replace( '/[^\PC\s]/u', '', $url );
168
169 return $url;
170 }
171
172 /**
173 * Apply a regular expression to the target URL, replacing any values.
174 *
175 * @param string $source_url Redirect source URL.
176 * @param string $target_url Target URL.
177 * @param string $requested_url The URL being requested (decoded).
178 * @param Red_Source_Flags $flags Source URL flags.
179 * @return string
180 */
181 protected function get_target_regex_url( $source_url, $target_url, $requested_url, Red_Source_Flags $flags ) {
182 $regex = new Red_Regex( $source_url, $flags->is_ignore_case() );
183
184 return $regex->replace( $target_url, $requested_url );
185 }
186
187 /**
188 * Create a Red_Match object, given a type
189 *
190 * @param string $name Match type.
191 * @param RedMatchData|string $data Match data.
192 * @return Red_Match<array<string, mixed>, (array<string, mixed>|string)>|null
193 */
194 public static function create( $name, $data = '' ) {
195 $avail = self::available();
196 if ( isset( $avail[ strtolower( $name ) ] ) ) {
197 $classname = $name . '_match';
198
199 /** @var class-string<Red_Match<array<string, mixed>, (array<string, mixed>|string)>> $classname */
200 if ( ! class_exists( strtolower( $classname ) ) ) {
201 include __DIR__ . '/../matches/' . $avail[ strtolower( $name ) ];
202 }
203
204 /**
205 * @var Red_Match<array<string, mixed>, (array<string, mixed>|string)>
206 */
207 $class = new $classname( $data );
208 $class->type = $name;
209 return $class;
210 }
211
212 return null;
213 }
214
215 /**
216 * Get all Red_Match objects
217 *
218 * @return array<string, string>
219 */
220 public static function all() {
221 $data = [];
222
223 $avail = self::available();
224 foreach ( array_keys( $avail ) as $name ) {
225 /** @var Red_Match<array<string, mixed>, (array<string, mixed>|string)>|null $obj */
226 $obj = self::create( $name );
227 if ( $obj === null ) {
228 continue;
229 }
230 $data[ $name ] = $obj->name();
231 }
232
233 return $data;
234 }
235
236 /**
237 * Get list of available matches
238 *
239 * @return array<string, string>
240 */
241 public static function available() {
242 return [
243 'url' => 'url.php',
244 'referrer' => 'referrer.php',
245 'agent' => 'user-agent.php',
246 'login' => 'login.php',
247 'header' => 'http-header.php',
248 'custom' => 'custom-filter.php',
249 'cookie' => 'cookie.php',
250 'role' => 'user-role.php',
251 'server' => 'server.php',
252 'ip' => 'ip.php',
253 'page' => 'page.php',
254 'language' => 'language.php',
255 ];
256 }
257 }
258