api de gestion de ticket, basé sur php-crud-api. Le but est de décorrélé les outils de gestion des données, afin
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

ValidationMiddleware.php 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. <?php
  2. namespace Tqdev\PhpCrudApi\Middleware;
  3. use Psr\Http\Message\ResponseInterface;
  4. use Psr\Http\Message\ServerRequestInterface;
  5. use Psr\Http\Server\RequestHandlerInterface;
  6. use Tqdev\PhpCrudApi\Column\ReflectionService;
  7. use Tqdev\PhpCrudApi\Column\Reflection\ReflectedTable;
  8. use Tqdev\PhpCrudApi\Controller\Responder;
  9. use Tqdev\PhpCrudApi\Middleware\Base\Middleware;
  10. use Tqdev\PhpCrudApi\Middleware\Router\Router;
  11. use Tqdev\PhpCrudApi\Record\ErrorCode;
  12. use Tqdev\PhpCrudApi\RequestUtils;
  13. class ValidationMiddleware extends Middleware {
  14. private $reflection;
  15. private $typesToValidate;
  16. public function __construct(Router $router, Responder $responder, array $properties, ReflectionService $reflection) {
  17. parent::__construct($router, $responder, $properties);
  18. $this->reflection = $reflection;
  19. $typesStr = $this->getProperty('types', 'all');
  20. if (is_null($typesStr)) {
  21. $typesStr = 'all';
  22. }
  23. if (strlen($typesStr) == 0) {
  24. $typesStr = 'none';
  25. }
  26. $this->typesToValidate = explode(',', $typesStr);
  27. if (is_null($this->typesToValidate) || count($this->typesToValidate) == 0) {
  28. $this->typesToValidate = ['all'];
  29. }
  30. }
  31. private function callHandler($handler, $record, string $operation, ReflectedTable $table) /*: ResponseInterface?*/ {
  32. $context = (array) $record;
  33. $details = array();
  34. $tableName = $table->getName();
  35. foreach ($context as $columnName => $value) {
  36. if ($table->hasColumn($columnName)) {
  37. $column = $table->getColumn($columnName);
  38. $valid = call_user_func($handler, $operation, $tableName, $column->serialize(), $value, $context);
  39. if ($valid || $valid == '') {
  40. $valid = $this->validateType($column->serialize(), $value);
  41. }
  42. if ($valid !== true && $valid !== '') {
  43. $details[$columnName] = $valid;
  44. }
  45. }
  46. }
  47. if (count($details) > 0) {
  48. return $this->responder->error(ErrorCode::INPUT_VALIDATION_FAILED, $tableName, $details);
  49. }
  50. return null;
  51. }
  52. private function validateType($column, $value) {
  53. if ($this->typesToValidate[0] == 'none') {
  54. return (true);
  55. }
  56. if ($this->typesToValidate[0] != 'all') {
  57. if (!in_array($column['type'], $this->typesToValidate)) {
  58. return (true);
  59. }
  60. }
  61. if (is_null($value)) {
  62. return ($column["nullable"] ? true : "cannot be null");
  63. }
  64. switch ($column['type']) {
  65. case 'integer':
  66. if (!is_numeric($value)) {
  67. return ('must be numeric');
  68. }
  69. if (strlen($value) > 20) {
  70. return ('exceeds range');
  71. }
  72. break;
  73. case 'bigint':
  74. if (!is_numeric($value)) {
  75. return ('must be numeric');
  76. }
  77. if (strlen($value) > 20) {
  78. return ('exceeds range');
  79. }
  80. break;
  81. case 'varchar':
  82. if (strlen($value) > $column['length']) {
  83. return ('too long');
  84. }
  85. break;
  86. case 'decimal':
  87. if (!is_float($value) && !is_numeric($value)) {
  88. return ('not a float');
  89. }
  90. break;
  91. case 'float':
  92. if (!is_float($value) && !is_numeric($value)) {
  93. return ('not a float');
  94. }
  95. break;
  96. case 'double':
  97. if (!is_float($value) && !is_numeric($value)) {
  98. return ('not a float');
  99. }
  100. break;
  101. case 'boolean':
  102. if ($value != 0 && $value != 1) {
  103. return ('not a valid boolean');
  104. }
  105. break;
  106. case 'date':
  107. $date_array = explode('-', $value);
  108. if (count($date_array) != 3) {
  109. return ('invalid date format use yyyy-mm-dd');
  110. }
  111. if (!@checkdate($date_array[1], $date_array[2], $date_array[0])) {
  112. return ('not a valid date');
  113. }
  114. break;
  115. case 'time':
  116. $time_array = explode(':', $value);
  117. if (count($time_array) != 3) {
  118. return ('invalid time format use hh:mm:ss');
  119. }
  120. foreach ($time_array as $t) {
  121. if (!is_numeric($t)) {
  122. return ('non-numeric time value');
  123. }
  124. }
  125. if ($time_array[1] < 0 || $time_array[2] < 0 || $time_array[0] < -838 || $time_array[1] > 59 || $time_array[2] > 59 || $time_array[0] > 838) {
  126. return ('not a valid time');
  127. }
  128. break;
  129. case 'timestamp':
  130. $split_timestamp = explode(' ', $value);
  131. if (count($split_timestamp) != 2) {
  132. return ('invalid timestamp format use yyyy-mm-dd hh:mm:ss');
  133. }
  134. $date_array = explode('-', $split_timestamp[0]);
  135. if (count($date_array) != 3) {
  136. return ('invalid date format use yyyy-mm-dd');
  137. }
  138. if (!@checkdate($date_array[1], $date_array[2], $date_array[0])) {
  139. return ('not a valid date');
  140. }
  141. $time_array = explode(':', $split_timestamp[1]);
  142. if (count($time_array) != 3) {
  143. return ('invalid time format use hh:mm:ss');
  144. }
  145. foreach ($time_array as $t) {
  146. if (!is_numeric($t)) {
  147. return ('non-numeric time value');
  148. }
  149. }
  150. if ($time_array[1] < 0 || $time_array[2] < 0 || $time_array[0] < 0 || $time_array[1] > 59 || $time_array[2] > 59 || $time_array[0] > 23) {
  151. return ('not a valid time');
  152. }
  153. break;
  154. case 'clob':
  155. break;
  156. case 'blob':
  157. break;
  158. case 'varbinary':
  159. if (((strlen($value) * 3 / 4) - substr_count(substr($value, -2), '=')) > $column['length']) {
  160. return ('too long');
  161. }
  162. break;
  163. case 'geometry':
  164. break;
  165. }
  166. return (true);
  167. }
  168. public function process(ServerRequestInterface $request, RequestHandlerInterface $next): ResponseInterface{
  169. $operation = RequestUtils::getOperation($request);
  170. if (in_array($operation, ['create', 'update', 'increment'])) {
  171. $tableName = RequestUtils::getPathSegment($request, 2);
  172. if ($this->reflection->hasTable($tableName)) {
  173. $record = $request->getParsedBody();
  174. if ($record !== null) {
  175. $handler = $this->getProperty('handler', '');
  176. if ($handler !== '') {
  177. $table = $this->reflection->getTable($tableName);
  178. if (is_array($record)) {
  179. foreach ($record as $r) {
  180. $response = $this->callHandler($handler, $r, $operation, $table);
  181. if ($response !== null) {
  182. return $response;
  183. }
  184. }
  185. } else {
  186. $response = $this->callHandler($handler, $record, $operation, $table);
  187. if ($response !== null) {
  188. return $response;
  189. }
  190. }
  191. }
  192. }
  193. }
  194. }
  195. return $next->handle($request);
  196. }
  197. }