File: UploadedFile.php

package info (click to toggle)
mediawiki 1%3A1.43.3%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 417,464 kB
  • sloc: php: 1,062,949; javascript: 664,290; sql: 9,714; python: 5,458; xml: 3,489; sh: 1,131; makefile: 64
file content (139 lines) | stat: -rw-r--r-- 3,614 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
<?php

namespace Wikimedia\ParamValidator\Util;

use Psr\Http\Message\UploadedFileInterface;
use RuntimeException;
use Wikimedia\AtEase\AtEase;

/**
 * A simple implementation of UploadedFileInterface
 *
 * This exists so ParamValidator needn't depend on any specific PSR-7
 * implementation for a class implementing UploadedFileInterface. It shouldn't
 * be used directly by other code, other than perhaps when implementing
 * Callbacks::getUploadedFile() when another PSR-7 library is not already in use.
 *
 * @since 1.34
 * @unstable
 */
class UploadedFile implements UploadedFileInterface {

	/** @var array File data */
	private $data;

	/** @var bool */
	private $fromUpload;

	/** @var UploadedFileStream|null */
	private $stream = null;

	/** @var bool Whether moveTo() was called */
	private $moved = false;

	/**
	 * @param array $data Data from $_FILES
	 * @param bool $fromUpload Set false if using this task with data not from
	 *  $_FILES. Intended for unit testing.
	 */
	public function __construct( array $data, $fromUpload = true ) {
		$this->data = $data;
		$this->fromUpload = $fromUpload;
	}

	/**
	 * Throw if there was an error
	 * @throws RuntimeException
	 */
	private function checkError() {
		switch ( $this->data['error'] ) {
			case UPLOAD_ERR_OK:
				break;

			case UPLOAD_ERR_INI_SIZE:
				throw new RuntimeException( 'Upload exceeded maximum size' );

			case UPLOAD_ERR_FORM_SIZE:
				throw new RuntimeException( 'Upload exceeded form-specified maximum size' );

			case UPLOAD_ERR_PARTIAL:
				throw new RuntimeException( 'File was only partially uploaded' );

			case UPLOAD_ERR_NO_FILE:
				throw new RuntimeException( 'No file was uploaded' );

			case UPLOAD_ERR_NO_TMP_DIR:
				throw new RuntimeException( 'PHP has no temporary folder for storing uploaded files' );

			case UPLOAD_ERR_CANT_WRITE:
				throw new RuntimeException( 'PHP was unable to save the uploaded file' );

			case UPLOAD_ERR_EXTENSION:
				throw new RuntimeException( 'A PHP extension stopped the file upload' );

			default:
				throw new RuntimeException( 'Unknown upload error code ' . $this->data['error'] );
		}

		if ( $this->moved ) {
			throw new RuntimeException( 'File has already been moved' );
		}
		if ( !isset( $this->data['tmp_name'] ) || !file_exists( $this->data['tmp_name'] ) ) {
			throw new RuntimeException( 'Uploaded file is missing' );
		}
	}

	public function getStream() {
		if ( $this->stream ) {
			return $this->stream;
		}

		$this->checkError();
		$this->stream = new UploadedFileStream( $this->data['tmp_name'] );
		return $this->stream;
	}

	public function moveTo( $targetPath ) {
		$this->checkError();

		if ( $this->fromUpload && !is_uploaded_file( $this->data['tmp_name'] ) ) {
			throw new RuntimeException( 'Specified file is not an uploaded file' );
		}

		error_clear_last();
		$ret = AtEase::quietCall(
			$this->fromUpload ? 'move_uploaded_file' : 'rename',
			$this->data['tmp_name'],
			$targetPath
		);
		if ( $ret === false ) {
			$err = error_get_last();
			throw new RuntimeException( "Move failed: " . ( $err['message'] ?? 'Unknown error' ) );
		}

		$this->moved = true;
		if ( $this->stream ) {
			$this->stream->close();
			$this->stream = null;
		}
	}

	public function getSize() {
		return $this->data['size'] ?? null;
	}

	public function getError() {
		return $this->data['error'] ?? UPLOAD_ERR_NO_FILE;
	}

	public function getClientFilename() {
		$ret = $this->data['name'] ?? null;
		return $ret === '' ? null : $ret;
	}

	public function getClientMediaType() {
		$ret = $this->data['type'] ?? null;
		return $ret === '' ? null : $ret;
	}

}