PageRenderTime 52ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/Varien/File/Uploader.php

https://github.com/guiohm/magento-french
PHP | 513 lines | 274 code | 55 blank | 184 comment | 49 complexity | 4698889a5ce18962cf7c578b844cac1c MD5 | raw file
  1. <?php
  2. /**
  3. * Magento
  4. *
  5. * NOTICE OF LICENSE
  6. *
  7. * This source file is subject to the Open Software License (OSL 3.0)
  8. * that is bundled with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://opensource.org/licenses/osl-3.0.php
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@magentocommerce.com so we can send you a copy immediately.
  14. *
  15. * DISCLAIMER
  16. *
  17. * Do not edit or add to this file if you wish to upgrade Magento to newer
  18. * versions in the future. If you wish to customize Magento for your
  19. * needs please refer to http://www.magentocommerce.com for more information.
  20. *
  21. * @category Varien
  22. * @package Varien_File
  23. * @copyright Copyright (c) 2008 Irubin Consulting Inc. DBA Varien (http://www.varien.com)
  24. * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
  25. */
  26. /**
  27. * File upload class
  28. *
  29. * @category Varien
  30. * @package Varien_File
  31. * @author Magento Core Team <core@magentocommerce.com>
  32. */
  33. class Varien_File_Uploader
  34. {
  35. /**
  36. * Uploaded file handle (copy of $_FILES[] element)
  37. *
  38. * @var array
  39. * @access protected
  40. */
  41. protected $_file;
  42. /**
  43. * Uploaded file mime type
  44. *
  45. * @var string
  46. * @access protected
  47. */
  48. protected $_fileMimeType;
  49. /**
  50. * Upload type. Used to right handle $_FILES array.
  51. *
  52. * @var Varien_File_Uploader::SINGLE_STYLE|Varien_File_Uploader::MULTIPLE_STYLE
  53. * @access protected
  54. */
  55. protected $_uploadType;
  56. /**
  57. * The name of uploaded file. By default it is original file name, but when
  58. * we will change file name, this variable will be changed too.
  59. *
  60. * @var string
  61. * @access protected
  62. */
  63. protected $_uploadedFileName;
  64. /**
  65. * The name of destination directory
  66. *
  67. * @var string
  68. * @access protected
  69. */
  70. protected $_uploadedFileDir;
  71. /**
  72. * If this variable is set to TRUE, our library will be able to automaticaly create
  73. * non-existant directories.
  74. *
  75. * @var bool
  76. * @access protected
  77. */
  78. protected $_allowCreateFolders = true;
  79. /**
  80. * If this variable is set to TRUE, uploaded file name will be changed if some file with the same
  81. * name already exists in the destination directory (if enabled).
  82. *
  83. * @var bool
  84. * @access protected
  85. */
  86. protected $_allowRenameFiles = false;
  87. /**
  88. * If this variable is set to TRUE, files despersion will be supported.
  89. *
  90. * @var bool
  91. * @access protected
  92. */
  93. protected $_enableFilesDispersion = false;
  94. /**
  95. * This variable is used both with $_enableFilesDispersion == true
  96. * It helps to avoid problems after migrating from case-insensitive file system to case-insensitive
  97. * (e.g. NTFS->ext or ext->NTFS)
  98. *
  99. * @var bool
  100. * @access protected
  101. */
  102. protected $_caseInsensitiveFilenames = true;
  103. /**
  104. * @var string
  105. * @access protected
  106. */
  107. protected $_dispretionPath = null;
  108. protected $_fileExists = false;
  109. protected $_allowedExtensions = null;
  110. /**
  111. * Validate callbacks storage
  112. *
  113. * @var array
  114. * @access protected
  115. */
  116. protected $_validateCallbacks = array();
  117. const SINGLE_STYLE = 0;
  118. const MULTIPLE_STYLE = 1;
  119. function __construct($fileId)
  120. {
  121. $this->_setUploadFileId($fileId);
  122. if( !file_exists($this->_file['tmp_name']) ) {
  123. throw new Exception('File was not uploaded.');
  124. return;
  125. } else {
  126. $this->_fileExists = true;
  127. }
  128. }
  129. /**
  130. * Used to save uploaded file into destination folder with
  131. * original or new file name (if specified)
  132. *
  133. * @param string $destinationFolder
  134. * @param string $newFileName
  135. * @access public
  136. * @return void|bool
  137. */
  138. public function save($destinationFolder, $newFileName=null)
  139. {
  140. $this->_validateFile();
  141. if( $this->_allowCreateFolders ) {
  142. $this->_createDestinationFolder($destinationFolder);
  143. }
  144. if( !is_writable($destinationFolder) ) {
  145. throw new Exception('Destination folder is not writable or does not exists.');
  146. }
  147. $result = false;
  148. $destFile = $destinationFolder;
  149. $fileName = ( isset($newFileName) ) ? $newFileName : self::getCorrectFileName($this->_file['name']);
  150. if( $this->_enableFilesDispersion ) {
  151. $fileName = $this->correctFileNameCase($fileName);
  152. $this->setAllowCreateFolders(true);
  153. $this->_dispretionPath = self::getDispretionPath($fileName);
  154. $destFile.= $this->_dispretionPath;
  155. $this->_createDestinationFolder($destFile);
  156. }
  157. if( $this->_allowRenameFiles ) {
  158. $fileName = self::getNewFileName(self::_addDirSeparator($destFile).$fileName);
  159. }
  160. $destFile = self::_addDirSeparator($destFile) . $fileName;
  161. $result = move_uploaded_file($this->_file['tmp_name'], $destFile);
  162. if( $result ) {
  163. chmod($destFile, 0777);
  164. if ( $this->_enableFilesDispersion ) {
  165. $fileName = str_replace(DIRECTORY_SEPARATOR, '/', self::_addDirSeparator($this->_dispretionPath)) . $fileName;
  166. }
  167. $this->_uploadedFileName = $fileName;
  168. $this->_uploadedFileDir = $destinationFolder;
  169. $result = $this->_file;
  170. $result['path'] = $destinationFolder;
  171. $result['file'] = $fileName;
  172. return $result;
  173. } else {
  174. return $result;
  175. }
  176. }
  177. /**
  178. * Validate file before save
  179. *
  180. * @access public
  181. */
  182. protected function _validateFile()
  183. {
  184. if( $this->_fileExists === false ) {
  185. return;
  186. }
  187. $filePath = $this->_file['tmp_name'];
  188. $fileName = $this->_file['name'];
  189. //is file extension allowed
  190. $fileExtension = substr($fileName, strrpos($fileName, '.')+1);
  191. if( !$this->chechAllowedExtension($fileExtension) ) {
  192. throw new Exception('Disallowed file type.');
  193. }
  194. //run validate callbacks
  195. foreach ($this->_validateCallbacks as $params)
  196. {
  197. if (is_object($params['object']) && method_exists($params['object'], $params['method'])) {
  198. $params['object']->$params['method']($filePath);
  199. }
  200. }
  201. }
  202. /**
  203. * Add validation callback model for us in self::_validateFile()
  204. *
  205. * @param string $callbackName
  206. * @param object $callbackObject
  207. * @param string $callbackMethod - method name of $callbackObject. It must have interface (string $tmpFilePath)
  208. * @access public
  209. * @return Varien_File_Uploader
  210. */
  211. public function addValidateCallback($callbackName, $callbackObject, $callbackMethod)
  212. {
  213. $this->_validateCallbacks[$callbackName] = array(
  214. 'object' => $callbackObject,
  215. 'method' => $callbackMethod
  216. );
  217. return $this;
  218. }
  219. /**
  220. * Delete validation callback model for us in self::_validateFile()
  221. *
  222. * @param string $callbackName
  223. * @access public
  224. * @return Varien_File_Uploader
  225. */
  226. public function removeValidateCallback($callbackName)
  227. {
  228. if (isset($this->_validateCallbacks[$callbackName])) {
  229. unset($this->_validateCallbacks[$callbackName]);
  230. }
  231. return $this;
  232. }
  233. /**
  234. * Correct filename with special chars and spaces
  235. *
  236. * @param string $fileName
  237. * @return string
  238. */
  239. static public function getCorrectFileName($fileName)
  240. {
  241. if (preg_match('/[^a-z0-9_\\-\\.\s]/i', $fileName)) {
  242. $fileName = 'file' . substr($fileName, strrpos($fileName, '.'));
  243. }
  244. return preg_replace('/\s+/', '_', $fileName);
  245. }
  246. /**
  247. * Convert filename to lowercase in case of case-insensitive file names
  248. *
  249. * @param string
  250. * @return string
  251. */
  252. public function correctFileNameCase($fileName)
  253. {
  254. if ($this->_caseInsensitiveFilenames) {
  255. return strtolower($fileName);
  256. }
  257. return $fileName;
  258. }
  259. static protected function _addDirSeparator($dir)
  260. {
  261. if (substr($dir,-1) != DIRECTORY_SEPARATOR) {
  262. $dir.= DIRECTORY_SEPARATOR;
  263. }
  264. return $dir;
  265. }
  266. /**
  267. * Used to check if uploaded file mime type is valid or not
  268. *
  269. * @param array $validTypes
  270. * @access public
  271. * @return bool
  272. */
  273. public function checkMimeType($validTypes=Array())
  274. {
  275. if( count($validTypes) > 0 ) {
  276. if( !in_array($this->_getMimeType(), $validTypes) ) {
  277. return false;
  278. }
  279. }
  280. return true;
  281. }
  282. /**
  283. * Returns a name of uploaded file
  284. *
  285. * @access public
  286. * @return string
  287. */
  288. public function getUploadedFileName()
  289. {
  290. return $this->_uploadedFileName;
  291. }
  292. /**
  293. * Used to set {@link _allowCreateFolders} value
  294. *
  295. * @param mixed $flag
  296. * @access public
  297. * @return Varien_File_Uploader
  298. */
  299. public function setAllowCreateFolders($flag)
  300. {
  301. $this->_allowCreateFolders = $flag;
  302. return $this;
  303. }
  304. /**
  305. * Used to set {@link _allowRenameFiles} value
  306. *
  307. * @param mixed $flag
  308. * @access public
  309. * @return Varien_File_Uploader
  310. */
  311. public function setAllowRenameFiles($flag)
  312. {
  313. $this->_allowRenameFiles = $flag;
  314. return $this;
  315. }
  316. /**
  317. * Used to set {@link _enableFilesDispersion} value
  318. *
  319. * @param mixed $flag
  320. * @access public
  321. * @return Varien_File_Uploader
  322. */
  323. public function setFilesDispersion($flag)
  324. {
  325. $this->_enableFilesDispersion = $flag;
  326. return $this;
  327. }
  328. /**
  329. * Filenames Case-sensitivity setter
  330. *
  331. * @param mixed $flag
  332. * @return Varien_File_Uploader
  333. */
  334. public function setFilenamesCaseSensitivity($flag)
  335. {
  336. $this->_caseInsensitiveFilenames = $flag;
  337. return $this;
  338. }
  339. public function setAllowedExtensions($extensions=array())
  340. {
  341. foreach ((array)$extensions as $extension) {
  342. $this->_allowedExtensions[] = strtolower($extension);
  343. }
  344. return $this;
  345. }
  346. public function chechAllowedExtension($extension)
  347. {
  348. if (is_null($this->_allowedExtensions)) {
  349. return true;
  350. }
  351. elseif (in_array(strtolower($extension), $this->_allowedExtensions)) {
  352. return true;
  353. }
  354. return false;
  355. }
  356. private function _getMimeType()
  357. {
  358. return $this->_file['type'];
  359. }
  360. private function _setUploadFileId($fileId)
  361. {
  362. if (empty($_FILES)) {
  363. throw new Exception('$_FILES array is empty');
  364. }
  365. if (is_array($fileId)) {
  366. $this->_uploadType = self::MULTIPLE_STYLE;
  367. $this->_file = $fileId;
  368. } else {
  369. preg_match("/^(.*?)\[(.*?)\]$/", $fileId, $file);
  370. if( count($file) > 0 && (count($file[0]) > 0) && (count($file[1]) > 0) ) {
  371. array_shift($file);
  372. $this->_uploadType = self::MULTIPLE_STYLE;
  373. $fileAttributes = $_FILES[$file[0]];
  374. $tmp_var = array();
  375. foreach( $fileAttributes as $attributeName => $attributeValue ) {
  376. $tmp_var[$attributeName] = $attributeValue[$file[1]];
  377. }
  378. $fileAttributes = $tmp_var;
  379. $this->_file = $fileAttributes;
  380. } elseif( count($fileId) > 0 && isset($_FILES[$fileId])) {
  381. $this->_uploadType = self::SINGLE_STYLE;
  382. $this->_file = $_FILES[$fileId];
  383. } elseif( $fileId == '' ) {
  384. throw new Exception('Invalid parameter given. A valid $_FILES[] identifier is expected.');
  385. }
  386. }
  387. }
  388. private function _createDestinationFolder($destinationFolder)
  389. {
  390. if( !$destinationFolder ) {
  391. return $this;
  392. }
  393. if (substr($destinationFolder, -1) == DIRECTORY_SEPARATOR) {
  394. $destinationFolder = substr($destinationFolder, 0, -1);
  395. }
  396. if (!(@is_dir($destinationFolder) || @mkdir($destinationFolder, 0777, true))) {
  397. throw new Exception("Unable to create directory '{$destinationFolder}'.");
  398. }
  399. return $this;
  400. $destinationFolder = str_replace('/', DIRECTORY_SEPARATOR, $destinationFolder);
  401. $path = explode(DIRECTORY_SEPARATOR, $destinationFolder);
  402. $newPath = null;
  403. $oldPath = null;
  404. foreach( $path as $key => $directory ) {
  405. if (trim($directory)=='') {
  406. continue;
  407. }
  408. if (strlen($directory)===2 && $directory{1}===':') {
  409. $newPath = $directory;
  410. continue;
  411. }
  412. $newPath.= ( $newPath != DIRECTORY_SEPARATOR ) ? DIRECTORY_SEPARATOR . $directory : $directory;
  413. if( is_dir($newPath) ) {
  414. $oldPath = $newPath;
  415. continue;
  416. } else {
  417. if( is_writable($oldPath) ) {
  418. mkdir($newPath, 0777);
  419. } else {
  420. throw new Exception("Unable to create directory '{$newPath}'. Access forbidden.");
  421. }
  422. }
  423. $oldPath = $newPath;
  424. }
  425. return $this;
  426. }
  427. static public function getNewFileName($destFile)
  428. {
  429. $fileInfo = pathinfo($destFile);
  430. if( file_exists($destFile) ) {
  431. $index = 1;
  432. $baseName = $fileInfo['filename'] . '.' . $fileInfo['extension'];
  433. while( file_exists($fileInfo['dirname'] . DIRECTORY_SEPARATOR . $baseName) ) {
  434. $baseName = $fileInfo['filename']. '_' . $index . '.' . $fileInfo['extension'];
  435. $index ++;
  436. }
  437. $destFileName = $baseName;
  438. } else {
  439. return $fileInfo['basename'];
  440. }
  441. return $destFileName;
  442. }
  443. static public function getDispretionPath($fileName)
  444. {
  445. $char = 0;
  446. $dispretionPath = '';
  447. while( ($char < 2) && ($char < strlen($fileName)) ) {
  448. if (empty($dispretionPath)) {
  449. $dispretionPath = DIRECTORY_SEPARATOR.('.' == $fileName[$char] ? '_' : $fileName[$char]);
  450. }
  451. else {
  452. $dispretionPath = self::_addDirSeparator($dispretionPath) . ('.' == $fileName[$char] ? '_' : $fileName[$char]);
  453. }
  454. $char ++;
  455. }
  456. return $dispretionPath;
  457. }
  458. }