PluginProbe
Redirection / 4.1
Redirection v4.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 / url-query.php

url-query.php in Redirection 4.1, at models/url-query.php

151 lines 4.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_Url_Query {
4 const RECURSION_LIMIT = 10;
5
6 private $query = [];
7
8 public function __construct( $url ) {
9 $this->query = $this->get_url_query( $url );
10 }
11
12 public function is_match( $url, Red_Source_Flags $flags ) {
13 $target = $this->get_url_query( $url );
14
15 // All params in the source have to exist in the request, but in any order
16 $matched = $this->get_query_same( $this->query, $target );
17
18 if ( count( $matched ) !== count( $this->query ) ) {
19 // Source params arent matched exactly
20 return false;
21 };
22
23 // Get list of whatever is left over
24 $query_diff = $this->get_query_diff( $this->query, $target );
25 $query_diff = array_merge( $query_diff, $this->get_query_diff( $target, $this->query ) );
26
27 if ( $flags->is_query_ignore() || $flags->is_query_pass() ) {
28 return true; // This ignores all other query params
29 }
30
31 // In an exact match there shouldn't be any more params
32 return count( $query_diff ) === 0;
33 }
34
35 /**
36 * Pass query params from one URL to another URL, ignoring any params that already exist on the target
37 *
38 * @param string $target_url The target URL to add params to
39 * @param string $requested_url The source URL to pass params from
40 * @param Red_Source_Flags $flags Any URL flags
41 * @return string URL, modified or not
42 */
43 public static function add_to_target( $target_url, $requested_url, Red_Source_Flags $flags ) {
44 if ( $flags->is_query_pass() && $target_url ) {
45 $source_query = new Red_Url_Query( $target_url );
46 $request_query = new Red_Url_Query( $requested_url );
47
48 // Now add any remaining params
49 $query_diff = $source_query->get_query_diff( $source_query->query, $request_query->query );
50 $query_diff = array_merge( $query_diff, $request_query->get_query_diff( $request_query->query, $source_query->query ) );
51
52 // Remove any params from $source that are present in $request - we dont allow
53 // predefined params to be overridden
54 foreach ( $query_diff as $key => $value ) {
55 if ( isset( $source_query->query[ $key ] ) ) {
56 unset( $query_diff[ $key ] );
57 }
58 }
59
60 $query = http_build_query( $query_diff );
61 $query = preg_replace( '@%5B\d*%5D@', '[]', $query ); // Make these look like []
62
63 if ( $query ) {
64 return $target_url . ( strpos( $target_url, '?' ) === false ? '?' : '&' ) . $query;
65 }
66 }
67
68 return $target_url;
69 }
70
71 public function get() {
72 return $this->query;
73 }
74
75 private function get_url_query( $url ) {
76 $params = [];
77 $query = $this->get_query_after( $url );
78
79 wp_parse_str( $query ? $query : '', $params );
80
81 return $params;
82 }
83
84 public function get_query_after( $url ) {
85 $qpos = strpos( $url, '?' );
86 $qrpos = strpos( $url, '\\?' );
87
88 if ( $qpos === false ) {
89 return '';
90 }
91
92 if ( $qrpos !== false && $qrpos < $qpos ) {
93 return substr( $url, $qrpos + strlen( $qrpos ) );
94 }
95
96 return substr( $url, $qpos + 1 );
97 }
98
99 public function get_query_same( array $source_query, array $target_query, $depth = 0 ) {
100 if ( $depth > self::RECURSION_LIMIT ) {
101 return [];
102 }
103
104 $same = [];
105 foreach ( $source_query as $key => $value ) {
106 if ( isset( $target_query[ $key ] ) ) {
107 $add = false;
108
109 if ( is_array( $value ) && is_array( $target_query[ $key ] ) ) {
110 $add = $this->get_query_same( $source_query[ $key ], $target_query[ $key ], $depth + 1 );
111
112 if ( count( $add ) !== count( $source_query[ $key ] ) ) {
113 $add = false;
114 }
115 } elseif ( is_string( $value ) && is_string( $target_query[ $key ] ) ) {
116 $add = $value === $target_query[ $key ] ? $value : false;
117 }
118
119 if ( ! empty( $add ) || $add === '' ) {
120 $same[ $key ] = $add;
121 }
122 }
123 }
124
125 return $same;
126 }
127
128 public function get_query_diff( array $source_query, array $target_query, $depth = 0 ) {
129 if ( $depth > self::RECURSION_LIMIT ) {
130 return [];
131 }
132
133 $diff = [];
134 foreach ( $source_query as $key => $value ) {
135 $found = false;
136
137 if ( isset( $target_query[ $key ] ) && is_array( $value ) && is_array( $target_query[ $key ] ) ) {
138 $add = $this->get_query_diff( $source_query[ $key ], $target_query[ $key ], $depth + 1 );
139
140 if ( ! empty( $add ) ) {
141 $diff[ $key ] = $add;
142 }
143 } elseif ( ! isset( $target_query[ $key ] ) || ! is_string( $value ) || ! is_string( $target_query[ $key ] ) || $target_query[ $key ] !== $source_query[ $key ] ) {
144 $diff[ $key ] = $value;
145 }
146 }
147
148 return $diff;
149 }
150 }
151