Skip to content

Commit

Permalink
Merge with upstream master branch.
Browse files Browse the repository at this point in the history
  • Loading branch information
webdevel committed Sep 11, 2013
2 parents 52fb7c1 + b2165e1 commit 5082715
Show file tree
Hide file tree
Showing 11 changed files with 632 additions and 60 deletions.
197 changes: 171 additions & 26 deletions bin/validate-json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ function __autoload($className)
$fileName = str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
}
$fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
require_once $fileName;
if (stream_resolve_include_path($fileName)) {
require_once $fileName;
}
}

/**
Expand All @@ -45,55 +47,198 @@ function showJsonError()
echo 'JSON parse error: ' . $json_errors[json_last_error()] . "\n";
}

function getUrlFromPath($path)
{
if (parse_url($path, PHP_URL_SCHEME) !== null) {
//already an URL
return $path;
}
if ($path{0} == '/') {
//absolute path
return 'file://' . $path;
}

//relative path: make absolute
return 'file://' . getcwd() . '/' . $path;
}

/**
* Take a HTTP header value and split it up into parts.
*
* @return array Key "_value" contains the main value, all others
* as given in the header value
*/
function parseHeaderValue($headerValue)
{
if (strpos($headerValue, ';') === false) {
return array('_value' => $headerValue);
}

$parts = explode(';', $headerValue);
$arData = array('_value' => array_shift($parts));
foreach ($parts as $part) {
list($name, $value) = explode('=', $part);
$arData[$name] = trim($value, ' "\'');
}
return $arData;
}


// support running this tool from git checkout
if (is_dir(__DIR__ . '/../src/JsonSchema')) {
set_include_path(__DIR__ . '/../src' . PATH_SEPARATOR . get_include_path());
}

