PluginProbe ʕ •ᴥ•ʔ
Secure Custom Fields / 6.8.6
Secure Custom Fields v6.8.6
6.9.5 6.9.4 6.9.3 6.9.2 6.9.1 6.9.0 6.8.9 6.8.7 6.8.8 6.8.6 6.8.4 6.8.5 trunk 6.4.0-beta1 6.4.0-beta2 6.4.1 6.4.1-beta3 6.4.1-beta4 6.4.1-beta5 6.4.1-beta6 6.4.1-beta7 6.4.2 6.5.0 6.5.1 6.5.2 6.5.3 6.5.4 6.5.5 6.5.6 6.5.7 6.6.0 6.7.0 6.7.1 6.8.0 6.8.1 6.8.2 6.8.3
secure-custom-fields / vendor / justinrainbow / json-schema / src / JsonSchema / Uri / UriRetriever.php
secure-custom-fields / vendor / justinrainbow / json-schema / src / JsonSchema / Uri Last commit date
Retrievers 9 months ago UriResolver.php 9 months ago UriRetriever.php 9 months ago
UriRetriever.php
350 lines
1 <?php
2
3 /*
4 * This file is part of the JsonSchema package.
5 *
6 * For the full copyright and license information, please view the LICENSE
7 * file that was distributed with this source code.
8 */
9
10 namespace JsonSchema\Uri;
11
12 use JsonSchema\Exception\InvalidSchemaMediaTypeException;
13 use JsonSchema\Exception\JsonDecodingException;
14 use JsonSchema\Exception\ResourceNotFoundException;
15 use JsonSchema\Uri\Retrievers\FileGetContents;
16 use JsonSchema\Uri\Retrievers\UriRetrieverInterface;
17 use JsonSchema\UriRetrieverInterface as BaseUriRetrieverInterface;
18 use JsonSchema\Validator;
19
20 /**
21 * Retrieves JSON Schema URIs
22 *
23 * @author Tyler Akins <fidian@rumkin.com>
24 */
25 class UriRetriever implements BaseUriRetrieverInterface
26 {
27 /**
28 * @var array Map of URL translations
29 */
30 protected $translationMap = array(
31 // use local copies of the spec schemas
32 '|^https?://json-schema.org/draft-(0[34])/schema#?|' => 'package://dist/schema/json-schema-draft-$1.json'
33 );
34
35 /**
36 * @var array A list of endpoints for media type check exclusion
37 */
38 protected $allowedInvalidContentTypeEndpoints = array(
39 'http://json-schema.org/',
40 'https://json-schema.org/'
41 );
42
43 /**
44 * @var null|UriRetrieverInterface
45 */
46 protected $uriRetriever = null;
47
48 /**
49 * @var array|object[]
50 *
51 * @see loadSchema
52 */
53 private $schemaCache = array();
54
55 /**
56 * Adds an endpoint to the media type validation exclusion list
57 *
58 * @param string $endpoint
59 */
60 public function addInvalidContentTypeEndpoint($endpoint)
61 {
62 $this->allowedInvalidContentTypeEndpoints[] = $endpoint;
63 }
64
65 /**
66 * Guarantee the correct media type was encountered
67 *
68 * @param UriRetrieverInterface $uriRetriever
69 * @param string $uri
70 *
71 * @return bool|void
72 */
73 public function confirmMediaType($uriRetriever, $uri)
74 {
75 $contentType = $uriRetriever->getContentType();
76
77 if (is_null($contentType)) {
78 // Well, we didn't get an invalid one
79 return;
80 }
81
82 if (in_array($contentType, array(Validator::SCHEMA_MEDIA_TYPE, 'application/json'))) {
83 return;
84 }
85
86 foreach ($this->allowedInvalidContentTypeEndpoints as $endpoint) {
87 if (strpos($uri, $endpoint) === 0) {
88 return true;
89 }
90 }
91
92 throw new InvalidSchemaMediaTypeException(sprintf('Media type %s expected', Validator::SCHEMA_MEDIA_TYPE));
93 }
94
95 /**
96 * Get a URI Retriever
97 *
98 * If none is specified, sets a default FileGetContents retriever and
99 * returns that object.
100 *
101 * @return UriRetrieverInterface
102 */
103 public function getUriRetriever()
104 {
105 if (is_null($this->uriRetriever)) {
106 $this->setUriRetriever(new FileGetContents());
107 }
108
109 return $this->uriRetriever;
110 }
111
112 /**
113 * Resolve a schema based on pointer
114 *
115 * URIs can have a fragment at the end in the format of
116 * #/path/to/object and we are to look up the 'path' property of
117 * the first object then the 'to' and 'object' properties.
118 *
119 * @param object $jsonSchema JSON Schema contents
120 * @param string $uri JSON Schema URI
121 *
122 * @throws ResourceNotFoundException
123 *
124 * @return object JSON Schema after walking down the fragment pieces
125 */
126 public function resolvePointer($jsonSchema, $uri)
127 {
128 $resolver = new UriResolver();
129 $parsed = $resolver->parse($uri);
130 if (empty($parsed['fragment'])) {
131 return $jsonSchema;
132 }
133
134 $path = explode('/', $parsed['fragment']);
135 while ($path) {
136 $pathElement = array_shift($path);
137 if (!empty($pathElement)) {
138 $pathElement = str_replace('~1', '/', $pathElement);
139 $pathElement = str_replace('~0', '~', $pathElement);
140 if (!empty($jsonSchema->$pathElement)) {
141 $jsonSchema = $jsonSchema->$pathElement;
142 } else {
143 throw new ResourceNotFoundException(
144 'Fragment "' . $parsed['fragment'] . '" not found'
145 . ' in ' . $uri
146 );
147 }
148
149 if (!is_object($jsonSchema)) {
150 throw new ResourceNotFoundException(
151 'Fragment part "' . $pathElement . '" is no object '
152 . ' in ' . $uri
153 );
154 }
155 }
156 }
157
158 return $jsonSchema;
159 }
160
161 /**
162 * {@inheritdoc}
163 */
164 public function retrieve($uri, $baseUri = null, $translate = true)
165 {
166 $resolver = new UriResolver();
167 $resolvedUri = $fetchUri = $resolver->resolve($uri, $baseUri);
168
169 //fetch URL without #fragment
170 $arParts = $resolver->parse($resolvedUri);
171 if (isset($arParts['fragment'])) {
172 unset($arParts['fragment']);
173 $fetchUri = $resolver->generate($arParts);
174 }
175
176 // apply URI translations
177 if ($translate) {
178 $fetchUri = $this->translate($fetchUri);
179 }
180
181 $jsonSchema = $this->loadSchema($fetchUri);
182
183 // Use the JSON pointer if specified
184 $jsonSchema = $this->resolvePointer($jsonSchema, $resolvedUri);
185
186 if ($jsonSchema instanceof \stdClass) {
187 $jsonSchema->id = $resolvedUri;
188 }
189
190 return $jsonSchema;
191 }
192
193 /**
194 * Fetch a schema from the given URI, json-decode it and return it.
195 * Caches schema objects.
196 *
197 * @param string $fetchUri Absolute URI
198 *
199 * @return object JSON schema object
200 */
201 protected function loadSchema($fetchUri)
202 {
203 if (isset($this->schemaCache[$fetchUri])) {
204 return $this->schemaCache[$fetchUri];
205 }
206
207 $uriRetriever = $this->getUriRetriever();
208 $contents = $this->uriRetriever->retrieve($fetchUri);
209 $this->confirmMediaType($uriRetriever, $fetchUri);
210 $jsonSchema = json_decode($contents);
211
212 if (JSON_ERROR_NONE < $error = json_last_error()) {
213 throw new JsonDecodingException($error);
214 }
215
216 $this->schemaCache[$fetchUri] = $jsonSchema;
217
218 return $jsonSchema;
219 }
220
221 /**
222 * Set the URI Retriever
223 *
224 * @param UriRetrieverInterface $uriRetriever
225 *
226 * @return $this for chaining
227 */
228 public function setUriRetriever(UriRetrieverInterface $uriRetriever)
229 {
230 $this->uriRetriever = $uriRetriever;
231
232 return $this;
233 }
234
235 /**
236 * Parses a URI into five main components
237 *
238 * @param string $uri
239 *
240 * @return array
241 */
242 public function parse($uri)
243 {
244 preg_match('|^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?|', $uri, $match);
245
246 $components = array();
247 if (5 < count($match)) {
248 $components = array(
249 'scheme' => $match[2],
250 'authority' => $match[4],
251 'path' => $match[5]
252 );
253 }
254
255 if (7 < count($match)) {
256 $components['query'] = $match[7];
257 }
258
259 if (9 < count($match)) {
260 $components['fragment'] = $match[9];
261 }
262
263 return $components;
264 }
265
266 /**
267 * Builds a URI based on n array with the main components
268 *
269 * @param array $components
270 *
271 * @return string
272 */
273 public function generate(array $components)
274 {
275 $uri = $components['scheme'] . '://'
276 . $components['authority']
277 . $components['path'];
278
279 if (array_key_exists('query', $components)) {
280 $uri .= $components['query'];
281 }
282
283 if (array_key_exists('fragment', $components)) {
284 $uri .= $components['fragment'];
285 }
286
287 return $uri;
288 }
289
290 /**
291 * Resolves a URI
292 *
293 * @param string $uri Absolute or relative
294 * @param string $baseUri Optional base URI
295 *
296 * @return string
297 */
298 public function resolve($uri, $baseUri = null)
299 {
300 $components = $this->parse($uri);
301 $path = $components['path'];
302
303 if ((array_key_exists('scheme', $components)) && ('http' === $components['scheme'])) {
304 return $uri;
305 }
306
307 $baseComponents = $this->parse($baseUri);
308 $basePath = $baseComponents['path'];
309
310 $baseComponents['path'] = UriResolver::combineRelativePathWithBasePath($path, $basePath);
311
312 return $this->generate($baseComponents);
313 }
314
315 /**
316 * @param string $uri
317 *
318 * @return bool
319 */
320 public function isValid($uri)
321 {
322 $components = $this->parse($uri);
323
324 return !empty($components);
325 }
326
327 /**
328 * Set a URL translation rule
329 */
330 public function setTranslation($from, $to)
331 {
332 $this->translationMap[$from] = $to;
333 }
334
335 /**
336 * Apply URI translation rules
337 */
338 public function translate($uri)
339 {
340 foreach ($this->translationMap as $from => $to) {
341 $uri = preg_replace($from, $to, $uri);
342 }
343
344 // translate references to local files within the json-schema package
345 $uri = preg_replace('|^package://|', sprintf('file://%s/', realpath(__DIR__ . '/../../..')), $uri);
346
347 return $uri;
348 }
349 }
350