ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
FileUploadImpl.php
Go to the documentation of this file.
1 <?php
2 
3 namespace ILIAS\FileUpload;
4 
21 
29 final class FileUploadImpl implements FileUpload
30 {
31 
39  private $filesystems;
47  private $processed;
51  private $moved;
55  private $uploadResult;
63  private $uploadStreams;
64 
65 
66 
67 
76  {
77  $this->processorManager = $processorManager;
78  $this->filesystems = $filesystems;
79  $this->globalHttpState = $globalHttpState;
80  $this->processed = false;
81  $this->moved = false;
82  $this->uploadResult = [];
83  $this->rejectedUploadResult = [];
84  }
85 
89  public function moveOneFileTo(UploadResult $uploadResult, $destination, $location = Location::STORAGE, $file_name = '', $override_existing = false)
90  {
91  if ($this->processed === false) {
92  throw new \RuntimeException('Can not move unprocessed files.');
93  }
94  $filesystem = $this->selectFilesystem($location);
95  $tempResults = [];
96 
97  if ($uploadResult->getStatus()->getCode() == ProcessingStatus::REJECTED) {
98  return false;
99  }
100 
101  try {
102  $path = rtrim($destination, "/") . '/' . ($file_name == "" ? $uploadResult->getName() : $file_name);
103  if ($override_existing && $filesystem->has($path)) {
104  $filesystem->delete($path);
105  }
106  $filesystem->writeStream($path, Streams::ofPsr7Stream($this->uploadStreams[$uploadResult->getPath()]));
107  $tempResults[] = $this->regenerateUploadResultWithPath($uploadResult, $path);
108  } catch (IOException $ex) {
109  $this->regenerateUploadResultWithCopyError($uploadResult, $ex->getMessage());
110  }
111  }
112 
113 
118  {
119  if ($this->processed === false) {
120  throw new \RuntimeException('Can not move unprocessed files.');
121  }
122 
123  if ($this->moved === true) {
124  throw new \RuntimeException('Can not move the files a second time.');
125  }
126 
127  $filesystem = $this->selectFilesystem($location);
128  $tempResults = [];
129 
130  foreach ($this->uploadResult as $key => $uploadResult) {
131  if ($uploadResult->getStatus()->getCode() == ProcessingStatus::REJECTED) {
132  continue;
133  }
134 
135  try {
136  $path = $destination . '/' . $uploadResult->getName();
137  $filesystem->writeStream($path, Streams::ofPsr7Stream($this->uploadStreams[$key]));
138  $tempResults[] = $this->regenerateUploadResultWithPath($uploadResult, $path);
139  } catch (IOException $ex) {
140  $this->regenerateUploadResultWithCopyError($uploadResult, $ex->getMessage());
141  }
142  }
143 
144  $this->uploadResult = $tempResults;
145  $this->uploadStreams = null;
146  $this->moved = true;
147  }
148 
149 
159  {
160  return new UploadResult(
161  $result->getName(),
162  $result->getSize(),
163  $result->getMimeType(),
164  $result->getMetaData(),
165  $result->getStatus(),
166  $path
167  );
168  }
169 
170 
180  {
181  return new UploadResult(
182  $result->getName(),
183  $result->getSize(),
184  $result->getMimeType(),
185  $result->getMetaData(),
186  new ProcessingStatus(ProcessingStatus::REJECTED, $errorReason),
187  ''
188  );
189  }
190 
191 
203  private function selectFilesystem($location)
204  {
205  switch ($location) {
207  return $this->filesystems->customizing();
208  case Location::STORAGE:
209  return $this->filesystems->storage();
210  case Location::WEB:
211  return $this->filesystems->web();
212  case Location::TEMPORARY:
213  return $this->filesystems->temp();
214  default:
215  throw new \InvalidArgumentException("No filesystem found for location code \"$location\"");
216  }
217  }
218 
219 
223  public function uploadSizeLimit()
224  {
225  return \ilUtil::getUploadSizeLimitBytes();
226  }
227 
228 
232  public function register(PreProcessor $preProcessor)
233  {
234  if ($this->processed === false) {
235  $this->processorManager->with($preProcessor);
236  } else {
237  throw new IllegalStateException('Can not register processor after the upload was processed.');
238  }
239  }
240 
241 
245  public function process()
246  {
247  if ($this->processed === true) {
248  throw new IllegalStateException('Can not reprocess the uploaded files.');
249  }
250 
254  $uploadedFiles = $this->globalHttpState->request()->getUploadedFiles();
255  $collectFilesFromNestedFields = $this->flattenUploadedFiles($uploadedFiles);
256  foreach ($collectFilesFromNestedFields as $file) {
257  $metadata = new Metadata($file->getClientFilename(), $file->getSize(), $file->getClientMediaType());
258  try {
259  $stream = Streams::ofPsr7Stream($file->getStream());
260  } catch (\RuntimeException $e) {
261  $this->rejectFailedUpload($file, $metadata);
262  continue;
263  }
264 
265  // we take the temporary file name as an identifier as it is the only unique attribute.
266  $identifier = $file->getStream()->getMetadata('uri');
267 
268  $identifier = is_array($identifier) ? '' : $identifier;
269 
270  $this->uploadStreams[$identifier] = $stream;
271 
272  if ($file->getError() === UPLOAD_ERR_OK) {
273  $processingResult = $this->processorManager->process($stream, $metadata);
274  $result = new UploadResult(
275  $metadata->getFilename(),
276  $metadata->getUploadSize(),
277  $metadata->getMimeType(),
278  $metadata->additionalMetaData(),
279  $processingResult,
280  is_string($identifier)?$identifier:''
281  );
282  $this->uploadResult[$identifier] = $result;
283  } else {
284  $this->rejectFailedUpload($file, $metadata);
285  }
286  }
287 
288  $this->processed = true;
289  }
290 
291 
301  {
302  //reject failed upload
303  $processingStatus = new ProcessingStatus(ProcessingStatus::REJECTED, 'Upload failed');
304  $extraMetadata = new ImmutableMapWrapper(new EntryLockingStringMap());
305  $result = new UploadResult(
306  $metadata->getFilename(),
307  $metadata->getUploadSize(),
308  $metadata->getMimeType(),
309  $extraMetadata,
310  $processingStatus,
311  ''
312  );
313 
314  $this->rejectedUploadResult[] = $result;
315  }
316 
317 
321  public function getResults()
322  {
323  if ($this->processed) {
324  return array_merge($this->uploadResult, $this->rejectedUploadResult);
325  }
326 
327  throw new IllegalStateException('Can not fetch results without processing the uploads.');
328  }
329 
330 
334  public function hasUploads()
335  {
336  if ($this->moved) {
337  return false;
338  }
339 
340  $uploadedFiles = $this->flattenUploadedFiles($this->globalHttpState->request()->getUploadedFiles());
341 
342  return (count($uploadedFiles) > 0);
343  }
344 
345 
351  protected function flattenUploadedFiles($uploadedFiles)
352  {
353  $recursiveIterator = new RecursiveIteratorIterator(
355  $uploadedFiles,
356  RecursiveArrayIterator::CHILD_ARRAYS_ONLY
357  ),
358  RecursiveIteratorIterator::LEAVES_ONLY
359  );
360 
361  return iterator_to_array($recursiveIterator, false);
362  }
363 
364 
368  public function hasBeenProcessed()
369  {
370  return $this->processed;
371  }
372 }
rejectFailedUpload(UploadedFileInterface $file, Metadata $metadata)
Reject a failed upload with the given metadata.
Interface GlobalHttpState.
$path
Definition: aliased.php:25
const REJECTED
Upload got rejected by a processor.
process()
Invokes all preprocessors for each uploaded file in the sequence they got registered.
$result
moveFilesTo($destination, $location=Location::STORAGE)
const STORAGE
The filesystem outside of the ilias web root.
Definition: Location.php:28
$location
Definition: buildRTE.php:44
$destination
__construct(PreProcessorManager $processorManager, Filesystems $filesystems, GlobalHttpState $globalHttpState)
FileUploadImpl constructor.
regenerateUploadResultWithCopyError(UploadResult $result, $errorReason)
Creates a clone of the given result and set the status to rejected with the passed error message...
moveOneFileTo(UploadResult $uploadResult, $destination, $location=Location::STORAGE, $file_name='', $override_existing=false)
Moves a single File (the attributes, metadata and upload-status of which are contained in UploadResul...
getMimeType()
Client supplied mime type of the uploaded.
Definition: Metadata.php:118
selectFilesystem($location)
Selects the correct filesystem by the given Location constant.
$metadata['__DYNAMIC:1__']
$stream
PHP stream implementation.
getFilename()
The filename supplied by the browser.
Definition: Metadata.php:73
getUploadSize()
This is always the original file size which was determined by the http service.
Definition: Metadata.php:105
static filesystems()
Returns the loaded filesystems.
const CUSTOMIZING
The filesystem within the web root where all the skins and plugins are saved.
Definition: Location.php:33
Class FileUpload.
Definition: FileUpload.php:21
regenerateUploadResultWithPath(UploadResult $result, $path)
Generate an exact copy of the result with the given path.
const TEMPORARY
The ILIAS temporary directory.
Definition: Location.php:38
$key
Definition: croninfo.php:18
Value object representing a file uploaded through an HTTP request.
const WEB
The filesystem within the ilias web root.
Definition: Location.php:23
Class Filesystems.
Definition: Filesystems.php:16
static ofPsr7Stream(StreamInterface $stream)
Create a FileStream from a Psr7 compliant stream.
Definition: Streams.php:69