Created
February 7, 2016 18:36
-
-
Save JimBecher/59cf97d0ddb1c526f25d to your computer and use it in GitHub Desktop.
Uploader.php - Magento Permission adjustment to fix errors with uploaded images
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Magento | |
* | |
* NOTICE OF LICENSE | |
* | |
* This source file is subject to the Open Software License (OSL 3.0) | |
* that is bundled with this package in the file LICENSE.txt. | |
* It is also available through the world-wide-web at this URL: | |
* http://opensource.org/licenses/osl-3.0.php | |
* If you did not receive a copy of the license and are unable to | |
* obtain it through the world-wide-web, please send an email | |
* to license@magento.com so we can send you a copy immediately. | |
* | |
* DISCLAIMER | |
* | |
* Do not edit or add to this file if you wish to upgrade Magento to newer | |
* versions in the future. If you wish to customize Magento for your | |
* needs please refer to http://www.magento.com for more information. | |
* | |
* @category Varien | |
* @package Varien_File | |
* @copyright Copyright (c) 2006-2015 X.commerce, Inc. (http://www.magento.com) | |
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) | |
*/ | |
/** | |
* File upload class | |
* | |
* ATTENTION! This class must be used like abstract class and must added | |
* validation by protected file extension list to extended class | |
* | |
* @category Varien | |
* @package Varien_File | |
* @author Magento Core Team <core@magentocommerce.com> | |
*/ | |
class Varien_File_Uploader | |
{ | |
/** | |
* Uploaded file handle (copy of $_FILES[] element) | |
* | |
* @var array | |
* @access protected | |
*/ | |
protected $_file; | |
/** | |
* Uploaded file mime type | |
* | |
* @var string | |
* @access protected | |
*/ | |
protected $_fileMimeType; | |
/** | |
* Upload type. Used to right handle $_FILES array. | |
* | |
* @var Varien_File_Uploader::SINGLE_STYLE|Varien_File_Uploader::MULTIPLE_STYLE | |
* @access protected | |
*/ | |
protected $_uploadType; | |
/** | |
* The name of uploaded file. By default it is original file name, but when | |
* we will change file name, this variable will be changed too. | |
* | |
* @var string | |
* @access protected | |
*/ | |
protected $_uploadedFileName; | |
/** | |
* The name of destination directory | |
* | |
* @var string | |
* @access protected | |
*/ | |
protected $_uploadedFileDir; | |
/** | |
* If this variable is set to TRUE, our library will be able to automaticaly create | |
* non-existant directories. | |
* | |
* @var bool | |
* @access protected | |
*/ | |
protected $_allowCreateFolders = true; | |
/** | |
* If this variable is set to TRUE, uploaded file name will be changed if some file with the same | |
* name already exists in the destination directory (if enabled). | |
* | |
* @var bool | |
* @access protected | |
*/ | |
protected $_allowRenameFiles = false; | |
/** | |
* If this variable is set to TRUE, files despersion will be supported. | |
* | |
* @var bool | |
* @access protected | |
*/ | |
protected $_enableFilesDispersion = false; | |
/** | |
* This variable is used both with $_enableFilesDispersion == true | |
* It helps to avoid problems after migrating from case-insensitive file system to case-insensitive | |
* (e.g. NTFS->ext or ext->NTFS) | |
* | |
* @var bool | |
* @access protected | |
*/ | |
protected $_caseInsensitiveFilenames = true; | |
/** | |
* @var string | |
* @access protected | |
*/ | |
protected $_dispretionPath = null; | |
protected $_fileExists = false; | |
protected $_allowedExtensions = null; | |
/** | |
* List of valid MIME-Types. | |
* | |
* @var array | |
*/ | |
protected $_validMimeTypes = array(); | |
/** | |
* Validate callbacks storage | |
* | |
* @var array | |
* @access protected | |
*/ | |
protected $_validateCallbacks = array(); | |
const SINGLE_STYLE = 0; | |
const MULTIPLE_STYLE = 1; | |
const TMP_NAME_EMPTY = 666; | |
/** | |
* Resulting of uploaded file | |
* | |
* @var array|bool Array with file info keys: path, file. Result is | |
* FALSE when file not uploaded | |
*/ | |
protected $_result; | |
function __construct($fileId) | |
{ | |
$this->_setUploadFileId($fileId); | |
if(!file_exists($this->_file['tmp_name'])) { | |
$code = empty($this->_file['tmp_name']) ? self::TMP_NAME_EMPTY : 0; | |
throw new Exception('File was not uploaded.', $code); | |
} else { | |
$this->_fileExists = true; | |
} | |
} | |
/** | |
* After save logic | |
* | |
* @param array $result | |
* @return Varien_File_Uploader | |
*/ | |
protected function _afterSave($result) | |
{ | |
return $this; | |
} | |
/** | |
* Used to save uploaded file into destination folder with | |
* original or new file name (if specified) | |
* | |
* @param string $destinationFolder | |
* @param string $newFileName | |
* @access public | |
* @return void|bool | |
*/ | |
public function save($destinationFolder, $newFileName = null) | |
{ | |
$this->_validateFile(); | |
if ($this->_allowCreateFolders) { | |
$this->_createDestinationFolder($destinationFolder); | |
} | |
if (!is_writable($destinationFolder)) { | |
throw new Exception('Destination folder is not writable or does not exists.'); | |
} | |
$this->_result = false; | |
$destinationFile = $destinationFolder; | |
$fileName = isset($newFileName) ? $newFileName : $this->_file['name']; | |
$fileName = self::getCorrectFileName($fileName); | |
if ($this->_enableFilesDispersion) { | |
$fileName = $this->correctFileNameCase($fileName); | |
$this->setAllowCreateFolders(true); | |
$this->_dispretionPath = self::getDispretionPath($fileName); | |
$destinationFile.= $this->_dispretionPath; | |
$this->_createDestinationFolder($destinationFile); | |
} | |
if ($this->_allowRenameFiles) { | |
$fileName = self::getNewFileName(self::_addDirSeparator($destinationFile) . $fileName); | |
} | |
$destinationFile = self::_addDirSeparator($destinationFile) . $fileName; | |
$this->_result = $this->_moveFile($this->_file['tmp_name'], $destinationFile); | |
if ($this->_result) { | |
/** Fix - Changed Permissions - chmod($destinationFile, 0640); */ | |
chmod($destinationFile, 0644); | |
if ($this->_enableFilesDispersion) { | |
$fileName = str_replace(DIRECTORY_SEPARATOR, '/', | |
self::_addDirSeparator($this->_dispretionPath)) . $fileName; | |
} | |
$this->_uploadedFileName = $fileName; | |
$this->_uploadedFileDir = $destinationFolder; | |
$this->_result = $this->_file; | |
$this->_result['path'] = $destinationFolder; | |
$this->_result['file'] = $fileName; | |
$this->_afterSave($this->_result); | |
} | |
return $this->_result; | |
} | |
/** | |
* Move files from TMP folder into destination folder | |
* | |
* @param string $tmpPath | |
* @param string $destPath | |
* @return bool | |
*/ | |
protected function _moveFile($tmpPath, $destPath) | |
{ | |
return move_uploaded_file($tmpPath, $destPath); | |
} | |
/** | |
* Validate file before save | |
* | |
* @access public | |
*/ | |
protected function _validateFile() | |
{ | |
if ($this->_fileExists === false) { | |
return; | |
} | |
//is file extension allowed | |
if (!$this->checkAllowedExtension($this->getFileExtension())) { | |
throw new Exception('Disallowed file type.'); | |
} | |
/* | |
* Validate MIME-Types. | |
*/ | |
if (!$this->checkMimeType($this->_validMimeTypes)) { | |
throw new Exception('Invalid MIME type.'); | |
} | |
//run validate callbacks | |
foreach ($this->_validateCallbacks as $params) { | |
if (is_object($params['object']) && method_exists($params['object'], $params['method'])) { | |
$params['object']->$params['method']($this->_file['tmp_name']); | |
} | |
} | |
} | |
/** | |
* Returns extension of the uploaded file | |
* | |
* @return string | |
*/ | |
public function getFileExtension() | |
{ | |
return $this->_fileExists ? pathinfo($this->_file['name'], PATHINFO_EXTENSION) : ''; | |
} | |
/** | |
* Add validation callback model for us in self::_validateFile() | |
* | |
* @param string $callbackName | |
* @param object $callbackObject | |
* @param string $callbackMethod Method name of $callbackObject. It must | |
* have interface (string $tmpFilePath) | |
* @return Varien_File_Uploader | |
*/ | |
public function addValidateCallback($callbackName, $callbackObject, $callbackMethod) | |
{ | |
$this->_validateCallbacks[$callbackName] = array( | |
'object' => $callbackObject, | |
'method' => $callbackMethod | |
); | |
return $this; | |
} | |
/** | |
* Delete validation callback model for us in self::_validateFile() | |
* | |
* @param string $callbackName | |
* @access public | |
* @return Varien_File_Uploader | |
*/ | |
public function removeValidateCallback($callbackName) | |
{ | |
if (isset($this->_validateCallbacks[$callbackName])) { | |
unset($this->_validateCallbacks[$callbackName]); | |
} | |
return $this; | |
} | |
/** | |
* Correct filename with special chars and spaces | |
* | |
* @param string $fileName | |
* @return string | |
*/ | |
static public function getCorrectFileName($fileName) | |
{ | |
$fileName = preg_replace('/[^a-z0-9_\\-\\.]+/i', '_', $fileName); | |
$fileInfo = pathinfo($fileName); | |
if (preg_match('/^_+$/', $fileInfo['filename'])) { | |
$fileName = 'file.' . $fileInfo['extension']; | |
} | |
return $fileName; | |
} | |
/** | |
* Convert filename to lowercase in case of case-insensitive file names | |
* | |
* @param string | |
* @return string | |
*/ | |
public function correctFileNameCase($fileName) | |
{ | |
if ($this->_caseInsensitiveFilenames) { | |
return strtolower($fileName); | |
} | |
return $fileName; | |
} | |
static protected function _addDirSeparator($dir) | |
{ | |
if (substr($dir,-1) != DIRECTORY_SEPARATOR) { | |
$dir.= DIRECTORY_SEPARATOR; | |
} | |
return $dir; | |
} | |
/** | |
* Used to check if uploaded file mime type is valid or not | |
* | |
* @param array $validTypes | |
* @access public | |
* @return bool | |
*/ | |
public function checkMimeType($validTypes = array()) | |
{ | |
try { | |
if (count($validTypes) > 0) { | |
$validator = new Zend_Validate_File_MimeType($validTypes); | |
return $validator->isValid($this->_file['tmp_name']); | |
} | |
return true; | |
} catch (Exception $e) { | |
return false; | |
} | |
} | |
/** | |
* Returns a name of uploaded file | |
* | |
* @access public | |
* @return string | |
*/ | |
public function getUploadedFileName() | |
{ | |
return $this->_uploadedFileName; | |
} | |
/** | |
* Used to set {@link _allowCreateFolders} value | |
* | |
* @param mixed $flag | |
* @access public | |
* @return Varien_File_Uploader | |
*/ | |
public function setAllowCreateFolders($flag) | |
{ | |
$this->_allowCreateFolders = $flag; | |
return $this; | |
} | |
/** | |
* Used to set {@link _allowRenameFiles} value | |
* | |
* @param mixed $flag | |
* @access public | |
* @return Varien_File_Uploader | |
*/ | |
public function setAllowRenameFiles($flag) | |
{ | |
$this->_allowRenameFiles = $flag; | |
return $this; | |
} | |
/** | |
* Used to set {@link _enableFilesDispersion} value | |
* | |
* @param mixed $flag | |
* @access public | |
* @return Varien_File_Uploader | |
*/ | |
public function setFilesDispersion($flag) | |
{ | |
$this->_enableFilesDispersion = $flag; | |
return $this; | |
} | |
/** | |
* Filenames Case-sensitivity setter | |
* | |
* @param mixed $flag | |
* @return Varien_File_Uploader | |
*/ | |
public function setFilenamesCaseSensitivity($flag) | |
{ | |
$this->_caseInsensitiveFilenames = $flag; | |
return $this; | |
} | |
public function setAllowedExtensions($extensions = array()) | |
{ | |
foreach ((array)$extensions as $extension) { | |
$this->_allowedExtensions[] = strtolower($extension); | |
} | |
return $this; | |
} | |
/** | |
* Set valid MIME-types. | |
* | |
* @param array $mimeTypes | |
* @return Varien_File_Uploader | |
*/ | |
public function setValidMimeTypes($mimeTypes = array()) | |
{ | |
$this->_validMimeTypes = array(); | |
foreach ((array) $mimeTypes as $mimeType) { | |
$this->_validMimeTypes[] = $mimeType; | |
} | |
return $this; | |
} | |
/** | |
* Check if specified extension is allowed | |
* | |
* @param string $extension | |
* @return boolean | |
*/ | |
public function checkAllowedExtension($extension) | |
{ | |
if (!is_array($this->_allowedExtensions) || empty($this->_allowedExtensions)) { | |
return true; | |
} | |
return in_array(strtolower($extension), $this->_allowedExtensions); | |
} | |
/** | |
* @deprecated after 1.5.0.0-beta2 | |
* | |
* @param string $extension | |
* @return boolean | |
*/ | |
public function chechAllowedExtension($extension) | |
{ | |
return $this->checkAllowedExtension($extension); | |
} | |
private function _getMimeType() | |
{ | |
return $this->_file['type']; | |
} | |
private function _setUploadFileId($fileId) | |
{ | |
if (empty($_FILES)) { | |
throw new Exception('$_FILES array is empty', self::TMP_NAME_EMPTY); | |
} | |
if (is_array($fileId)) { | |
$this->_uploadType = self::MULTIPLE_STYLE; | |
$this->_file = $fileId; | |
} else { | |
preg_match("/^(.*?)\[(.*?)\]$/", $fileId, $file); | |
if (count($file) > 0 && (count($file[0]) > 0) && (count($file[1]) > 0)) { | |
array_shift($file); | |
$this->_uploadType = self::MULTIPLE_STYLE; | |
$fileAttributes = $_FILES[$file[0]]; | |
$tmp_var = array(); | |
foreach ($fileAttributes as $attributeName => $attributeValue) { | |
$tmp_var[$attributeName] = $attributeValue[$file[1]]; | |
} | |
$fileAttributes = $tmp_var; | |
$this->_file = $fileAttributes; | |
} elseif( count($fileId) > 0 && isset($_FILES[$fileId])) { | |
$this->_uploadType = self::SINGLE_STYLE; | |
$this->_file = $_FILES[$fileId]; | |
} elseif( $fileId == '' ) { | |
throw new Exception('Invalid parameter given. A valid $_FILES[] identifier is expected.'); | |
} | |
} | |
} | |
private function _createDestinationFolder($destinationFolder) | |
{ | |
if (!$destinationFolder) { | |
return $this; | |
} | |
if (substr($destinationFolder, -1) == DIRECTORY_SEPARATOR) { | |
$destinationFolder = substr($destinationFolder, 0, -1); | |
} | |
/** Previous - fixed Permissions - if (!(@is_dir($destinationFolder) || @mkdir($destinationFolder, 0750, true))) { */ | |
if (!(@is_dir($destinationFolder) || @mkdir($destinationFolder, 0755, true))) { | |
throw new Exception("Unable to create directory '{$destinationFolder}'."); | |
} | |
return $this; | |
} | |
static public function getNewFileName($destFile) | |
{ | |
$fileInfo = pathinfo($destFile); | |
if (file_exists($destFile)) { | |
$index = 1; | |
$baseName = $fileInfo['filename'] . '.' . $fileInfo['extension']; | |
while( file_exists($fileInfo['dirname'] . DIRECTORY_SEPARATOR . $baseName) ) { | |
$baseName = $fileInfo['filename']. '_' . $index . '.' . $fileInfo['extension']; | |
$index ++; | |
} | |
$destFileName = $baseName; | |
} else { | |
return $fileInfo['basename']; | |
} | |
return $destFileName; | |
} | |
static public function getDispretionPath($fileName) | |
{ | |
$char = 0; | |
$dispretionPath = ''; | |
while (($char < 2) && ($char < strlen($fileName))) { | |
if (empty($dispretionPath)) { | |
$dispretionPath = DIRECTORY_SEPARATOR | |
. ('.' == $fileName[$char] ? '_' : $fileName[$char]); | |
} else { | |
$dispretionPath = self::_addDirSeparator($dispretionPath) | |
. ('.' == $fileName[$char] ? '_' : $fileName[$char]); | |
} | |
$char ++; | |
} | |
return $dispretionPath; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment