PluginProbe
Analytify – Analytics Dashboard for WordPress (Google Analytics 4) / 1.0.3
Analytify – Analytics Dashboard for WordPress (Google Analytics 4) v1.0.3
9.1.2 9.1.1 9.1.0 9.0.2 9.0.1 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.1.0 1.1.1 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.3.0 1.3.1 1.3.2 All 153 releases
wp-analytify / lib / Google / Utils / URITemplate.php

URITemplate.php in Analytify – Analytics Dashboard for WordPress (Google Analytics 4) 1.0.3, at lib/Google/Utils/URITemplate.php

334 lines 9.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 * Copyright 2013 Google Inc.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 /**
19 * Implementation of levels 1-3 of the URI Template spec.
20 * @see http://tools.ietf.org/html/rfc6570
21 */
22 class Analytify_Google_Utils_URITemplate
23 {
24 const TYPE_MAP = "1";
25 const TYPE_LIST = "2";
26 const TYPE_SCALAR = "4";
27
28 /**
29 * @var $operators array
30 * These are valid at the start of a template block to
31 * modify the way in which the variables inside are
32 * processed.
33 */
34 private $operators = array(
35 "+" => "reserved",
36 "/" => "segments",
37 "." => "dotprefix",
38 "#" => "fragment",
39 ";" => "semicolon",
40 "?" => "form",
41 "&" => "continuation"
42 );
43
44 /**
45 * @var reserved array
46 * These are the characters which should not be URL encoded in reserved
47 * strings.
48 */
49 private $reserved = array(
50 "=", ",", "!", "@", "|", ":", "/", "?", "#",
51 "[", "]",'$', "&", "'", "(", ")", "*", "+", ";"
52 );
53 private $reservedEncoded = array(
54 "%3D", "%2C", "%21", "%40", "%7C", "%3A", "%2F", "%3F",
55 "%23", "%5B", "%5D", "%24", "%26", "%27", "%28", "%29",
56 "%2A", "%2B", "%3B"
57 );
58
59 public function parse($string, array $parameters)
60 {
61 return $this->resolveNextSection($string, $parameters);
62 }
63
64 /**
65 * This function finds the first matching {...} block and
66 * executes the replacement. It then calls itself to find
67 * subsequent blocks, if any.
68 */
69 private function resolveNextSection($string, $parameters)
70 {
71 $start = strpos($string, "{");
72 if ($start === false) {
73 return $string;
74 }
75 $end = strpos($string, "}");
76 if ($end === false) {
77 return $string;
78 }
79 $string = $this->replace($string, $start, $end, $parameters);
80 return $this->resolveNextSection($string, $parameters);
81 }
82
83 private function replace($string, $start, $end, $parameters)
84 {
85 // We know a data block will have {} round it, so we can strip that.
86 $data = substr($string, $start + 1, $end - $start - 1);
87
88 // If the first character is one of the reserved operators, it effects
89 // the processing of the stream.
90 if (isset($this->operators[$data[0]])) {
91 $op = $this->operators[$data[0]];
92 $data = substr($data, 1);
93 $prefix = "";
94 $prefix_on_missing = false;
95
96 switch ($op) {
97 case "reserved":
98 // Reserved means certain characters should not be URL encoded
99 $data = $this->replaceVars($data, $parameters, ",", null, true);
100 break;
101 case "fragment":
102 // Comma separated with fragment prefix. Bare values only.
103 $prefix = "#";
104 $prefix_on_missing = true;
105 $data = $this->replaceVars($data, $parameters, ",", null, true);
106 break;
107 case "segments":
108 // Slash separated data. Bare values only.
109 $prefix = "/";
110 $data =$this->replaceVars($data, $parameters, "/");
111 break;
112 case "dotprefix":
113 // Dot separated data. Bare values only.
114 $prefix = ".";
115 $prefix_on_missing = true;
116 $data = $this->replaceVars($data, $parameters, ".");
117 break;
118 case "semicolon":
119 // Semicolon prefixed and separated. Uses the key name
120 $prefix = ";";
121 $data = $this->replaceVars($data, $parameters, ";", "=", false, true, false);
122 break;
123 case "form":
124 // Standard URL format. Uses the key name
125 $prefix = "?";
126 $data = $this->replaceVars($data, $parameters, "&", "=");
127 break;
128 case "continuation":
129 // Standard URL, but with leading ampersand. Uses key name.
130 $prefix = "&";
131 $data = $this->replaceVars($data, $parameters, "&", "=");
132 break;
133 }
134
135 // Add the initial prefix character if data is valid.
136 if ($data || ($data !== false && $prefix_on_missing)) {
137 $data = $prefix . $data;
138 }
139
140 } else {
141 // If no operator we replace with the defaults.
142 $data = $this->replaceVars($data, $parameters);
143 }
144 // This is chops out the {...} and replaces with the new section.
145 return substr($string, 0, $start) . $data . substr($string, $end + 1);
146 }
147
148 private function replaceVars(
149 $section,
150 $parameters,
151 $sep = ",",
152 $combine = null,
153 $reserved = false,
154 $tag_empty = false,
155 $combine_on_empty = true
156 ) {
157 if (strpos($section, ",") === false) {
158 // If we only have a single value, we can immediately process.
159 return $this->combine(
160 $section,
161 $parameters,
162 $sep,
163 $combine,
164 $reserved,
165 $tag_empty,
166 $combine_on_empty
167 );
168 } else {
169 // If we have multiple values, we need to split and loop over them.
170 // Each is treated individually, then glued together with the
171 // separator character.
172 $vars = explode(",", $section);
173 return $this->combineList(
174 $vars,
175 $sep,
176 $parameters,
177 $combine,
178 $reserved,
179 false, // Never emit empty strings in multi-param replacements
180 $combine_on_empty
181 );
182 }
183 }
184
185 public function combine(
186 $key,
187 $parameters,
188 $sep,
189 $combine,
190 $reserved,
191 $tag_empty,
192 $combine_on_empty
193 ) {
194 $length = false;
195 $explode = false;
196 $skip_final_combine = false;
197 $value = false;
198
199 // Check for length restriction.
200 if (strpos($key, ":") !== false) {
201 list($key, $length) = explode(":", $key);
202 }
203
204 // Check for explode parameter.
205 if ($key[strlen($key) - 1] == "*") {
206 $explode = true;
207 $key = substr($key, 0, -1);
208 $skip_final_combine = true;
209 }
210
211 // Define the list separator.
212 $list_sep = $explode ? $sep : ",";
213
214 if (isset($parameters[$key])) {
215 $data_type = $this->getDataType($parameters[$key]);
216 switch($data_type) {
217 case self::TYPE_SCALAR:
218 $value = $this->getValue($parameters[$key], $length);
219 break;
220 case self::TYPE_LIST:
221 $values = array();
222 foreach ($parameters[$key] as $pkey => $pvalue) {
223 $pvalue = $this->getValue($pvalue, $length);
224 if ($combine && $explode) {
225 $values[$pkey] = $key . $combine . $pvalue;
226 } else {
227 $values[$pkey] = $pvalue;
228 }
229 }
230 $value = implode($list_sep, $values);
231 if ($value == '') {
232 return '';
233 }
234 break;
235 case self::TYPE_MAP:
236 $values = array();
237 foreach ($parameters[$key] as $pkey => $pvalue) {
238 $pvalue = $this->getValue($pvalue, $length);
239 if ($explode) {
240 $pkey = $this->getValue($pkey, $length);
241 $values[] = $pkey . "=" . $pvalue; // Explode triggers = combine.
242 } else {
243 $values[] = $pkey;
244 $values[] = $pvalue;
245 }
246 }
247 $value = implode($list_sep, $values);
248 if ($value == '') {
249 return false;
250 }
251 break;
252 }
253 } else if ($tag_empty) {
254 // If we are just indicating empty values with their key name, return that.
255 return $key;
256 } else {
257 // Otherwise we can skip this variable due to not being defined.
258 return false;
259 }
260
261 if ($reserved) {
262 $value = str_replace($this->reservedEncoded, $this->reserved, $value);
263 }
264
265 // If we do not need to include the key name, we just return the raw
266 // value.
267 if (!$combine || $skip_final_combine) {
268 return $value;
269 }
270
271 // Else we combine the key name: foo=bar, if value is not the empty string.
272 return $key . ($value != '' || $combine_on_empty ? $combine . $value : '');
273 }
274
275 /**
276 * Return the type of a passed in value
277 */
278 private function getDataType($data)
279 {
280 if (is_array($data)) {
281 reset($data);
282 if (key($data) !== 0) {
283 return self::TYPE_MAP;
284 }
285 return self::TYPE_LIST;
286 }
287 return self::TYPE_SCALAR;
288 }
289
290 /**
291 * Utility function that merges multiple combine calls
292 * for multi-key templates.
293 */
294 private function combineList(
295 $vars,
296 $sep,
297 $parameters,
298 $combine,
299 $reserved,
300 $tag_empty,
301 $combine_on_empty
302 ) {
303 $ret = array();
304 foreach ($vars as $var) {
305 $response = $this->combine(
306 $var,
307 $parameters,
308 $sep,
309 $combine,
310 $reserved,
311 $tag_empty,
312 $combine_on_empty
313 );
314 if ($response === false) {
315 continue;
316 }
317 $ret[] = $response;
318 }
319 return implode($sep, $ret);
320 }
321
322 /**
323 * Utility function to encode and trim values
324 */
325 private function getValue($value, $length)
326 {
327 if ($length) {
328 $value = substr($value, 0, $length);
329 }
330 $value = rawurlencode($value);
331 return $value;
332 }
333 }
334