设为首页 收藏本站
查看: 754|回复: 0

[经验分享] json-schema-php

[复制链接]

尚未签到

发表于 2017-3-21 10:17:54 | 显示全部楼层 |阅读模式
  


?php
/*
* MoXie (SysTem128@GMail.Com) 2010-12-11
*
* Copyright © 2010-2010 Zoeey.Org
* Code license: GNU Lesser General Public License Version 3
* http://www.gnu.org/licenses/lgpl-3.0.txt
*
* website:
* http://code.google.com/p/json-schema-php/
*/
/**
* JSON Schema generate/validate
*
* @author moxie(system128@gmail.com)
*/
class JsonSchema {
/**
* JSON
*
* @var string
*/
private $json;
/**
* Last error
*
* @var array
*/
private $errors;
/**
* Extend types
*
* @var map
*/
private $complexTypes;
/**
*
* @param string $json
*/
function __construct($json) {
$this->errors = array();
$this->complexTypes = array();
$this->json = json_decode($json);
}
/**
* Generate JSON Schema
*
* @return string JSON Schema
*/
public function getSchema() {
$schema = null;
$schema = $this->genByType($this->json);
return json_encode($schema);
}
/**
* Generate JSON Schema by type
* @param mixed $value
* @return object
*/
private function genByType($value) {
$type = gettype($value);
$schema = array();
switch ($type) {
case 'boolean':
$schema['type'] = 'boolean';
$schema['default'] = false;
break;
case 'integer':
$schema['type'] = 'integer';
$schema['default'] = 0;
$schema['minimum'] = 0;
$schema['maximum'] = PHP_INT_MAX;
$schema['exclusiveMinimum'] = 0;
$schema['exclusiveMaximum'] = PHP_INT_MAX;
break;
case 'double':
$schema['type'] = 'number';
$schema['default'] = 0;
$schema['minimum'] = 0;
$schema['maximum'] = PHP_INT_MAX;
$schema['exclusiveMinimum'] = 0;
$schema['exclusiveMaximum'] = PHP_INT_MAX;
break;
case 'string':
$schema['type'] = 'string';
$schema['format'] = 'regex';
$schema['pattern'] = '/^[a-z0-9]+$/i';
$schema['minLength'] = 0;
$schema['maxLength'] = PHP_INT_MAX;
break;
case 'array':
$schema['type'] = 'array';
$schema['minItems'] = 0;
$schema['maxItems'] = 20;
$items = array();
foreach ($value as $value) {
$items = $this->genByType($value);
break;
}
$schema['items'] = $items;
break;
case 'object':
$schema['type'] = 'object';
$items = array();
$value = get_object_vars($value);
foreach ($value as $key => $value) {
$items[$key] = $this->genByType($value);
}
$schema['properties'] = $items;
break;
case 'null': // any in union types
$schema['type'] = 'null';
break;
default:
break;
}
return $schema;
}
/**
* Set type schema
* @param string $typeSchema
*/
public function addType($typeSchema) {
if (empty($typeSchema)) {
return;
}
$typeSchema = json_decode($typeSchema, true);
if (is_array($typeSchema) && isset($typeSchema['id'])) {
$this->complexTypes[$typeSchema['id']] = $typeSchema;
}
}
/**
* Get type schema
*
* @param string ref
* @return string schema
*/
private function getType($ref) {
if (isset($this->complexTypes[$ref])) {
return $this->complexTypes[$ref];
}
return null;
}
/**
* Validate JSON
*
* @param string $schema JSON Schema
* @return boolean
*/
public function validate($schema) {
$isVali = false;
do {
$schema = json_decode($schema, true);
if (!is_array($schema) || !isset($schema['type'])) {
$this->addError('schema parse error. (PHP 5 >= 5.3.0) see json_last_error(void).');
break;
}
$isVali = $this->checkByType($this->json, $schema);
} while (false);
return $isVali;
}
/**
* check type: string
* http://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.1
*
* @param string $value
* @param array $schema
*/
private function checkString($value, $schema) {
// string
$isVali = false;
do {
if (!is_string($value)) {
$this->addError(sprintf('value: "%s" is not a string.', $value));
break;
}
$len = strlen($value);
if (isset($schema['minLength'])) {
if ($schema['minLength'] > $len) {
$this->addError(sprintf('value: "%s" is too short.', $value));
break;
}
}
if (isset($schema['maxLength'])) {
if ($schema['maxLength'] < $len) {
$this->addError(sprintf('value: "%s" is too long.', $value));
break;
}
}
if (isset($schema['format'])) {
switch ($schema['format']) {
case 'date-time':
/**
* date-time  This SHOULD be a date in ISO 8601 format of YYYY-MM-
* DDThh:mm:ssZ in UTC time.  This is the recommended form of date/
* timestamp.
*/
break;
case 'date':
/**
* date  This SHOULD be a date in the format of YYYY-MM-DD.  It is
* recommended that you use the "date-time" format instead of "date"
* unless you need to transfer only the date part.
*/
break;
case 'time':
/**
* time  This SHOULD be a time in the format of hh:mm:ss.  It is
* recommended that you use the "date-time" format instead of "time"
* unless you need to transfer only the time part.
*/
break;
case 'utc-millisec':
/**
* utc-millisec  This SHOULD be the difference, measured in
* milliseconds, between the specified time and midnight, 00:00 of
* January 1, 1970 UTC.  The value SHOULD be a number (integer or
* float).
*/
break;
case 'regex':
/**
* regex  A regular expression, following the regular expression
* specification from ECMA 262/Perl 5.
*/
if (isset($schema['pattern'])) {
$pattern = $schema['pattern'];
if (preg_match($pattern, $value)) {
$isVali = true;
} else {
$this->addError(printf('"%s" does not match "%s"', $value, $pattern));
}
} else {
$this->addError('format-regex: pattern is undefined.');
}
break;
case 'color':
/**
* color  This is a CSS color (like "#FF0000" or "red"), based on CSS
* 2.1 [W3C.CR-CSS21-20070719].
*/
break;
case 'style':
/**
* style  This is a CSS style definition (like "color: red; background-
* color:#FFF"), based on CSS 2.1 [W3C.CR-CSS21-20070719].
*/
break;
case 'phone':
/**
* phone  This SHOULD be a phone number (format MAY follow E.123).
* http://en.wikipedia.org/wiki/E.123
*/
if (preg_match("/^(\(0?[0-9]{2}\) \d{3,4}\s?\d{4}|\+\d{2} \d{2} \d{3,4}\s?\d{4})$/", $value)) {
$isVali = true;
} else {
$this->addError(sprintf('value: "%s" is not a phone number.', $value));
}
break;
case 'uri':
/**
* uri  This value SHOULD be a URI..
*/
if (filter_var($value, FILTER_VALIDATE_URL, FILTER_FLAG_QUERY_REQUIRED)) {
$isVali = true;
} else {
$this->addError(sprintf('value: "%s" is not a URI.', $value));
}
break;
case 'email':
/**
*  email  This SHOULD be an email address.
*/
if (filter_var($value, FILTER_VALIDATE_EMAIL)) {
$isVali = true;
} else {
$this->addError(sprintf('value: "%s" is not a email.', $value));
}
break;
case 'ip-address':
/**
*  ip-address  This SHOULD be an ip version 4 address.
*/
if (filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
$isVali = true;
} else {
$this->addError(sprintf('value: "%s" is not a ipv4 address.', $value));
}
break;
case 'ipv6':
/**
*  ipv6  This SHOULD be an ip version 6 address.
*/
if (filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
$isVali = true;
} else {
$this->addError(sprintf('value: "%s" is not a ipv6 address.', $value));
}
break;
case 'host-name':
/**
*  host-name  This SHOULD be a host-name.
*/
break;
default:
$this->addError(sprintf('format: "%s" is undefined.', $schema['format']));
break;
}
break;
}
$isVali = true;
} while (false);
return $isVali;
}
/**
* check type: integer/double
*
* @param number $value
* @param array $schema
* @return boolean
*/
private function checkNumber($value, $schema) {
// number
$isVali = false;
do {
if (!is_numeric($value)) {
$this->addError($value . ' is not a number.');
break;
}
if (isset($schema['minimum'])) {
if ($schema['minimum'] > $value) {
$this->addError(sprintf('%s is less than %s.', $value, $schema['minimum']));
break;
}
}
if (isset($schema['maximum'])) {
if ($schema['maximum'] < $value) {
$this->addError(sprintf('%s is bigger than %s.', $value, $schema['maximum']));
break;
}
}
if (isset($schema['exclusiveMinimum'])) {
if ($schema['exclusiveMinimum'] >= $value) {
$this->addError(sprintf('%s is less or than %s or equal.', $value, $schema['exclusiveMinimum']));
break;
}
}
if (isset($schema['exclusiveMaximum'])) {
if ($schema['exclusiveMaximum'] <= $value) {
$this->addError(sprintf('%s is bigger than %s or equal.', $value, $schema['exclusiveMaximum']));
break;
}
}
$isVali = true;
} while (false);
return $isVali;
}
/**
* check type: integer
*
* @param integer $value
* @param array $schema
* @return boolean
*/
private function checkInteger($value, $schema) {
// integer
if (!is_integer($value)) {
$this->addError(sprintf('value:"%s" is not a integer.', $value));
return false;
}
return $this->checkNumber($value, $schema);
}
/**
* check type: boolean
*
* @param boolean $value
* @param array $schema
* @return boolean
*/
private function checkBoolean($value, $schema) {
// boolean
if (!is_bool($value)) {
$this->addError(sprintf('value: "%s" is not a boolean.', $value));
return false;
}
return true;
}
/**
* check type: object
*
* @param object $valueProp
* @param array $schema
* @return boolean
*/
private function checkObject($value, $schema) {
// object
$isVali = false;
do {
if (!is_object($value)) {
$this->addError(sprintf('value: "%s" is not an object.', $value));
break;
}
if (isset($schema['properties'])
&& !empty($schema['properties'])
) {
$schemaProp = $schema['properties'];
$valueProp = get_object_vars($value);
$valueKeys = array_keys($valueProp);
$schemaKeys = array_keys($schemaProp);
$diffKeys = array_diff($valueKeys, $schemaKeys);
if (!empty($diffKeys)) {
foreach ($diffKeys as $key) {
// property not defined / not optional
if (!isset($schemaProp[$key])
|| !isset($schemaProp[$key]['optional'])
|| !$schemaProp[$key]['optional']
) {
$this->addError(sprintf('key: "%s" is not exist,And it\'s not a optional property.', $value));
break 2;
}
}
}
foreach ($schemaProp as $key => $sch) {
if (!isset($valueProp[$key])) {
continue;
}
if (!$this->checkByType($valueProp[$key], $sch)) {
break 2;
}
}
}
$isVali = true;
} while (false);
return $isVali;
}
/**
* check type: array
*
* @param array $value
* @param array $schema
* @return boolean
*/
private function checkArray($value, $schema) {
$isVali = false;
do {
if (!is_array($value)) {
$this->addError(sprintf('value: "%s" is not an array.', $value));
break;
}
if (!isset($schema['items'])) {
$this->addError('schema: items schema is undefined.');
break;
}
$size = count($value);
if (isset($schema['minItems'])) {
if ($schema['minItems'] > $size) {
$this->addError(sprintf('array size: %s  is less than %s.', $size, $schema['minItems']));
break;
}
}
if (isset($schema['maxItems'])) {
if ($schema['maxItems'] < $size) {
$this->addError(sprintf('array size: %s is bigger than %s.', $size, $schema['maxItems']));
break;
}
}
foreach ($value as $val) {
if (!$this->checkByType($val, $schema['items'])) {
break 2;
}
}

$isVali = true;
} while (false);
return $isVali;
}
/**
* check value based on type
*
* @param mixed $value
* @param array $schema
* @return boolean
*/
private function checkByType($value, $schema) {
$isVali = false;
if ($schema && isset($schema['type'])) {
// union types
if (is_array($schema['type'])) {
$types = $schema['type'];
foreach ($types as $type) {
$schema['type'] = $type;
$isVali = $this->checkByType($value, $schema);
if ($isVali) {
break;
}
}
} else {
$type = $schema['type'];
switch ($type) {
case 'boolean':
$isVali = $this->checkBoolean($value, $schema);
break;
case 'integer':
$isVali = $this->checkInteger($value, $schema);
break;
case 'number':
$isVali = $this->checkNumber($value, $schema);
break;
case 'string':
$isVali = $this->checkString($value, $schema);
break;
case 'array':
$isVali = $this->checkArray($value, $schema);
break;
case 'object':
$isVali = $this->checkObject($value, $schema);
break;
case 'enum':
$isVali = is_null($value);
break;
case 'null':
$isVali = is_null($value);
break;
case 'any':
$isVali = true;
break;
default:
$this->addError(sprintf('type_schema: "%s" is undefined.', $value));
break;
}
}
}
if (isset($schema['$ref'])) {
$isVali = $this->checkByType($value, $this->getType($schema['$ref']));
}
return $isVali;
}
/**
*  Get errors
*
* @return array errors
*/
public function getErrors() {
return $this->errors;
}
/**
* add error message
* @param string $msg
*/
protected function addError($msg) {
$this->errors[] = htmlentities($msg);
}
}
?>

 

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-352867-1-1.html 上篇帖子: PHP的curl 下篇帖子: PHP JSON 封装
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表