MediaWiki REL1_39
Validator.php
Go to the documentation of this file.
1<?php
2
4
12use Wikimedia\ObjectFactory\ObjectFactory;
24
32class 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' ];
64
66 private const BODY_METHODS = [ 'POST', 'PUT' ];
67
68 // NOTE: per RFC 7231 (https://www.rfc-editor.org/rfc/rfc7231#section-4.3.5), sending a body
69 // with the DELETE method "has no defined semantics". We allow it, as it is useful for
70 // passing the csrf token required by some authentication methods.
71
73 private const FORM_DATA_CONTENT_TYPES = [
74 'application/x-www-form-urlencoded',
75 'multipart/form-data',
76 ];
77
79 private $paramValidator;
80
87 public function __construct(
88 ObjectFactory $objectFactory,
89 RequestInterface $request,
90 Authority $authority
91 ) {
92 $this->paramValidator = new ParamValidator(
93 new ParamValidatorCallbacks( $request, $authority ),
94 $objectFactory,
95 [
96 'typeDefs' => self::TYPE_DEFS,
97 ]
98 );
99 }
100
107 public function validateParams( array $paramSettings ) {
108 $validatedParams = [];
109 foreach ( $paramSettings as $name => $settings ) {
110 try {
111 $validatedParams[$name] = $this->paramValidator->getValue( $name, $settings, [
112 'source' => $settings[Handler::PARAM_SOURCE] ?? 'unspecified',
113 ] );
114 } catch ( ValidationException $e ) {
115 throw new LocalizedHttpException( $e->getFailureMessage(), 400, [
116 'error' => 'parameter-validation-failed',
117 'name' => $e->getParamName(),
118 'value' => $e->getParamValue(),
119 'failureCode' => $e->getFailureMessage()->getCode(),
120 'failureData' => $e->getFailureMessage()->getData(),
121 ] );
122 }
123 }
124 return $validatedParams;
125 }
126
139 public function validateBody( RequestInterface $request, Handler $handler ) {
140 $method = strtoupper( trim( $request->getMethod() ) );
141
142 // If the method should never have a body, don't bother validating.
143 if ( in_array( $method, self::NO_BODY_METHODS, true ) ) {
144 return null;
145 }
146
147 // Get the content type
148 list( $ct ) = explode( ';', $request->getHeaderLine( 'Content-Type' ), 2 );
149 $ct = strtolower( trim( $ct ) );
150 if ( $ct === '' ) {
151 // No Content-Type was supplied. RFC 7231 ยง 3.1.1.5 allows this, but since it's probably a
152 // client error let's return a 415. But don't 415 for unknown methods and an empty body.
153 if ( !in_array( $method, self::BODY_METHODS, true ) ) {
154 $body = $request->getBody();
155 $size = $body->getSize();
156 if ( $size === null ) {
157 // No size available. Try reading 1 byte.
158 if ( $body->isSeekable() ) {
159 $body->rewind();
160 }
161 $size = $body->read( 1 ) === '' ? 0 : 1;
162 }
163 if ( $size === 0 ) {
164 return null;
165 }
166 }
167 throw new HttpException( "A Content-Type header must be supplied with a request payload.", 415, [
168 'error' => 'no-content-type',
169 ] );
170 }
171
172 // Form data is parsed into $_POST and $_FILES by PHP and from there is accessed as parameters,
173 // don't bother trying to handle these via BodyValidator too.
174 if ( in_array( $ct, self::FORM_DATA_CONTENT_TYPES, true ) ) {
175 return null;
176 }
177
178 // Validate the body. BodyValidator throws an HttpException on failure.
179 return $handler->getBodyValidator( $ct )->validateBody( $request );
180 }
181
182}
Type definition for page titles.
Definition TitleDef.php:22
Type definition for user types.
Definition UserDef.php:27
Base class for REST route handlers.
Definition Handler.php:20
getBodyValidator( $contentType)
Fetch the BodyValidator.
Definition Handler.php:325
const PARAM_SOURCE
(string) ParamValidator constant to specify the source of the parameter.
Definition Handler.php:29
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.
validateBody(RequestInterface $request, Handler $handler)
Validate the body of a request.
__construct(ObjectFactory $objectFactory, RequestInterface $request, Authority $authority)
Definition Validator.php:87
Service for formatting and validating API parameters.
Type definition for boolean types.
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.
Type definition for "password" types.
Type definition for string types.
Definition StringDef.php:24
Type definition for timestamp types.
Type definition for upload types.
Definition UploadDef.php:34
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.
Copyright (C) 2011-2020 Wikimedia Foundation and others.