if ($argc < 3) {
echo "Usage: validate-json schema.json data.json\n";
exit(1);
$arOptions = array();
$arArgs = array();
array_shift($argv);//script itself
foreach ($argv as $arg) {
if ($arg{0} == '-') {
$arOptions[$arg] = true;
} else {
$arArgs[] = $arg;
}
}

$pathSchema = $argv[1];
$pathData = $argv[2];
if (count($arArgs) == 0
|| isset($arOptions['--help']) || isset($arOptions['-h'])
) {
echo <<<HLP
Validate schema
Usage: validate-json data.json
or: validate-json data.json schema.json
if (!is_readable($pathSchema)) {
echo "Schema file is not readable.\n";
exit(2);
Options:
--dump-schema Output full schema and exit
--dump-schema-url Output URL of schema
-h --help Show this help
HLP;
exit(1);
}

if (!is_readable($pathData)) {
echo "Data file is not readable.\n";
exit(3);
if (count($arArgs) == 1) {
$pathData = $arArgs[0];
$pathSchema = null;
} else {
$pathData = $arArgs[0];
$pathSchema = getUrlFromPath($arArgs[1]);
}

$data = json_decode(file_get_contents($pathData));
$urlData = getUrlFromPath($pathData);

$context = stream_context_create(
array(
'http' => array(
'header' => array(
'Accept: */*',
'Connection: Close'
),
'max_redirects' => 5
)
)
);
$dataString = file_get_contents($pathData, false, $context);
if ($dataString == '') {
echo "Data file is not readable or empty.\n";
exit(3);
}

$data = json_decode($dataString);
unset($dataString);
if ($data === null) {
echo "Error loading JSON data file\n";
showJsonError();
exit(5);
}

$schema = json_decode(file_get_contents($pathSchema));
if ($pathSchema === null) {
if (isset($http_response_header)) {
array_shift($http_response_header);//HTTP/1.0 line
foreach ($http_response_header as $headerLine) {
list($hName, $hValue) = explode(':', $headerLine, 2);
$hName = strtolower($hName);
if ($hName == 'link') {
//Link: <http://example.org/schema#>; rel="describedBy"
$hParts = parseHeaderValue($hValue);
if (isset($hParts['rel']) && $hParts['rel'] == 'describedBy') {
$pathSchema = trim($hParts['_value'], ' <>');
}
} else if ($hName == 'content-type') {
//Content-Type: application/my-media-type+json;
// profile=http://example.org/schema#
$hParts = parseHeaderValue($hValue);
if (isset($hParts['profile'])) {
$pathSchema = $hParts['profile'];
}

}
}
}
if (is_object($data) && property_exists($data, '$schema')) {
$pathSchema = $data->{'$schema'};
}

//autodetect schema
if ($pathSchema === null) {
echo "JSON data must be an object and have a \$schema property.\n";
echo "You can pass the schema file on the command line as well.\n";
echo "Schema autodetection failed.\n";
exit(6);
}
}
if ($pathSchema{0} == '/') {
$pathSchema = 'file://' . $pathSchema;
}

$resolver = new JsonSchema\Uri\UriResolver();
$retriever = new JsonSchema\Uri\UriRetriever();
try {
$urlSchema = $resolver->resolve($pathSchema, $urlData);

if (isset($arOptions['--dump-schema-url'])) {
echo $urlSchema . "\n";
exit();
}

if ($schema === null) {
$schema = $retriever->retrieve($urlSchema);
if ($schema === null) {
echo "Error loading JSON schema file\n";
echo $urlSchema . "\n";
showJsonError();
exit(2);
}
} catch (Exception $e) {
echo "Error loading JSON schema file\n";
showJsonError();
exit(6);
echo $urlSchema . "\n";
echo $e->getMessage() . "\n";
exit(2);
}
$refResolver = new JsonSchema\RefResolver($retriever);
$refResolver->resolve($schema, $urlSchema);

$validator = new JsonSchema\Validator();
$validator->check($data, $schema);
if (isset($arOptions['--dump-schema'])) {
echo json_encode($schema, JSON_PRETTY_PRINT) . "\n";
exit();
}

if ($validator->isValid()) {
echo "OK. The supplied JSON validates against the schema.\n";
} else {
echo "JSON does not validate. Violations:\n";
foreach ($validator->getErrors() as $error) {
echo sprintf("[%s] %s\n", $error['property'], $error['message']);
try {
$validator = new JsonSchema\Validator();
$validator->check($data, $schema);

if ($validator->isValid()) {
echo "OK. The supplied JSON validates against the schema.\n";
} else {
echo "JSON does not validate. Violations:\n";
foreach ($validator->getErrors() as $error) {
echo sprintf("[%s] %s\n", $error['property'], $error['message']);
}
exit(23);
}
exit(23);
} catch (Exception $e) {
echo "JSON does not validate. Error:\n";
echo $e->getMessage() . "\n";
echo "Error code: " . $e->getCode() . "\n";
exit(24);
}
?>
5 changes: 4 additions & 1 deletion src/JsonSchema/Constraints/Undefined.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ public function check($value, $schema = null, $path = null, $i = null)
}

if (!is_object($schema)) {
throw new InvalidArgumentException('Given schema must be an object.');
throw new InvalidArgumentException(
'Given schema must be an object in ' . $path
. ' but is a ' . gettype($schema)
);
}

$i = is_null($i) ? "" : $i;
Expand Down
21 changes: 19 additions & 2 deletions src/JsonSchema/RefResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@
*/
class RefResolver
{
/**
* HACK to prevent too many recursive expansions.
* Happens e.g. when you want to validate a schema against the schema
* definition.
*
* @var integer
*/
protected static $depth = 0;

/**
* @var UriRetrieverInterface
*/
Expand All @@ -41,7 +50,7 @@ public function __construct($retriever = null)
*/
public function fetchRef($ref, $sourceUri)
{
$retriever = $this->getUriRetriever();
$retriever = $this->getUriRetriever();
$jsonSchema = $retriever->retrieve($ref, $sourceUri);
$this->resolve($jsonSchema);

Expand Down Expand Up @@ -79,7 +88,13 @@ public function getUriRetriever()
*/
public function resolve($schema, $sourceUri = null)
{
if (self::$depth > 7) {
return;
}
++self::$depth;

if (! is_object($schema)) {
--self::$depth;
return;
}

Expand Down Expand Up @@ -107,6 +122,8 @@ public function resolve($schema, $sourceUri = null)
foreach (array('dependencies', 'patternProperties', 'properties') as $propertyName) {
$this->resolveObjectOfSchemas($schema, $propertyName, $sourceUri);
}

--self::$depth;
}

/**
Expand Down Expand Up @@ -201,4 +218,4 @@ public function setUriRetriever(UriRetriever $retriever)

return $this;
}
}
}
4 changes: 1 addition & 3 deletions src/JsonSchema/Uri/Retrievers/Curl.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@

use JsonSchema\Validator;

use JsonSchema\Exception\ResourceNotFoundException;

/**
* Tries to retrieve JSON schemas from a URI using cURL library
*
Expand Down Expand Up @@ -44,7 +42,7 @@ public function retrieve($uri)

$response = curl_exec($ch);
if (false === $response) {
throw new ResourceNotFoundException('JSON schema not found');
throw new \JsonSchema\Exception\ResourceNotFoundException('JSON schema not found');
}

$this->fetchMessageBody($response);
Expand Down
12 changes: 9 additions & 3 deletions src/JsonSchema/Uri/Retrievers/FileGetContents.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

namespace JsonSchema\Uri\Retrievers;

use JsonSchema\Exception\ResourceNotFoundException;
use JsonSchema\Validator;

/**
Expand All @@ -34,9 +35,14 @@ public function retrieve($uri)

$response = file_get_contents($uri);
if (false === $response) {
throw new ResourceNotFoundException('JSON schema not found');
throw new ResourceNotFoundException('JSON schema not found at ' . $uri);
}

if ($response == ''
&& substr($uri, 0, 7) == 'file://' && substr($uri, -1) == '/'
) {
throw new ResourceNotFoundException('JSON schema not found at ' . $uri);
}

$this->messageBody = $response;
if (! empty($http_response_header)) {
$this->fetchContentType($http_response_header);
Expand Down Expand Up @@ -73,4 +79,4 @@ protected static function getContentTypeMatchInHeader($header)
return trim($match[1]);
}
}
}
}
3 changes: 1 addition & 2 deletions src/JsonSchema/Uri/Retrievers/PredefinedArray.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

use JsonSchema\Validator;
use JsonSchema\Uri\Retrievers\UriRetrieverInterface;
use JsonSchema\Exception\ResourceNotFoundException;

/**
* URI retrieved based on a predefined array of schemas
Expand Down Expand Up @@ -45,7 +44,7 @@ public function __construct(array $schemas, $contentType = Validator::SCHEMA_MED
public function retrieve($uri)
{
if (!array_key_exists($uri, $this->schemas)) {
throw new ResourceNotFoundException(sprintf(
throw new \JsonSchema\Exception\ResourceNotFoundException(sprintf(
'The JSON schema "%s" was not found.',
$uri
));
Expand Down
Loading

0 comments on commit 5082715

Please sign in to comment.