MediaWiki  master
UploadDef.php
Go to the documentation of this file.
1 <?php
2 
4 
5 use InvalidArgumentException;
6 use Psr\Http\Message\UploadedFileInterface;
7 use UnexpectedValueException;
12 
34 class UploadDef extends TypeDef {
35 
36  public function getValue( $name, array $settings, array $options ) {
37  $ret = $this->callbacks->getUploadedFile( $name, $options );
38 
39  if ( $ret && $ret->getError() === UPLOAD_ERR_NO_FILE &&
40  !$this->callbacks->hasParam( $name, $options )
41  ) {
42  // This seems to be that the client explicitly specified "no file" for the field
43  // instead of just omitting the field completely. DWTM.
44  $ret = null;
45  } elseif ( !$ret && $this->callbacks->hasParam( $name, $options ) ) {
46  // The client didn't format their upload properly so it came in as an ordinary
47  // field. Convert it to an error.
48  $ret = new UploadedFile( [
49  'name' => '',
50  'type' => '',
51  'tmp_name' => '',
52  'error' => -42, // PHP's UPLOAD_ERR_* are all positive numbers.
53  'size' => 0,
54  ] );
55  }
56 
57  return $ret;
58  }
59 
69  protected function getIniSize() {
70  return ini_get( 'upload_max_filesize' );
71  }
72 
73  public function validate( $name, $value, array $settings, array $options ) {
74  static $codemap = [
75  -42 => 'notupload', // Local from getValue()
76  UPLOAD_ERR_FORM_SIZE => 'formsize',
77  UPLOAD_ERR_PARTIAL => 'partial',
78  UPLOAD_ERR_NO_FILE => 'nofile',
79  UPLOAD_ERR_NO_TMP_DIR => 'notmpdir',
80  UPLOAD_ERR_CANT_WRITE => 'cantwrite',
81  UPLOAD_ERR_EXTENSION => 'phpext',
82  ];
83 
84  if ( !$value instanceof UploadedFileInterface ) {
85  // Err?
86  $type = is_object( $value ) ? get_class( $value ) : gettype( $value );
87  throw new InvalidArgumentException( "\$value must be UploadedFileInterface, got $type" );
88  }
89 
90  $err = $value->getError();
91  if ( $err === UPLOAD_ERR_OK ) {
92  return $value;
93  } elseif ( $err === UPLOAD_ERR_INI_SIZE ) {
94  static $prefixes = [
95  'g' => 1024 ** 3,
96  'm' => 1024 ** 2,
97  'k' => 1024 ** 1,
98  ];
99  $size = $this->getIniSize();
100  $last = strtolower( substr( $size, -1 ) );
101  $size = intval( $size, 10 ) * ( $prefixes[$last] ?? 1 );
102  $this->failure(
103  $this->failureMessage( 'badupload', [
104  'code' => 'inisize',
105  'size' => $size,
106  ], 'inisize' )->sizeParams( $size ),
107  $name, '', $settings, $options
108  );
109  } elseif ( isset( $codemap[$err] ) ) {
110  $this->failure(
111  $this->failureMessage( 'badupload', [ 'code' => $codemap[$err] ], $codemap[$err] ),
112  $name, '', $settings, $options
113  );
114  } else {
115  $constant = '';
116  foreach ( get_defined_constants() as $c => $v ) {
117  // @phan-suppress-next-line PhanTypeComparisonFromArray
118  if ( $v === $err && str_starts_with( $c, 'UPLOAD_ERR_' ) ) {
119  $constant = " ($c?)";
120  }
121  }
122  throw new UnexpectedValueException( "Unrecognized PHP upload error value $err$constant" );
123  }
124  }
125 
126  public function checkSettings( string $name, $settings, array $options, array $ret ): array {
127  $ret = parent::checkSettings( $name, $settings, $options, $ret );
128 
129  if ( isset( $settings[ParamValidator::PARAM_DEFAULT] ) ) {
130  $ret['issues'][ParamValidator::PARAM_DEFAULT] =
131  'Cannot specify a default for upload-type parameters';
132  }
133 
134  if ( !empty( $settings[ParamValidator::PARAM_ISMULTI] ) &&
135  !isset( $ret['issues'][ParamValidator::PARAM_ISMULTI] )
136  ) {
137  $ret['issues'][ParamValidator::PARAM_ISMULTI] =
138  'PARAM_ISMULTI cannot be used for upload-type parameters';
139  }
140 
141  return $ret;
142  }
143 
144  public function stringifyValue( $name, $value, array $settings, array $options ) {
145  // Not going to happen.
146  return null;
147  }
148 
149  public function getHelpInfo( $name, array $settings, array $options ) {
150  $info = parent::getHelpInfo( $name, $settings, $options );
151 
152  $info[ParamValidator::PARAM_TYPE] = MessageValue::new( 'paramvalidator-help-type-upload' );
153 
154  return $info;
155  }
156 
157 }
Value object representing a message for i18n.
static new( $key, $params=[])
Static constructor for easier chaining of ->params() methods.
Service for formatting and validating API parameters.
const PARAM_ISMULTI
(bool) Indicate that the parameter is multi-valued.
const PARAM_DEFAULT
(mixed) Default value of the parameter.
const PARAM_TYPE
(string|array) Type of the parameter.
Type definition for upload types.
Definition: UploadDef.php:34
checkSettings(string $name, $settings, array $options, array $ret)
Validate a parameter settings array.
Definition: UploadDef.php:126
getHelpInfo( $name, array $settings, array $options)
Describe parameter settings in human-readable format.
Definition: UploadDef.php:149
getIniSize()
Fetch the value of PHP's upload_max_filesize ini setting.
Definition: UploadDef.php:69
stringifyValue( $name, $value, array $settings, array $options)
Convert a value to a string representation.
Definition: UploadDef.php:144
getValue( $name, array $settings, array $options)
Get the value from the request.
Definition: UploadDef.php:36
validate( $name, $value, array $settings, array $options)
Validate the value.
Definition: UploadDef.php:73
Base definition for ParamValidator types.
Definition: TypeDef.php:19
failureMessage( $code, array $data=null, $suffix=null)
Create a DataMessageValue representing a failure.
Definition: TypeDef.php:84
failure( $failure, $name, $value, array $settings, array $options, $fatal=true)
Record a failure message.
Definition: TypeDef.php:49
A simple implementation of UploadedFileInterface.