PageRenderTime 46ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/Varien/File/Uploader.php

https://github.com/jpratt/cal
PHP | 447 lines | 246 code | 52 blank | 149 comment | 46 complexity | f99980dbf492d99a728aabcdfcdea75e 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. const SINGLE_STYLE = 0;
  111. const MULTIPLE_STYLE = 1;
  112. function __construct($fileId)
  113. {
  114. $this->_setUploadFileId($fileId);
  115. if( !file_exists($this->_file['tmp_name']) ) {
  116. throw new Exception('File was not uploaded.');
  117. return;
  118. } else {
  119. $this->_fileExists = true;
  120. }
  121. }
  122. /**
  123. * Used to save uploaded file into destination folder with
  124. * original or new file name (if specified)
  125. *
  126. * @param string $destinationFolder
  127. * @param string $newFileName
  128. * @access public
  129. * @return void|bool
  130. */
  131. public function save($destinationFolder, $newFileName=null)
  132. {
  133. if( $this->_fileExists === false ) {
  134. return;
  135. }
  136. if( $this->_allowCreateFolders ) {
  137. $this->_createDestinationFolder($destinationFolder);
  138. }
  139. if( !is_writable($destinationFolder) ) {
  140. throw new Exception('Destination folder is not writable or does not exists.');
  141. }
  142. $result = false;
  143. $destFile = $destinationFolder;
  144. $fileName = ( isset($newFileName) ) ? $newFileName : self::getCorrectFileName($this->_file['name']);
  145. $fileExtension = substr($fileName, strrpos($fileName, '.')+1);
  146. if( !$this->chechAllowedExtension($fileExtension) ) {
  147. throw new Exception('Disallowed file type.');
  148. }
  149. if( $this->_enableFilesDispersion ) {
  150. $fileName = $this->correctFileNameCase($fileName);
  151. $this->setAllowCreateFolders(true);
  152. $this->_dispretionPath = self::getDispretionPath($fileName);
  153. $destFile.= $this->_dispretionPath;
  154. $this->_createDestinationFolder($destFile);
  155. }
  156. if( $this->_allowRenameFiles ) {
  157. $fileName = self::getNewFileName(self::_addDirSeparator($destFile).$fileName);
  158. }
  159. $destFile = self::_addDirSeparator($destFile) . $fileName;
  160. $result = move_uploaded_file($this->_file['tmp_name'], $destFile);
  161. if( $result ) {
  162. chmod($destFile, 0777);
  163. if ( $this->_enableFilesDispersion ) {
  164. $fileName = str_replace(DIRECTORY_SEPARATOR, '/', self::_addDirSeparator($this->_dispretionPath)) . $fileName;
  165. }
  166. $this->_uploadedFileName = $fileName;
  167. $this->_uploadedFileDir = $destinationFolder;
  168. $result = $this->_file;
  169. $result['path'] = $destinationFolder;
  170. $result['file'] = $fileName;
  171. return $result;
  172. } else {
  173. return $result;
  174. }
  175. }
  176. static public function getCorrectFileName($fileName)
  177. {
  178. if (preg_match('/[^a-z0-9_\\-\\.]/i', $fileName)) {
  179. $fileName = 'file' . substr($fileName, strrpos($fileName, '.'));
  180. }
  181. return $fileName;
  182. }
  183. /**
  184. * Convert filename to lowercase in case of case-insensitive file names
  185. *
  186. * @param string
  187. * @return string
  188. */
  189. public function correctFileNameCase($fileName)
  190. {
  191. if ($this->_caseInsensitiveFilenames) {
  192. return strtolower($fileName);
  193. }
  194. return $fileName;
  195. }
  196. static protected function _addDirSeparator($dir)
  197. {
  198. if (substr($dir,-1) != DIRECTORY_SEPARATOR) {
  199. $dir.= DIRECTORY_SEPARATOR;
  200. }
  201. return $dir;
  202. }
  203. /**
  204. * Used to check if uploaded file mime type is valid or not
  205. *
  206. * @param array $validTypes
  207. * @access public
  208. * @return bool
  209. */
  210. public function checkMimeType($validTypes=Array())
  211. {
  212. if( count($validTypes) > 0 ) {
  213. if( !in_array($this->_getMimeType(), $validTypes) ) {
  214. return false;
  215. }
  216. }
  217. return true;
  218. }
  219. /**
  220. * Returns a name of uploaded file
  221. *
  222. * @access public
  223. * @return string
  224. */
  225. public function getUploadedFileName()
  226. {
  227. return $this->_uploadedFileName;
  228. }
  229. /**
  230. * Used to set {@link _allowCreateFolders} value
  231. *
  232. * @param mixed $flag
  233. * @access public
  234. * @return Varien_File_Uploader
  235. */
  236. public function setAllowCreateFolders($flag)
  237. {
  238. $this->_allowCreateFolders = $flag;
  239. return $this;
  240. }
  241. /**
  242. * Used to set {@link _allowRenameFiles} value
  243. *
  244. * @param mixed $flag
  245. * @access public
  246. * @return Varien_File_Uploader
  247. */
  248. public function setAllowRenameFiles($flag)
  249. {
  250. $this->_allowRenameFiles = $flag;
  251. return $this;
  252. }
  253. /**
  254. * Used to set {@link _enableFilesDispersion} value
  255. *
  256. * @param mixed $flag
  257. * @access public
  258. * @return Varien_File_Uploader
  259. */
  260. public function setFilesDispersion($flag)
  261. {
  262. $this->_enableFilesDispersion = $flag;
  263. return $this;
  264. }
  265. /**
  266. * Filenames Case-sensitivity setter
  267. *
  268. * @param mixed $flag
  269. * @return Varien_File_Uploader
  270. */
  271. public function setFilenamesCaseSensitivity($flag)
  272. {
  273. $this->_caseInsensitiveFilenames = $flag;
  274. return $this;
  275. }
  276. public function setAllowedExtensions($extensions=array())
  277. {
  278. foreach ((array)$extensions as $extension) {
  279. $this->_allowedExtensions[] = strtolower($extension);
  280. }
  281. return $this;
  282. }
  283. public function chechAllowedExtension($extension)
  284. {
  285. if (is_null($this->_allowedExtensions)) {
  286. return true;
  287. }
  288. elseif (in_array(strtolower($extension), $this->_allowedExtensions)) {
  289. return true;
  290. }
  291. return false;
  292. }
  293. private function _getMimeType()
  294. {
  295. return $this->_file['type'];
  296. }
  297. private function _setUploadFileId($fileId)
  298. {
  299. if (empty($_FILES)) {
  300. throw new Exception('$_FILES array is empty');
  301. }
  302. if (is_array($fileId)) {
  303. $this->_uploadType = self::MULTIPLE_STYLE;
  304. $this->_file = $fileId;
  305. } else {
  306. preg_match("/^(.*?)\[(.*?)\]$/", $fileId, $file);
  307. if( count($file) > 0 && (count($file[0]) > 0) && (count($file[1]) > 0) ) {
  308. array_shift($file);
  309. $this->_uploadType = self::MULTIPLE_STYLE;
  310. $fileAttributes = $_FILES[$file[0]];
  311. $tmp_var = array();
  312. foreach( $fileAttributes as $attributeName => $attributeValue ) {
  313. $tmp_var[$attributeName] = $attributeValue[$file[1]];
  314. }
  315. $fileAttributes = $tmp_var;
  316. $this->_file = $fileAttributes;
  317. } elseif( count($fileId) > 0 && isset($_FILES[$fileId])) {
  318. $this->_uploadType = self::SINGLE_STYLE;
  319. $this->_file = $_FILES[$fileId];
  320. } elseif( $fileId == '' ) {
  321. throw new Exception('Invalid parameter given. A valid $_FILES[] identifier is expected.');
  322. }
  323. }
  324. }
  325. private function _createDestinationFolder($destinationFolder)
  326. {
  327. if( !$destinationFolder ) {
  328. return $this;
  329. }
  330. if (substr($destinationFolder, -1) == DIRECTORY_SEPARATOR) {
  331. $destinationFolder = substr($destinationFolder, 0, -1);
  332. }
  333. if (!(@is_dir($destinationFolder) || @mkdir($destinationFolder, 0777, true))) {
  334. throw new Exception("Unable to create directory '{$destinationFolder}'.");
  335. }
  336. return $this;
  337. $destinationFolder = str_replace('/', DIRECTORY_SEPARATOR, $destinationFolder);
  338. $path = explode(DIRECTORY_SEPARATOR, $destinationFolder);
  339. $newPath = null;
  340. $oldPath = null;
  341. foreach( $path as $key => $directory ) {
  342. if (trim($directory)=='') {
  343. continue;
  344. }
  345. if (strlen($directory)===2 && $directory{1}===':') {
  346. $newPath = $directory;
  347. continue;
  348. }
  349. $newPath.= ( $newPath != DIRECTORY_SEPARATOR ) ? DIRECTORY_SEPARATOR . $directory : $directory;
  350. if( is_dir($newPath) ) {
  351. $oldPath = $newPath;
  352. continue;
  353. } else {
  354. if( is_writable($oldPath) ) {
  355. mkdir($newPath, 0777);
  356. } else {
  357. throw new Exception("Unable to create directory '{$newPath}'. Access forbidden.");
  358. }
  359. }
  360. $oldPath = $newPath;
  361. }
  362. return $this;
  363. }
  364. static public function getNewFileName($destFile)
  365. {
  366. $fileInfo = pathinfo($destFile);
  367. if( file_exists($destFile) ) {
  368. $index = 1;
  369. $baseName = $fileInfo['filename'] . '.' . $fileInfo['extension'];
  370. while( file_exists($fileInfo['dirname'] . DIRECTORY_SEPARATOR . $baseName) ) {
  371. $baseName = $fileInfo['filename']. '_' . $index . '.' . $fileInfo['extension'];
  372. $index ++;
  373. }
  374. $destFileName = $baseName;
  375. } else {
  376. return $fileInfo['basename'];
  377. }
  378. return $destFileName;
  379. }
  380. static public function getDispretionPath($fileName)
  381. {
  382. $char = 0;
  383. $dispretionPath = '';
  384. while( ($char < 2) && ($char < strlen($fileName)) ) {
  385. if (empty($dispretionPath)) {
  386. $dispretionPath = DIRECTORY_SEPARATOR.('.' == $fileName[$char] ? '_' : $fileName[$char]);
  387. }
  388. else {
  389. $dispretionPath = self::_addDirSeparator($dispretionPath) . ('.' == $fileName[$char] ? '_' : $fileName[$char]);
  390. }
  391. $char ++;
  392. }
  393. return $dispretionPath;
  394. }
  395. }