PluginProbe ʕ •ᴥ•ʔ
ShareThis Dashboard for Google Analytics / 3.2.0
ShareThis Dashboard for Google Analytics v3.2.0
3.3.2 trunk 1.0.7 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.1 2.1.2 2.1.3 2.1.4 2.1.5 2.2.5 2.3.5 2.3.6 2.3.7 2.3.8 2.4.0 2.4.1 2.5.0 2.5.1 2.5.2 2.5.3 2.5.4 2.5.5 3.0.0 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.2.0 3.2.1 3.2.2 3.2.3 3.2.4 3.3.0 3.3.1
googleanalytics / lib / analytics-admin / vendor / google / apiclient / src / Utils / UriTemplate.php
googleanalytics / lib / analytics-admin / vendor / google / apiclient / src / Utils Last commit date
UriTemplate.php 3 years ago
UriTemplate.php
335 lines
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 namespace Google\Utils;
19
20 /**
21 * Implementation of levels 1-3 of the URI Template spec.
22 * @see http://tools.ietf.org/html/rfc6570
23 */
24 class UriTemplate
25 {
26 const TYPE_MAP = "1";
27 const TYPE_LIST = "2";
28 const TYPE_SCALAR = "4";
29
30 /**
31 * @var array $operators
32 * These are valid at the start of a template block to
33 * modify the way in which the variables inside are
34 * processed.
35 */
36 private $operators = [
37 "+" => "reserved",
38 "/" => "segments",
39 "." => "dotprefix",
40 "#" => "fragment",
41 ";" => "semicolon",
42 "?" => "form",
43 "&" => "continuation"
44 ];
45
46 /**
47 * @var array<string>
48 * These are the characters which should not be URL encoded in reserved
49 * strings.
50 */
51 private $reserved = [
52 "=", ",", "!", "@", "|", ":", "/", "?", "#",
53 "[", "]", '$', "&", "'", "(", ")", "*", "+", ";"
54 ];
55 private $reservedEncoded = [
56 "%3D", "%2C", "%21", "%40", "%7C", "%3A", "%2F", "%3F",
57 "%23", "%5B", "%5D", "%24", "%26", "%27", "%28", "%29",
58 "%2A", "%2B", "%3B"
59 ];
60
61 public function parse($string, array $parameters)
62 {
63 return $this->resolveNextSection($string, $parameters);
64 }
65
66 /**
67 * This function finds the first matching {...} block and
68 * executes the replacement. It then calls itself to find
69 * subsequent blocks, if any.
70 */
71 private function resolveNextSection($string, $parameters)
72 {
73 $start = strpos($string, "{");
74 if ($start === false) {
75 return $string;
76 }
77 $end = strpos($string, "}");
78 if ($end === false) {
79 return $string;
80 }
81 $string = $this->replace($string, $start, $end, $parameters);
82 return $this->resolveNextSection($string, $parameters);
83 }
84
85 private function replace($string, $start, $end, $parameters)
86 {
87 // We know a data block will have {} round it, so we can strip that.
88 $data = substr($string, $start + 1, $end - $start - 1);
89
90 // If the first character is one of the reserved operators, it effects
91 // the processing of the stream.
92 if (isset($this->operators[$data[0]])) {
93 $op = $this->operators[$data[0]];
94 $data = substr($data, 1);
95 $prefix = "";
96 $prefix_on_missing = false;
97
98 switch ($op) {
99 case "reserved":
100 // Reserved means certain characters should not be URL encoded
101 $data = $this->replaceVars($data, $parameters, ",", null, true);
102 break;
103 case "fragment":
104 // Comma separated with fragment prefix. Bare values only.
105 $prefix = "#";
106 $prefix_on_missing = true;
107 $data = $this->replaceVars($data, $parameters, ",", null, true);
108 break;
109 case "segments":
110 // Slash separated data. Bare values only.
111 $prefix = "/";
112 $data =$this->replaceVars($data, $parameters, "/");
113 break;
114 case "dotprefix":
115 // Dot separated data. Bare values only.
116 $prefix = ".";
117 $prefix_on_missing = true;
118 $data = $this->replaceVars($data, $parameters, ".");
119 break;
120 case "semicolon":
121 // Semicolon prefixed and separated. Uses the key name
122 $prefix = ";";
123 $data = $this->replaceVars($data, $parameters, ";", "=", false, true, false);
124 break;
125 case "form":
126 // Standard URL format. Uses the key name
127 $prefix = "?";
128 $data = $this->replaceVars($data, $parameters, "&", "=");
129 break;
130 case "continuation":
131 // Standard URL, but with leading ampersand. Uses key name.
132 $prefix = "&";
133 $data = $this->replaceVars($data, $parameters, "&", "=");
134 break;
135 }
136
137 // Add the initial prefix character if data is valid.
138 if ($data || ($data !== false && $prefix_on_missing)) {
139 $data = $prefix . $data;
140 }
141 } else {
142 // If no operator we replace with the defaults.
143 $data = $this->replaceVars($data, $parameters);
144 }
145 // This is chops out the {...} and replaces with the new section.
146 return substr($string, 0, $start) . $data . substr($string, $end + 1);
147 }
148
149 private function replaceVars(
150 $section,
151 $parameters,
152 $sep = ",",
153 $combine = null,
154 $reserved = false,
155 $tag_empty = false,
156 $combine_on_empty = true
157 ) {
158 if (strpos($section, ",") === false) {
159 // If we only have a single value, we can immediately process.
160 return $this->combine(
161 $section,
162 $parameters,
163 $sep,
164 $combine,
165 $reserved,
166 $tag_empty,
167 $combine_on_empty
168 );
169 } else {
170 // If we have multiple values, we need to split and loop over them.
171 // Each is treated individually, then glued together with the
172 // separator character.
173 $vars = explode(",", $section);
174 return $this->combineList(
175 $vars,
176 $sep,
177 $parameters,
178 $combine,
179 $reserved,
180 false, // Never emit empty strings in multi-param replacements
181 $combine_on_empty
182 );
183 }
184 }
185
186 public function combine(
187 $key,
188 $parameters,
189 $sep,
190 $combine,
191 $reserved,
192 $tag_empty,
193 $combine_on_empty
194 ) {
195 $length = false;
196 $explode = false;
197 $skip_final_combine = false;
198 $value = false;
199
200 // Check for length restriction.
201 if (strpos($key, ":") !== false) {
202 list($key, $length) = explode(":", $key);
203 }
204
205 // Check for explode parameter.
206 if ($key[strlen($key) - 1] == "*") {
207 $explode = true;
208 $key = substr($key, 0, -1);
209 $skip_final_combine = true;
210 }
211
212 // Define the list separator.
213 $list_sep = $explode ? $sep : ",";
214
215 if (isset($parameters[$key])) {
216 $data_type = $this->getDataType($parameters[$key]);
217 switch ($data_type) {
218 case self::TYPE_SCALAR:
219 $value = $this->getValue($parameters[$key], $length);
220 break;
221 case self::TYPE_LIST:
222 $values = [];
223 foreach ($parameters[$key] as $pkey => $pvalue) {
224 $pvalue = $this->getValue($pvalue, $length);
225 if ($combine && $explode) {
226 $values[$pkey] = $key . $combine . $pvalue;
227 } else {
228 $values[$pkey] = $pvalue;
229 }
230 }
231 $value = implode($list_sep, $values);
232 if ($value == '') {
233 return '';
234 }
235 break;
236 case self::TYPE_MAP:
237 $values = [];
238 foreach ($parameters[$key] as $pkey => $pvalue) {
239 $pvalue = $this->getValue($pvalue, $length);
240 if ($explode) {
241 $pkey = $this->getValue($pkey, $length);
242 $values[] = $pkey . "=" . $pvalue; // Explode triggers = combine.
243 } else {
244 $values[] = $pkey;
245 $values[] = $pvalue;
246 }
247 }
248 $value = implode($list_sep, $values);
249 if ($value == '') {
250 return false;
251 }
252 break;
253 }
254 } elseif ($tag_empty) {
255 // If we are just indicating empty values with their key name, return that.
256 return $key;
257 } else {
258 // Otherwise we can skip this variable due to not being defined.
259 return false;
260 }
261
262 if ($reserved) {
263 $value = str_replace($this->reservedEncoded, $this->reserved, $value);
264 }
265
266 // If we do not need to include the key name, we just return the raw
267 // value.
268 if (!$combine || $skip_final_combine) {
269 return $value;
270 }
271
272 // Else we combine the key name: foo=bar, if value is not the empty string.
273 return $key . ($value != '' || $combine_on_empty ? $combine . $value : '');
274 }
275
276 /**
277 * Return the type of a passed in value
278 */
279 private function getDataType($data)
280 {
281 if (is_array($data)) {
282 reset($data);
283 if (key($data) !== 0) {
284 return self::TYPE_MAP;
285 }
286 return self::TYPE_LIST;
287 }
288 return self::TYPE_SCALAR;
289 }
290
291 /**
292 * Utility function that merges multiple combine calls
293 * for multi-key templates.
294 */
295 private function combineList(
296 $vars,
297 $sep,
298 $parameters,
299 $combine,
300 $reserved,
301 $tag_empty,
302 $combine_on_empty
303 ) {
304 $ret = [];
305 foreach ($vars as $var) {
306 $response = $this->combine(
307 $var,
308 $parameters,
309 $sep,
310 $combine,
311 $reserved,
312 $tag_empty,
313 $combine_on_empty
314 );
315 if ($response === false) {
316 continue;
317 }
318 $ret[] = $response;
319 }
320 return implode($sep, $ret);
321 }
322
323 /**
324 * Utility function to encode and trim values
325 */
326 private function getValue($value, $length)
327 {
328 if ($length) {
329 $value = substr($value, 0, $length);
330 }
331 $value = rawurlencode($value);
332 return $value;
333 }
334 }
335