MediaWiki  master
Validator.php
Go to the documentation of this file.
1 <?php
2 
4 
12 use Wikimedia\ObjectFactory\ObjectFactory;
24 
32 class Validator {
33 
35  private const TYPE_DEFS = [
36  'boolean' => [ 'class' => BooleanDef::class ],
37  'enum' => [ 'class' => EnumDef::class ],
38  'integer' => [ 'class' => IntegerDef::class ],
39  'float' => [ 'class' => FloatDef::class ],
40  'double' => [ 'class' => FloatDef::class ],
41  'NULL' => [
42  'class' => StringDef::class,
43  'args' => [ [
44  'allowEmptyWhenRequired' => true,
45  ] ],
46  ],
47  'password' => [ 'class' => PasswordDef::class ],
48  'string' => [ 'class' => StringDef::class ],
49  'timestamp' => [ 'class' => TimestampDef::class ],
50  'upload' => [ 'class' => UploadDef::class ],
51  'expiry' => [ 'class' => ExpiryDef::class ],
52  'title' => [
53  'class' => TitleDef::class,
54  'services' => [ 'TitleFactory' ],
55  ],
56  'user' => [
57  'class' => UserDef::class,
58  'services' => [ 'UserIdentityLookup', 'TitleParser', 'UserNameUtils' ]
59  ],
60  ];
61 
63  private const NO_BODY_METHODS = [ 'GET', 'HEAD', 'DELETE' ];
64 
66  private const BODY_METHODS = [ 'POST', 'PUT' ];
67 
69  private const FORM_DATA_CONTENT_TYPES = [
70  'application/x-www-form-urlencoded',
71  'multipart/form-data',
72  ];
73 
75  private $paramValidator;
76 
83  public function __construct(
84  ObjectFactory $objectFactory,
85  RequestInterface $request,
86  Authority $authority
87  ) {
88  $this->paramValidator = new ParamValidator(
89  new ParamValidatorCallbacks( $request, $authority ),
90  $objectFactory,
91  [
92  'typeDefs' => self::TYPE_DEFS,
93  ]
94  );
95  }
96 
103  public function validateParams( array $paramSettings ) {
104  $validatedParams = [];
105  foreach ( $paramSettings as $name => $settings ) {
106  try {
107  $validatedParams[$name] = $this->paramValidator->getValue( $name, $settings, [
108  'source' => $settings[Handler::PARAM_SOURCE] ?? 'unspecified',
109  ] );
110  } catch ( ValidationException $e ) {
111  throw new LocalizedHttpException( $e->getFailureMessage(), 400, [
112  'error' => 'parameter-validation-failed',
113  'name' => $e->getParamName(),
114  'value' => $e->getParamValue(),
115  'failureCode' => $e->getFailureMessage()->getCode(),
116  'failureData' => $e->getFailureMessage()->getData(),
117  ] );
118  }
119  }
120  return $validatedParams;
121  }
122 
135  public function validateBody( RequestInterface $request, Handler $handler ) {
136  $method = strtoupper( trim( $request->getMethod() ) );
137 
138  // If the method should never have a body, don't bother validating.
139  if ( in_array( $method, self::NO_BODY_METHODS, true ) ) {
140  return null;
141  }
142 
143  // Get the content type
144  list( $ct ) = explode( ';', $request->getHeaderLine( 'Content-Type' ), 2 );
145  $ct = strtolower( trim( $ct ) );
146  if ( $ct === '' ) {
147  // No Content-Type was supplied. RFC 7231 ยง 3.1.1.5 allows this, but since it's probably a
148  // client error let's return a 415. But don't 415 for unknown methods and an empty body.
149  if ( !in_array( $method, self::BODY_METHODS, true ) ) {
150  $body = $request->getBody();
151  $size = $body->getSize();
152  if ( $size === null ) {
153  // No size available. Try reading 1 byte.
154  if ( $body->isSeekable() ) {
155  $body->rewind();
156  }
157  $size = $body->read( 1 ) === '' ? 0 : 1;
158  }
159  if ( $size === 0 ) {
160  return null;
161  }
162  }
163  throw new HttpException( "A Content-Type header must be supplied with a request payload.", 415, [
164  'error' => 'no-content-type',
165  ] );
166  }
167 
168  // Form data is parsed into $_POST and $_FILES by PHP and from there is accessed as parameters,
169  // don't bother trying to handle these via BodyValidator too.
170  if ( in_array( $ct, self::FORM_DATA_CONTENT_TYPES, true ) ) {
171  return null;
172  }
173 
174  // Validate the body. BodyValidator throws an HttpException on failure.
175  return $handler->getBodyValidator( $ct )->validateBody( $request );
176  }
177 
178 }
Base class for REST route handlers.
Definition: Handler.php:17
getBodyValidator( $contentType)
Fetch the BodyValidator.
Definition: Handler.php:271
const PARAM_SOURCE
(string) ParamValidator constant to specify the source of the parameter.
Definition: Handler.php:26
This is the base exception class for non-fatal exceptions thrown from REST handlers.
Wrapper for ParamValidator.
Definition: Validator.php:32
validateParams(array $paramSettings)
Validate parameters.
Definition: Validator.php:103
validateBody(RequestInterface $request, Handler $handler)
Validate the body of a request.
Definition: Validator.php:135
__construct(ObjectFactory $objectFactory, RequestInterface $request, Authority $authority)
Definition: Validator.php:83
Service for formatting and validating API parameters.
Type definition for boolean types.
Definition: BooleanDef.php:23
Type definition for enumeration types.
Definition: EnumDef.php:32
Type definition for expiry timestamps.
Definition: ExpiryDef.php:17
Type definition for a floating-point type.
Definition: FloatDef.php:29
Type definition for integer types.
Definition: IntegerDef.php:23
Type definition for "password" types.
Definition: PasswordDef.php:16
Type definition for string types.
Definition: StringDef.php:24
Type definition for timestamp types.
Type definition for upload types.
Definition: UploadDef.php:34
Error reporting for ParamValidator.
getParamValue()
Fetch the parameter value that failed validation.
getFailureMessage()
Fetch the validation failure message.
getParamName()
Fetch the parameter name that failed validation.
This interface represents the authority associated the current execution context, such as a web reque...
Definition: Authority.php:37
A request interface similar to PSR-7's ServerRequestInterface.
getMethod()
Retrieves the HTTP method of the request.
getBody()
Gets the body of the message.
getHeaderLine( $name)
Retrieves a comma-separated string of the values for a single header.