Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
Uploader.php
Go to the documentation of this file.
1 <?php
6 namespace Magento\Framework\File;
7 
17 class Uploader
18 {
25  protected $_file;
26 
33  protected $_fileMimeType;
34 
41  protected $_uploadType;
42 
50  protected $_uploadedFileName;
51 
58  protected $_uploadedFileDir;
59 
67  protected $_allowCreateFolders = true;
68 
76  protected $_allowRenameFiles = false;
77 
84  protected $_enableFilesDispersion = false;
85 
94  protected $_caseInsensitiveFilenames = true;
95 
100  protected $_dispretionPath = null;
101 
105  protected $_fileExists = false;
106 
110  protected $_allowedExtensions = null;
111 
118  protected $_validateCallbacks = [];
119 
123  private $fileMime;
124 
128  const SINGLE_STYLE = 0;
129 
130  const MULTIPLE_STYLE = 1;
131 
137  const TMP_NAME_EMPTY = 666;
138 
144  const MAX_IMAGE_WIDTH = 4096;
145 
151  const MAX_IMAGE_HEIGHT = 2160;
152 
159  protected $_result;
160 
168  public function __construct(
169  $fileId,
170  Mime $fileMime = null
171  ) {
172  $this->_setUploadFileId($fileId);
173  if (!file_exists($this->_file['tmp_name'])) {
174  $code = empty($this->_file['tmp_name']) ? self::TMP_NAME_EMPTY : 0;
175  throw new \Exception('The file was not uploaded.', $code);
176  } else {
177  $this->_fileExists = true;
178  }
179  $this->fileMime = $fileMime ?: \Magento\Framework\App\ObjectManager::getInstance()->get(Mime::class);
180  }
181 
189  protected function _afterSave($result)
190  {
191  return $this;
192  }
193 
203  public function save($destinationFolder, $newFileName = null)
204  {
205  $this->_validateFile();
206  $this->validateDestination($destinationFolder);
207 
208  $this->_result = false;
209  $destinationFile = $destinationFolder;
210  $fileName = isset($newFileName) ? $newFileName : $this->_file['name'];
211  $fileName = static::getCorrectFileName($fileName);
212  if ($this->_enableFilesDispersion) {
214  $this->setAllowCreateFolders(true);
215  $this->_dispretionPath = static::getDispersionPath($fileName);
216  $destinationFile .= $this->_dispretionPath;
217  $this->_createDestinationFolder($destinationFile);
218  }
219 
220  if ($this->_allowRenameFiles) {
221  $fileName = static::getNewFileName(
222  static::_addDirSeparator($destinationFile) . $fileName
223  );
224  }
225 
226  $destinationFile = static::_addDirSeparator($destinationFile) . $fileName;
227 
228  try {
229  $this->_result = $this->_moveFile($this->_file['tmp_name'], $destinationFile);
230  } catch (\Exception $e) {
231  // if the file exists and we had an exception continue anyway
232  if (file_exists($destinationFile)) {
233  $this->_result = true;
234  } else {
235  throw $e;
236  }
237  }
238 
239  if ($this->_result) {
240  if ($this->_enableFilesDispersion) {
241  $fileName = str_replace('\\', '/', self::_addDirSeparator($this->_dispretionPath)) . $fileName;
242  }
243  $this->_uploadedFileName = $fileName;
244  $this->_uploadedFileDir = $destinationFolder;
245  $this->_result = $this->_file;
246  $this->_result['path'] = $destinationFolder;
247  $this->_result['file'] = $fileName;
248 
249  $this->_afterSave($this->_result);
250  }
251 
252  return $this->_result;
253  }
254 
262  private function validateDestination($destinationFolder)
263  {
264  if ($this->_allowCreateFolders) {
265  $this->_createDestinationFolder($destinationFolder);
266  }
267 
268  if (!is_writable($destinationFolder)) {
269  throw new \Exception('Destination folder is not writable or does not exists.');
270  }
271  }
272 
281  protected function chmod($file)
282  {
283  chmod($file, 0777);
284  }
285 
293  protected function _moveFile($tmpPath, $destPath)
294  {
295  if (is_uploaded_file($tmpPath)) {
296  return move_uploaded_file($tmpPath, $destPath);
297  } elseif (is_file($tmpPath)) {
298  return rename($tmpPath, $destPath);
299  }
300  }
301 
308  protected function _validateFile()
309  {
310  if ($this->_fileExists === false) {
311  return;
312  }
313 
314  //is file extension allowed
315  if (!$this->checkAllowedExtension($this->getFileExtension())) {
316  throw new \Exception('Disallowed file type.');
317  }
318  //run validate callbacks
319  foreach ($this->_validateCallbacks as $params) {
320  if (is_object($params['object'])
321  && method_exists($params['object'], $params['method'])
322  && is_callable([$params['object'], $params['method']])
323  ) {
324  $params['object']->{$params['method']}($this->_file['tmp_name']);
325  }
326  }
327  }
328 
334  public function getFileExtension()
335  {
336  return $this->_fileExists ? pathinfo($this->_file['name'], PATHINFO_EXTENSION) : '';
337  }
338 
348  public function addValidateCallback($callbackName, $callbackObject, $callbackMethod)
349  {
350  $this->_validateCallbacks[$callbackName] = ['object' => $callbackObject, 'method' => $callbackMethod];
351  return $this;
352  }
353 
361  public function removeValidateCallback($callbackName)
362  {
363  if (isset($this->_validateCallbacks[$callbackName])) {
364  unset($this->_validateCallbacks[$callbackName]);
365  }
366  return $this;
367  }
368 
375  public static function getCorrectFileName($fileName)
376  {
377  $fileName = preg_replace('/[^a-z0-9_\\-\\.]+/i', '_', $fileName);
378  $fileInfo = pathinfo($fileName);
379 
380  if (preg_match('/^_+$/', $fileInfo['filename'])) {
381  $fileName = 'file.' . $fileInfo['extension'];
382  }
383  return $fileName;
384  }
385 
393  {
394  if ($this->_caseInsensitiveFilenames) {
395  return strtolower($fileName);
396  }
397  return $fileName;
398  }
399 
406  protected static function _addDirSeparator($dir)
407  {
408  if (substr($dir, -1) != '/') {
409  $dir .= '/';
410  }
411  return $dir;
412  }
413 
421  public function checkMimeType($validTypes = [])
422  {
423  if (count($validTypes) > 0) {
424  if (!in_array($this->_getMimeType(), $validTypes)) {
425  return false;
426  }
427  }
428  return true;
429  }
430 
437  public function getUploadedFileName()
438  {
439  return $this->_uploadedFileName;
440  }
441 
449  public function setAllowCreateFolders($flag)
450  {
451  $this->_allowCreateFolders = $flag;
452  return $this;
453  }
454 
462  public function setAllowRenameFiles($flag)
463  {
464  $this->_allowRenameFiles = $flag;
465  return $this;
466  }
467 
475  public function setFilesDispersion($flag)
476  {
477  $this->_enableFilesDispersion = $flag;
478  return $this;
479  }
480 
487  public function setFilenamesCaseSensitivity($flag)
488  {
489  $this->_caseInsensitiveFilenames = $flag;
490  return $this;
491  }
492 
499  public function setAllowedExtensions($extensions = [])
500  {
501  foreach ((array)$extensions as $extension) {
502  $this->_allowedExtensions[] = strtolower($extension);
503  }
504  return $this;
505  }
506 
514  {
515  if (!is_array($this->_allowedExtensions) || empty($this->_allowedExtensions)) {
516  return true;
517  }
518 
519  return in_array(strtolower($extension), $this->_allowedExtensions);
520  }
521 
527  private function _getMimeType()
528  {
529  return $this->fileMime->getMimeType($this->_file['tmp_name']);
530  }
531 
540  private function _setUploadFileId($fileId)
541  {
542  if (is_array($fileId)) {
543  $this->_uploadType = self::MULTIPLE_STYLE;
544  $this->_file = $fileId;
545  } else {
546  if (empty($_FILES)) {
547  throw new \Exception('$_FILES array is empty');
548  }
549 
550  preg_match("/^(.*?)\[(.*?)\]$/", $fileId, $file);
551 
552  if (is_array($file) && count($file) > 0 && count($file[0]) > 0 && count($file[1]) > 0) {
553  array_shift($file);
554  $this->_uploadType = self::MULTIPLE_STYLE;
555 
556  $fileAttributes = $_FILES[$file[0]];
557  $tmpVar = [];
558 
559  foreach ($fileAttributes as $attributeName => $attributeValue) {
560  $tmpVar[$attributeName] = $attributeValue[$file[1]];
561  }
562 
563  $fileAttributes = $tmpVar;
564  $this->_file = $fileAttributes;
565  } elseif (!empty($fileId) && isset($_FILES[$fileId])) {
566  $this->_uploadType = self::SINGLE_STYLE;
567  $this->_file = $_FILES[$fileId];
568  } elseif ($fileId == '') {
569  throw new \Exception('Invalid parameter given. A valid $_FILES[] identifier is expected.');
570  }
571  }
572  }
573 
581  private function _createDestinationFolder($destinationFolder)
582  {
583  if (!$destinationFolder) {
584  return $this;
585  }
586 
587  if (substr($destinationFolder, -1) == '/') {
588  $destinationFolder = substr($destinationFolder, 0, -1);
589  }
590 
591  if (!(@is_dir($destinationFolder)
592  || @mkdir($destinationFolder, 0777, true)
593  )) {
594  throw new \Exception("Unable to create directory '{$destinationFolder}'.");
595  }
596  return $this;
597  }
598 
605  public static function getNewFileName($destinationFile)
606  {
607  $fileInfo = pathinfo($destinationFile);
608  if (file_exists($destinationFile)) {
609  $index = 1;
610  $baseName = $fileInfo['filename'] . '.' . $fileInfo['extension'];
611  while (file_exists($fileInfo['dirname'] . '/' . $baseName)) {
612  $baseName = $fileInfo['filename'] . '_' . $index . '.' . $fileInfo['extension'];
613  $index++;
614  }
615  $destFileName = $baseName;
616  } else {
617  return $fileInfo['basename'];
618  }
619 
620  return $destFileName;
621  }
622 
630  public static function getDispretionPath($fileName)
631  {
632  return self::getDispersionPath($fileName);
633  }
634 
642  public static function getDispersionPath($fileName)
643  {
644  $char = 0;
645  $dispertionPath = '';
646  while ($char < 2 && $char < strlen($fileName)) {
647  if (empty($dispertionPath)) {
648  $dispertionPath = '/' . ('.' == $fileName[$char] ? '_' : $fileName[$char]);
649  } else {
650  $dispertionPath = self::_addDirSeparator(
651  $dispertionPath
652  ) . ('.' == $fileName[$char] ? '_' : $fileName[$char]);
653  }
654  $char++;
655  }
656  return $dispertionPath;
657  }
658 }
removeValidateCallback($callbackName)
Definition: Uploader.php:361
addValidateCallback($callbackName, $callbackObject, $callbackMethod)
Definition: Uploader.php:348
elseif(isset( $params[ 'redirect_parent']))
Definition: iframe.phtml:17
static getDispretionPath($fileName)
Definition: Uploader.php:630
static getCorrectFileName($fileName)
Definition: Uploader.php:375
setAllowedExtensions($extensions=[])
Definition: Uploader.php:499
__construct( $fileId, Mime $fileMime=null)
Definition: Uploader.php:168
$fileName
Definition: translate.phtml:15
rename($oldPath, $newPath, DriverInterface $targetDriver=null)
Definition: File.php:286
is_writable($path)
Definition: io.php:25
mkdir($pathname, $mode=0777, $recursive=false, $context=null)
Definition: ioMock.php:25
$params[\Magento\Store\Model\StoreManager::PARAM_RUN_CODE]
Definition: website.php:18
static getNewFileName($destinationFile)
Definition: Uploader.php:605
checkMimeType($validTypes=[])
Definition: Uploader.php:421
$index
Definition: list.phtml:44
save($destinationFolder, $newFileName=null)
Definition: Uploader.php:203
static getDispersionPath($fileName)
Definition: Uploader.php:642
$code
Definition: info.phtml:12
_moveFile($tmpPath, $destPath)
Definition: Uploader.php:293