PageRenderTime 50ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/home/administrator/components/com_hikashop/helpers/upload.php

https://bitbucket.org/rubbystar/carimod
PHP | 382 lines | 316 code | 59 blank | 7 comment | 101 complexity | 8cbfc4d72264001d4eb7c58651a74658 MD5 | raw file
Possible License(s): LGPL-2.1, GPL-2.0, GPL-3.0
  1. <?php
  2. /**
  3. * @package HikaShop for Joomla!
  4. * @version 3.0.0
  5. * @author hikashop.com
  6. * @copyright (C) 2010-2017 HIKARI SOFTWARE. All rights reserved.
  7. * @license GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
  8. */
  9. defined('_JEXEC') or die('Restricted access');
  10. ?><?php
  11. class hikashopUploadHelper {
  12. protected $options;
  13. protected $imagesExt = array('jpg', 'jpeg', 'gif', 'png');
  14. public function __construct() {
  15. $this->setOptions();
  16. }
  17. public function setOptions($options = null) {
  18. $this->options = array(
  19. 'upload_dir' => HIKASHOP_MEDIA.'upload'.DS,
  20. 'upload_url' => JURI::base(true).'/media/'.HIKASHOP_COMPONENT.'/upload/',
  21. 'param_name' => 'files',
  22. 'max_file_size' => null,
  23. 'min_file_size' => 1,
  24. 'accept_file_types' => '/.+$/i',
  25. 'max_width' => null,
  26. 'max_height' => null,
  27. 'min_width' => 1,
  28. 'min_height' => 1,
  29. 'send_header' => false,
  30. 'orient_image' => false,
  31. 'image_versions' => array()
  32. );
  33. if(empty($options))
  34. return;
  35. foreach($options as $k => $v) {
  36. if(!is_array($v) || empty($this->options[$k]))
  37. $this->options[$k] = $v;
  38. else
  39. $this->options[$k] = array_merge($this->options[$k], $v);
  40. }
  41. }
  42. public function process($options = null) {
  43. JRequest::checkToken() || die('Invalid Token');
  44. if(!empty($options))
  45. $this->setOptions($options);
  46. if(!empty($this->options['send_header']) && !headers_sent()) {
  47. header('Pragma: no-cache');
  48. header('Cache-Control: no-store, no-cache, must-revalidate');
  49. header('X-Content-Type-Options: nosniff');
  50. }
  51. $upload = reset($_FILES);
  52. if(isset($_FILES[$this->options['param_name']]))
  53. $upload = $_FILES[$this->options['param_name']];
  54. if(empty($upload))
  55. return null;
  56. $uploaded_file = isset($upload['tmp_name']) ? $upload['tmp_name'] : null;
  57. $name = isset($_SERVER['HTTP_X_FILE_NAME']) ? $_SERVER['HTTP_X_FILE_NAME'] : (isset($upload['name']) ? $upload['name'] : null);
  58. $size = isset($_SERVER['HTTP_X_FILE_SIZE']) ? $_SERVER['HTTP_X_FILE_SIZE'] : (isset($upload['size']) ? $upload['size'] : null);
  59. $type = isset($_SERVER['HTTP_X_FILE_TYPE']) ? $_SERVER['HTTP_X_FILE_TYPE'] : (isset($upload['type']) ? $upload['type'] : null);
  60. $error = isset($upload['error']) ? $upload['error'] : null;
  61. $slice = null;
  62. if(isset($_POST['slices']) && (int)$_POST['slices'] > 1) {
  63. $slice = array(
  64. 'index' => (int)@$_POST['slice'],
  65. 'total' => $_POST['slices'],
  66. 'size' => (int)@$_POST['slice_size'],
  67. 'total_size' => (int)@$_POST['slices_size'],
  68. );
  69. }
  70. $file = new stdClass();
  71. $file->name = $this->trim_file_name($name, $type);
  72. $file->size = intval($size);
  73. $file->type = $type;
  74. if(empty($this->options['sub_folder']))
  75. $this->options['sub_folder'] = '';
  76. $shopConfig = hikashop_config();
  77. if($options['type'] == 'file')
  78. $allowed_extensions = $shopConfig->get('allowedfiles');
  79. else
  80. $allowed_extensions = $shopConfig->get('allowedimages');
  81. if(!empty($error)) {
  82. $file->error = $error;
  83. } else if(empty($file->name)) {
  84. $file->error = 'missingFileName';
  85. } else if(!is_uploaded_file($uploaded_file)) {
  86. $file->error = 'missingData';
  87. } else if(!empty($this->options['max_file_size']) && $file->size > $this->options['max_file_size']) {
  88. $file->error = 'maxFileSize';
  89. } else if(!empty($this->options['min_file_size']) && $file->size < $this->options['min_file_size']) {
  90. $file->error = 'minFileSize';
  91. }
  92. if(!empty($file->error))
  93. return $file;
  94. $file_path = strtolower(JFile::makeSafe($name));
  95. if(!empty($slice) && $slice['index'] > 0 && substr($file_path, -5) == '.part') {
  96. $pos = strrpos($file_path, '_');
  97. $file_path = substr($file_path, 0, $pos);
  98. }
  99. if(!preg_match('#\.('.str_replace(array(',','.'), array('|','\.'), $allowed_extensions).')$#Ui', $file_path, $extension) || preg_match('#\.(php.?|.?htm.?|pl|py|jsp|asp|sh|cgi)$#Ui', $file_path)) {
  100. $file->error = JText::sprintf('ACCEPTED_TYPE', substr($file_path,strrpos($file_path, '.') + 1), $allowed_extensions);
  101. return $file;
  102. }
  103. $file_path = str_replace(array('.',' '), '_', substr($file_path, 0, strpos($file_path,$extension[0]))) . $extension[0];
  104. if(empty($slice) || $slice['index'] == 0) {
  105. $file_path_origin = $file_path;
  106. if(JFile::exists($this->options['upload_dir'] . $this->options['sub_folder'] . $file_path)) {
  107. $pos = strrpos($file_path, '.');
  108. $file_path = substr($file_path, 0, $pos) . '_' . rand() . '.' . substr($file_path, $pos + 1);
  109. }
  110. if(!empty($slice)) {
  111. $pos = strrpos($file_path, '.');
  112. $file_path .= '_' . $slice['total_size'] . '-' . $slice['size'] . '.part';
  113. $file->partial = true;
  114. if(JFile::exists($this->options['upload_dir'] . $this->options['sub_folder'] . $file_path)) {
  115. clearstatcache();
  116. $current_filesize = filesize($this->options['upload_dir'] . $this->options['sub_folder'] . $file_path);
  117. $current_slice = $current_filesize / $slice['size'];
  118. if(is_int($current_slice)) {
  119. $file->name = $file_path;
  120. $file->resume = true;
  121. $file->slice = $current_slice;
  122. return $file;
  123. }
  124. $pos = strrpos($file_path_origin, '.');
  125. $file_path = substr($file_path_origin, 0, $pos) . '_' . rand() . '.' . substr($file_path_origin, $pos + 1) . '_' . $slice['total_size'] . '-' . $slice['size'] . '.part';
  126. }
  127. }
  128. if(!JFile::upload($uploaded_file, $this->options['upload_dir'] . $this->options['sub_folder'] . $file_path)) {
  129. if(!move_uploaded_file($uploaded_file, $this->options['upload_dir'] . $this->options['sub_folder'] . $file_path)) {
  130. $file->error = JText::sprintf('FAIL_UPLOAD', $uploaded_file, $this->options['upload_dir'] . $this->options['sub_folder'] . $file_path);
  131. return $file;
  132. }
  133. }
  134. } else {
  135. $file_path = strtolower(JFile::makeSafe($name));
  136. if(substr($file_path, -5) != '.part' || !JFile::exists($this->options['upload_dir'] . $this->options['sub_folder'] . $file_path)) {
  137. $file->error = 'partialUploadNotFound';
  138. return $file;
  139. }
  140. clearstatcache();
  141. $current_filesize = filesize($this->options['upload_dir'] . $this->options['sub_folder'] . $file_path);
  142. if($current_filesize != ((int)$slice['index'] * (int)$slice['size'])) {
  143. $file->error = 'partialUploadInvalid';
  144. return $file;
  145. }
  146. $destFile = fopen($this->options['upload_dir'] . $this->options['sub_folder'] .$file_path, 'ab');
  147. $sourceFile = fopen($uploaded_file, 'rb');
  148. while(!feof($sourceFile)) {
  149. $c = fread($sourceFile, 8192);
  150. fwrite($destFile, $c);
  151. }
  152. fclose($destFile);
  153. fclose($sourceFile);
  154. if(((int)$slice['index'] + 1) == (int)$slice['total']) {
  155. clearstatcache();
  156. $current_filesize = filesize($this->options['upload_dir'] . $this->options['sub_folder'] . $file_path);
  157. if((int)$current_filesize != (int)$slice['total_size']) {
  158. $file->error = 'partialUploadSizeError';
  159. return $file;
  160. }
  161. $pos = strrpos($file_path, '_');
  162. $orgin_path = substr($file_path, 0, $pos);
  163. rename($this->options['upload_dir'] . $this->options['sub_folder'] . $file_path, $this->options['upload_dir'] . $this->options['sub_folder'] . $orgin_path);
  164. $file_path = $orgin_path;
  165. } else
  166. $file->partial = true;
  167. }
  168. if($options['type'] != 'file' && strpos($file->name, '.') !== false && !empty($this->options['orient_image'])) {
  169. $ext = strtolower(substr($file->name, strrpos($file->name, '.') + 1));
  170. if(!in_array($ext, $this->imagesExt))
  171. $this->orient_image($this->options['upload_dir'] . $this->options['sub_folder'] . $file_path);
  172. }
  173. $file->name = $file_path;
  174. $file->path = $this->options['upload_dir'] . $this->options['sub_folder'] . $file_path;
  175. $file->url = $this->options['upload_url'] . $this->options['sub_folder'] . rawurlencode($file->name);
  176. $file->size = filesize($this->options['upload_dir'] . $this->options['sub_folder'] . $file_path);
  177. return $file;
  178. }
  179. public function processFallback($options = null) {
  180. JRequest::checkToken() || die('Invalid Token');
  181. if(!empty($options)) {
  182. $this->setOptions($options);
  183. }
  184. $upload = isset($_FILES[$this->options['param_name']]) ? $_FILES[$this->options['param_name']] : reset($_FILES);
  185. $info = array();
  186. if($upload && is_array($upload['tmp_name'])) {
  187. foreach ($upload['tmp_name'] as $index => $value) {
  188. $info[] = $this->handle_file_upload(
  189. $upload['tmp_name'][$index],
  190. isset($_SERVER['HTTP_X_FILE_NAME']) ? $_SERVER['HTTP_X_FILE_NAME'] : $upload['name'][$index],
  191. isset($_SERVER['HTTP_X_FILE_SIZE']) ? $_SERVER['HTTP_X_FILE_SIZE'] : $upload['size'][$index],
  192. isset($_SERVER['HTTP_X_FILE_TYPE']) ? $_SERVER['HTTP_X_FILE_TYPE'] : $upload['type'][$index],
  193. $upload['error'][$index],
  194. $options,
  195. $index
  196. );
  197. }
  198. } else if($upload || isset($_SERVER['HTTP_X_FILE_NAME'])) {
  199. $info[] = $this->handle_file_upload(
  200. isset($upload['tmp_name']) ? $upload['tmp_name'] : null,
  201. isset($_SERVER['HTTP_X_FILE_NAME']) ? $_SERVER['HTTP_X_FILE_NAME'] : (isset($upload['name']) ? $upload['name'] : null),
  202. isset($_SERVER['HTTP_X_FILE_SIZE']) ? $_SERVER['HTTP_X_FILE_SIZE'] : (isset($upload['size']) ? $upload['size'] : null),
  203. isset($_SERVER['HTTP_X_FILE_TYPE']) ? $_SERVER['HTTP_X_FILE_TYPE'] : (isset($upload['type']) ? $upload['type'] : null),
  204. isset($upload['error']) ? $upload['error'] : null,
  205. $options
  206. );
  207. }
  208. return $info;
  209. }
  210. protected function validate($uploaded_file, $file, $error) {
  211. if($error) {
  212. $file->error = $error;
  213. return false;
  214. }
  215. if(!$file->name) {
  216. $file->error = 'missingFileName';
  217. return false;
  218. }
  219. if(!preg_match($this->options['accept_file_types'], $file->name)) {
  220. $file->error = 'acceptFileTypes';
  221. return false;
  222. }
  223. if($uploaded_file && is_uploaded_file($uploaded_file)) {
  224. $file_size = filesize($uploaded_file);
  225. } else {
  226. $file_size = $_SERVER['CONTENT_LENGTH'];
  227. }
  228. if($this->options['max_file_size'] && ( $file_size > $this->options['max_file_size'] || $file->size > $this->options['max_file_size']) ) {
  229. $file->error = 'maxFileSize';
  230. return false;
  231. }
  232. if($this->options['min_file_size'] && $file_size < $this->options['min_file_size']) {
  233. $file->error = 'minFileSize';
  234. return false;
  235. }
  236. list($img_width, $img_height) = @getimagesize($uploaded_file);
  237. if(is_int($img_width)) {
  238. if($this->options['max_width'] && $img_width > $this->options['max_width'] || $this->options['max_height'] && $img_height > $this->options['max_height']) {
  239. $file->error = 'maxResolution';
  240. return false;
  241. }
  242. if($this->options['min_width'] && $img_width < $this->options['min_width'] || $this->options['min_height'] && $img_height < $this->options['min_height']) {
  243. $file->error = 'minResolution';
  244. return false;
  245. }
  246. }
  247. return true;
  248. }
  249. protected function handle_file_upload($uploaded_file, $name, $size, $type, $error, $options) {
  250. $file = new stdClass();
  251. $file->name = $this->trim_file_name($name, $type);
  252. $file->size = intval($size);
  253. $file->type = $type;
  254. if(empty($this->options['sub_folder']))
  255. $this->options['sub_folder'] = '';
  256. if(!$this->validate($uploaded_file, $file, $error))
  257. return $file;
  258. $shopConfig = hikashop_config();
  259. if($options['type'] == 'file') {
  260. $allowed = $shopConfig->get('allowedfiles');
  261. } else {
  262. $allowed = $shopConfig->get('allowedimages');
  263. }
  264. $file_path = strtolower(JFile::makeSafe($name));
  265. if(!preg_match('#\.('.str_replace(array(',','.'), array('|','\.'), $allowed).')$#Ui', $file_path,$extension) || preg_match('#\.(php.?|.?htm.?|pl|py|jsp|asp|sh|cgi)$#Ui', $file_path)) {
  266. $file->error = JText::sprintf('ACCEPTED_TYPE', substr($file_path,strrpos($file_path, '.') + 1), str_replace(',',', ',$allowed));
  267. return $file;
  268. }
  269. $file_path = str_replace(array('.',' '), '_', substr($file_path, 0, strpos($file_path,$extension[0]))) . $extension[0];
  270. if(JFile::exists($this->options['upload_dir'] . $this->options['sub_folder'] . $file_path)) {
  271. $pos = strrpos($file_path, '.');
  272. $file_path = substr($file_path, 0, $pos) . '_' . rand() . '.' . substr($file_path, $pos + 1);
  273. }
  274. if(!JFile::upload($uploaded_file, $this->options['upload_dir'] . $this->options['sub_folder'] . $file_path)) {
  275. if(!move_uploaded_file($uploaded_file, $this->options['upload_dir'] . $this->options['sub_folder'] . $file_path)) {
  276. $file->error = JText::sprintf('FAIL_UPLOAD', $uploaded_file, $this->options['upload_dir'] . $this->options['sub_folder'] . $file_path);
  277. return $file;
  278. }
  279. }
  280. $file_size = filesize($this->options['upload_dir'] . $this->options['sub_folder'] . $file_path);
  281. $file->name = $file_path;
  282. $file->path = $this->options['upload_dir'] . $this->options['sub_folder'] . $file_path;
  283. $file->url = $this->options['upload_url'] . $this->options['sub_folder'] . rawurlencode($file->name);
  284. if(strpos($file->name, '.') !== false) {
  285. $ext = strtolower(substr($file->name, strrpos($file->name, '.') + 1));
  286. if(!in_array($ext, $this->imagesExt) && $this->options['orient_image']) {
  287. $this->orient_image($this->options['upload_dir'] . $this->options['sub_folder'] . $file_path);
  288. }
  289. }
  290. return $file;
  291. }
  292. protected function trim_file_name($name, $type) {
  293. $file_name = trim(basename(stripslashes($name)), ".\x00..\x20");
  294. if(strpos($file_name, '.') === false && preg_match('/^image\/(gif|jpe?g|png)/', $type, $matches))
  295. $file_name .= '.'.$matches[1];
  296. return $file_name;
  297. }
  298. protected function orient_image($file_path) {
  299. $exif = @exif_read_data($file_path);
  300. if($exif === false)
  301. return false;
  302. $orientation = intval(@$exif['Orientation']);
  303. if(!in_array($orientation, array(3, 6, 8)))
  304. return false;
  305. $image = @imagecreatefromjpeg($file_path);
  306. switch ($orientation) {
  307. case 3:
  308. $image = @imagerotate($image, 180, 0);
  309. break;
  310. case 6:
  311. $image = @imagerotate($image, 270, 0);
  312. break;
  313. case 8:
  314. $image = @imagerotate($image, 90, 0);
  315. break;
  316. default:
  317. return false;
  318. }
  319. $success = imagejpeg($image, $file_path);
  320. @imagedestroy($image);
  321. return $success;
  322. }
  323. }