Validate.php 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. <?php
  2. namespace Typecho;
  3. /**
  4. * 验证类
  5. *
  6. * @package Validate
  7. */
  8. class Validate
  9. {
  10. /**
  11. * 内部数据
  12. *
  13. * @access private
  14. * @var array
  15. */
  16. private $data;
  17. /**
  18. * 当前验证指针
  19. *
  20. * @access private
  21. * @var string
  22. */
  23. private $key;
  24. /**
  25. * 验证规则数组
  26. *
  27. * @access private
  28. * @var array
  29. */
  30. private $rules = [];
  31. /**
  32. * 中断模式,一旦出现验证错误即抛出而不再继续执行
  33. *
  34. * @access private
  35. * @var boolean
  36. */
  37. private $break = false;
  38. /**
  39. * 最小长度
  40. *
  41. * @access public
  42. *
  43. * @param string $str 待处理的字符串
  44. * @param integer $length 最小长度
  45. *
  46. * @return boolean
  47. */
  48. public static function minLength(string $str, int $length): bool
  49. {
  50. return (Common::strLen($str) >= $length);
  51. }
  52. /**
  53. * 枚举类型判断
  54. *
  55. * @access public
  56. *
  57. * @param string $str 待处理的字符串
  58. * @param array $params 枚举值
  59. *
  60. * @return bool
  61. */
  62. public static function enum(string $str, array $params): bool
  63. {
  64. $keys = array_flip($params);
  65. return isset($keys[$str]);
  66. }
  67. /**
  68. * Max Length
  69. *
  70. * @param string $str
  71. * @param int $length
  72. *
  73. * @return bool
  74. */
  75. public static function maxLength(string $str, int $length): bool
  76. {
  77. return (Common::strLen($str) < $length);
  78. }
  79. /**
  80. * Valid Email
  81. *
  82. * @access public
  83. *
  84. * @param string $str
  85. *
  86. * @return boolean
  87. */
  88. public static function email(string $str): bool
  89. {
  90. $email = filter_var($str, FILTER_SANITIZE_EMAIL);
  91. return !!filter_var($str, FILTER_VALIDATE_EMAIL) && ($email === $str);
  92. }
  93. /**
  94. * 验证是否为网址
  95. *
  96. * @access public
  97. *
  98. * @param string $str
  99. *
  100. * @return boolean
  101. */
  102. public static function url(string $str): bool
  103. {
  104. $url = Common::safeUrl($str);
  105. return !!filter_var($str, FILTER_VALIDATE_URL) && ($url === $str);
  106. }
  107. /**
  108. * Alpha
  109. *
  110. * @access public
  111. *
  112. * @param string
  113. *
  114. * @return boolean
  115. */
  116. public static function alpha(string $str): bool
  117. {
  118. return ctype_alpha($str);
  119. }
  120. /**
  121. * Alpha-numeric
  122. *
  123. * @access public
  124. *
  125. * @param string
  126. *
  127. * @return boolean
  128. */
  129. public static function alphaNumeric(string $str): bool
  130. {
  131. return ctype_alnum($str);
  132. }
  133. /**
  134. * Alpha-numeric with underscores and dashes
  135. *
  136. * @access public
  137. *
  138. * @param string
  139. *
  140. * @return boolean
  141. */
  142. public static function alphaDash(string $str): bool
  143. {
  144. return !!preg_match("/^([_a-z0-9-])+$/i", $str);
  145. }
  146. /**
  147. * 对xss字符串的检测
  148. *
  149. * @access public
  150. *
  151. * @param string $str
  152. *
  153. * @return boolean
  154. */
  155. public static function xssCheck(string $str): bool
  156. {
  157. $search = 'abcdefghijklmnopqrstuvwxyz';
  158. $search .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  159. $search .= '1234567890!@#$%^&*()';
  160. $search .= '~`";:?+/={}[]-_|\'\\';
  161. for ($i = 0; $i < strlen($search); $i++) {
  162. // ;? matches the ;, which is optional
  163. // 0{0,7} matches any padded zeros, which are optional and go up to 8 chars
  164. // &#x0040 @ search for the hex values
  165. $str = preg_replace('/(&#[xX]0{0,8}' . dechex(ord($search[$i])) . ';?)/i', $search[$i], $str); // with a ;
  166. // &#00064 @ 0{0,7} matches '0' zero to seven times
  167. $str = preg_replace('/(&#0{0,8}' . ord($search[$i]) . ';?)/', $search[$i], $str); // with a ;
  168. }
  169. return !preg_match('/(\(|\)|\\\|"|<|>|[\x00-\x08]|[\x0b-\x0c]|[\x0e-\x19]|' . "\r|\n|\t" . ')/', $str);
  170. }
  171. /**
  172. * Numeric
  173. *
  174. * @access public
  175. *
  176. * @param mixed $str
  177. *
  178. * @return boolean
  179. */
  180. public static function isFloat($str): bool
  181. {
  182. return filter_var($str, FILTER_VALIDATE_FLOAT) !== false;
  183. }
  184. /**
  185. * Is Numeric
  186. *
  187. * @access public
  188. *
  189. * @param mixed $str
  190. *
  191. * @return boolean
  192. */
  193. public static function isInteger($str): bool
  194. {
  195. return filter_var($str, FILTER_VALIDATE_INT) !== false;
  196. }
  197. /**
  198. * 增加验证规则
  199. *
  200. * @access public
  201. *
  202. * @param string $key 数值键值
  203. * @param string|callable $rule 规则名称
  204. * @param string $message 错误字符串
  205. *
  206. * @return $this
  207. */
  208. public function addRule(string $key, $rule, string $message): Validate
  209. {
  210. if (func_num_args() <= 3) {
  211. $this->rules[$key][] = [$rule, $message];
  212. } else {
  213. $params = func_get_args();
  214. $params = array_splice($params, 3);
  215. $this->rules[$key][] = array_merge([$rule, $message], $params);
  216. }
  217. return $this;
  218. }
  219. /**
  220. * 设置为中断模式
  221. *
  222. * @access public
  223. * @return void
  224. */
  225. public function setBreak()
  226. {
  227. $this->break = true;
  228. }
  229. /**
  230. * Run the Validator
  231. * This function does all the work.
  232. *
  233. * @access public
  234. *
  235. * @param array $data 需要验证的数据
  236. * @param array|null $rules 验证数据遵循的规则
  237. *
  238. * @return array
  239. */
  240. public function run(array $data, array $rules = null): array
  241. {
  242. $result = [];
  243. $this->data = $data;
  244. $rules = empty($rules) ? $this->rules : $rules;
  245. // Cycle through the rules and test for errors
  246. foreach ($rules as $key => $rule) {
  247. $this->key = $key;
  248. $data[$key] = (is_array($data[$key]) ? 0 == count($data[$key])
  249. : 0 == strlen($data[$key] ?? '')) ? null : $data[$key];
  250. foreach ($rule as $params) {
  251. $method = $params[0];
  252. if ('required' != $method && 'confirm' != $method && 0 == strlen($data[$key] ?? '')) {
  253. continue;
  254. }
  255. $message = $params[1];
  256. $params[1] = $data[$key];
  257. $params = array_slice($params, 1);
  258. if (!call_user_func_array(is_callable($method) ? $method : [$this, $method], $params)) {
  259. $result[$key] = $message;
  260. break;
  261. }
  262. }
  263. /** 开启中断 */
  264. if ($this->break && $result) {
  265. break;
  266. }
  267. }
  268. return $result;
  269. }
  270. /**
  271. * 验证输入是否一致
  272. *
  273. * @access public
  274. *
  275. * @param string|null $str 待处理的字符串
  276. * @param string $key 需要一致性检查的键值
  277. *
  278. * @return boolean
  279. */
  280. public function confirm(?string $str, string $key): bool
  281. {
  282. return !empty($this->data[$key]) ? ($str == $this->data[$key]) : empty($str);
  283. }
  284. /**
  285. * 是否为空
  286. *
  287. * @access public
  288. *
  289. * @return boolean
  290. */
  291. public function required(): bool
  292. {
  293. return !empty($this->data[$this->key]);
  294. }
  295. }