forked from friendica/php-json-ld
Add relative @context URL resolution.
This commit is contained in:
parent
ef8769fe5a
commit
7b20e349af
115
jsonld.php
115
jsonld.php
|
@ -214,7 +214,71 @@ function jsonld_unregister_rdf_parser($content_type) {
|
||||||
if(property_exists($jsonld_rdf_parsers, $content_type)) {
|
if(property_exists($jsonld_rdf_parsers, $content_type)) {
|
||||||
unset($jsonld_rdf_parsers->{$content_type});
|
unset($jsonld_rdf_parsers->{$content_type});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a relative path into an absolute URL.
|
||||||
|
*
|
||||||
|
* @param string $path the relative path.
|
||||||
|
* @param string $url the absolute URL base.
|
||||||
|
*
|
||||||
|
* @return string the absolute URL for the given relative path.
|
||||||
|
*/
|
||||||
|
function jsonld_to_absolute_url($path, $url) {
|
||||||
|
// validate path (it may already be an absolute URL)
|
||||||
|
if(filter_var($path, FILTER_VALIDATE_URL) === false) {
|
||||||
|
$url = parse_url($url);
|
||||||
|
$rval = "{$url['scheme']}://";
|
||||||
|
|
||||||
|
if(isset($url['user']) || isset($url['pass'])) {
|
||||||
|
$rval .= "{$url['user']}:{$url['pass']}@";
|
||||||
|
}
|
||||||
|
|
||||||
|
$rval .= $url['host'];
|
||||||
|
if(isset($url['port'])) {
|
||||||
|
$rval .= ":{$url['port']}";
|
||||||
|
}
|
||||||
|
|
||||||
|
$rval .= jsonld_prepend_base($url['path'], $path);
|
||||||
|
if(strrpos($rval, '?') === false && isset($url['query'])) {
|
||||||
|
$rval .= "?{$url['query']}";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strrpos($rval, '#') === false && isset($url['fragment'])) {
|
||||||
|
$rval .= "#{$url['fragment']}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$rval = $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate result
|
||||||
|
if(filter_var($rval, FILTER_VALIDATE_URL) === false) {
|
||||||
|
throw new JsonLdException(
|
||||||
|
'Malformed URL.', 'jsonld.InvalidUrl', array('url' => $rval));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepend a relative IRI to a base IRI.
|
||||||
|
*
|
||||||
|
* @param string $base the base IRI.
|
||||||
|
* @param string $iri the relative IRI.
|
||||||
|
*/
|
||||||
|
function jsonld_prepend_base($base, $iri) {
|
||||||
|
if($iri === '' || strpos($iri, '#') === 0) {
|
||||||
|
return "$base$iri";
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepend last directory for base
|
||||||
|
$idx = strrpos($base, '/');
|
||||||
|
if($idx === false) {
|
||||||
|
return $iri;
|
||||||
|
}
|
||||||
|
return substr($base, 0, $idx + 1) . $iri;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A JSON-LD processor.
|
* A JSON-LD processor.
|
||||||
|
@ -376,7 +440,8 @@ class JsonLdProcessor {
|
||||||
// resolve all @context URLs in the input
|
// resolve all @context URLs in the input
|
||||||
$input = self::copy($input);
|
$input = self::copy($input);
|
||||||
try {
|
try {
|
||||||
$this->_resolveContextUrls($input, new stdClass(), $options['resolver']);
|
$this->_resolveContextUrls(
|
||||||
|
$input, new stdClass(), $options['resolver'], $options['base']);
|
||||||
}
|
}
|
||||||
catch(Exception $e) {
|
catch(Exception $e) {
|
||||||
throw new JsonLdException(
|
throw new JsonLdException(
|
||||||
|
@ -627,7 +692,8 @@ class JsonLdProcessor {
|
||||||
$ctx = (object)array('@context' => $ctx);
|
$ctx = (object)array('@context' => $ctx);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
$this->_resolveContextUrls($ctx, new stdClass(), $options['resolver']);
|
$this->_resolveContextUrls(
|
||||||
|
$ctx, new stdClass(), $options['resolver'], $options['base']);
|
||||||
}
|
}
|
||||||
catch(Exception $e) {
|
catch(Exception $e) {
|
||||||
throw new JsonLdException(
|
throw new JsonLdException(
|
||||||
|
@ -3534,18 +3600,19 @@ class JsonLdProcessor {
|
||||||
* @param mixed $input the JSON-LD input.
|
* @param mixed $input the JSON-LD input.
|
||||||
* @param stdClass $urls a map of URLs (url => false/@contexts).
|
* @param stdClass $urls a map of URLs (url => false/@contexts).
|
||||||
* @param bool $replace true to replace the URLs in the given input with
|
* @param bool $replace true to replace the URLs in the given input with
|
||||||
* the @contexts from the urls map, false not to.
|
* the @contexts from the urls map, false not to.
|
||||||
|
* @param string $base the base URL to resolve relative URLs with.
|
||||||
*/
|
*/
|
||||||
protected function _findContextUrls($input, $urls, $replace) {
|
protected function _findContextUrls($input, $urls, $replace, $base) {
|
||||||
if(is_array($input)) {
|
if(is_array($input)) {
|
||||||
foreach($input as $e) {
|
foreach($input as $e) {
|
||||||
$this->_findContextUrls($e, $urls, $replace);
|
$this->_findContextUrls($e, $urls, $replace, $base);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(is_object($input)) {
|
else if(is_object($input)) {
|
||||||
foreach($input as $k => &$v) {
|
foreach($input as $k => &$v) {
|
||||||
if($k !== '@context') {
|
if($k !== '@context') {
|
||||||
$this->_findContextUrls($v, $urls, $replace);
|
$this->_findContextUrls($v, $urls, $replace, $base);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3554,7 +3621,7 @@ class JsonLdProcessor {
|
||||||
$length = count($v);
|
$length = count($v);
|
||||||
for($i = 0; $i < $length; ++$i) {
|
for($i = 0; $i < $length; ++$i) {
|
||||||
if(is_string($v[$i])) {
|
if(is_string($v[$i])) {
|
||||||
$url = $v[$i];
|
$url = jsonld_to_absolute_url($v[$i], $base);
|
||||||
// replace w/@context if requested
|
// replace w/@context if requested
|
||||||
if($replace) {
|
if($replace) {
|
||||||
$ctx = $urls->{$url};
|
$ctx = $urls->{$url};
|
||||||
|
@ -3576,7 +3643,8 @@ class JsonLdProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// string @context
|
// string @context
|
||||||
else if(is_string($v)) {
|
else if(is_string($v)) {
|
||||||
|
$v = jsonld_to_absolute_url($v, $base);
|
||||||
// replace w/@context if requested
|
// replace w/@context if requested
|
||||||
if($replace) {
|
if($replace) {
|
||||||
$input->{$k} = $urls->{$v};
|
$input->{$k} = $urls->{$v};
|
||||||
|
@ -3598,10 +3666,12 @@ class JsonLdProcessor {
|
||||||
* @param mixed $input the JSON-LD input with possible contexts.
|
* @param mixed $input the JSON-LD input with possible contexts.
|
||||||
* @param stdClass $cycles an object for tracking context cycles.
|
* @param stdClass $cycles an object for tracking context cycles.
|
||||||
* @param callable $resolver(url) the URL resolver.
|
* @param callable $resolver(url) the URL resolver.
|
||||||
|
* @param base $base the base URL to resolve relative URLs against.
|
||||||
*
|
*
|
||||||
* @return mixed the result.
|
* @return mixed the result.
|
||||||
*/
|
*/
|
||||||
protected function _resolveContextUrls(&$input, $cycles, $resolver) {
|
protected function _resolveContextUrls(
|
||||||
|
&$input, $cycles, $resolver, $base='') {
|
||||||
if(count(get_object_vars($cycles)) > self::MAX_CONTEXT_URLS) {
|
if(count(get_object_vars($cycles)) > self::MAX_CONTEXT_URLS) {
|
||||||
throw new JsonLdException(
|
throw new JsonLdException(
|
||||||
'Maximum number of @context URLs exceeded.',
|
'Maximum number of @context URLs exceeded.',
|
||||||
|
@ -3612,17 +3682,12 @@ class JsonLdProcessor {
|
||||||
$urls = new stdClass();
|
$urls = new stdClass();
|
||||||
|
|
||||||
// find all URLs in the given input
|
// find all URLs in the given input
|
||||||
$this->_findContextUrls($input, $urls, false);
|
$this->_findContextUrls($input, $urls, false, $base);
|
||||||
|
|
||||||
// queue all unresolved URLs
|
// queue all unresolved URLs
|
||||||
$queue = array();
|
$queue = array();
|
||||||
foreach($urls as $url => $ctx) {
|
foreach($urls as $url => $ctx) {
|
||||||
if($ctx === false) {
|
if($ctx === false) {
|
||||||
// validate URL
|
|
||||||
if(filter_var($url, FILTER_VALIDATE_URL) === false) {
|
|
||||||
throw new JsonLdException(
|
|
||||||
'Malformed URL.', 'jsonld.InvalidUrl', array('url' => $url));
|
|
||||||
}
|
|
||||||
$queue[] = $url;
|
$queue[] = $url;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3684,12 +3749,12 @@ class JsonLdProcessor {
|
||||||
}
|
}
|
||||||
|
|
||||||
// recurse
|
// recurse
|
||||||
$this->_resolveContextUrls($ctx, $_cycles, $resolver);
|
$this->_resolveContextUrls($ctx, $_cycles, $resolver, $url);
|
||||||
$urls->{$url} = $ctx->{'@context'};
|
$urls->{$url} = $ctx->{'@context'};
|
||||||
}
|
}
|
||||||
|
|
||||||
// replace all URLS in the input
|
// replace all URLS in the input
|
||||||
$this->_findContextUrls($input, $urls, true);
|
$this->_findContextUrls($input, $urls, true, $base);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3701,19 +3766,7 @@ class JsonLdProcessor {
|
||||||
* @return string the absolute IRI.
|
* @return string the absolute IRI.
|
||||||
*/
|
*/
|
||||||
protected function _prependBase($base, $iri) {
|
protected function _prependBase($base, $iri) {
|
||||||
if($iri === '' || strpos($iri, '#') === 0) {
|
return jsonld_prepend_base($base, $iri);
|
||||||
return "$base$iri";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// prepend last directory for base
|
|
||||||
$idx = strrpos($base, '/');
|
|
||||||
if($idx === false) {
|
|
||||||
return $iri;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return substr($base, 0, $idx + 1) . $iri;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue