PageRenderTime 59ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

/upload/admin/controller/common/filemanager.php

http://github.com/opencart/opencart
PHP | 492 lines | 384 code | 60 blank | 48 comment | 53 complexity | d99fcdefec2f6590183386ba49e92e38 MD5 | raw file
Possible License(s): Apache-2.0, BSD-3-Clause, LGPL-2.1, MPL-2.0-no-copyleft-exception
  1. <?php
  2. namespace Opencart\Admin\Controller\Common;
  3. class FileManager extends \Opencart\System\Engine\Controller {
  4. public function index(): void {
  5. $this->load->language('common/filemanager');
  6. $data['error_upload_size'] = sprintf($this->language->get('error_upload_size'), $this->config->get('config_file_max_size'));
  7. $data['config_file_max_size'] = $this->config->get('config_file_max_size');
  8. // Return the target ID for the file manager to set the value
  9. if (isset($this->request->get['target'])) {
  10. $data['target'] = $this->request->get['target'];
  11. } else {
  12. $data['target'] = '';
  13. }
  14. // Return the thumbnail for the file manager to show a thumbnail
  15. if (isset($this->request->get['thumb'])) {
  16. $data['thumb'] = $this->request->get['thumb'];
  17. } else {
  18. $data['thumb'] = '';
  19. }
  20. if (isset($this->request->get['ckeditor'])) {
  21. $data['ckeditor'] = $this->request->get['ckeditor'];
  22. } else {
  23. $data['ckeditor'] = '';
  24. }
  25. $data['user_token'] = $this->session->data['user_token'];
  26. $this->response->setOutput($this->load->view('common/filemanager', $data));
  27. }
  28. public function list(): void {
  29. $this->load->language('common/filemanager');
  30. // Make sure we have the correct directory
  31. if (isset($this->request->get['directory'])) {
  32. $directory = DIR_IMAGE . 'catalog/' . html_entity_decode($this->request->get['directory'], ENT_QUOTES, 'UTF-8') . '/';
  33. } else {
  34. $directory = DIR_IMAGE . 'catalog/';
  35. }
  36. if (isset($this->request->get['filter_name'])) {
  37. $filter_name = basename(html_entity_decode($this->request->get['filter_name'], ENT_QUOTES, 'UTF-8'));
  38. } else {
  39. $filter_name = '';
  40. }
  41. if (isset($this->request->get['page'])) {
  42. $page = (int)$this->request->get['page'];
  43. } else {
  44. $page = 1;
  45. }
  46. $data['directories'] = [];
  47. // Get directories
  48. $directories = glob($directory . '*', GLOB_ONLYDIR);
  49. if ($directories) {
  50. // Split the array based on current page number and max number of items per page of 10
  51. $images = array_slice($directories, ($page - 1) * 16, 16);
  52. foreach ($images as $image) {
  53. if (substr(str_replace('\\', '/', realpath($image)), 0, strlen(DIR_IMAGE . 'catalog')) == DIR_IMAGE . 'catalog') {
  54. $name = basename($image);
  55. $url = '';
  56. if (isset($this->request->get['target'])) {
  57. $url .= '&target=' . $this->request->get['target'];
  58. }
  59. if (isset($this->request->get['thumb'])) {
  60. $url .= '&thumb=' . $this->request->get['thumb'];
  61. }
  62. if (isset($this->request->get['ckeditor'])) {
  63. $url .= '&ckeditor=' . $this->request->get['ckeditor'];
  64. }
  65. $data['directories'][] = [
  66. 'name' => $name,
  67. 'path' => utf8_substr($image, utf8_strlen(DIR_IMAGE)),
  68. 'type' => 'directory',
  69. 'href' => $this->url->link('common/filemanager|list', 'user_token=' . $this->session->data['user_token'] . '&directory=' . urlencode(utf8_substr($image, utf8_strlen(DIR_IMAGE . 'catalog/'))) . $url)
  70. ];
  71. }
  72. }
  73. }
  74. $this->load->model('tool/image');
  75. $data['images'] = [];
  76. $allowed = [
  77. 'ico',
  78. 'jpg',
  79. 'jpeg',
  80. 'png',
  81. 'gif',
  82. 'webp',
  83. 'JPG',
  84. 'JPEG',
  85. 'PNG',
  86. 'GIF'
  87. ];
  88. // Validate the file is an image
  89. $files = glob($directory . $filter_name . '*');
  90. foreach ($files as $key => $value) {
  91. if (!is_file($value)) {
  92. unset($files[$key]);
  93. continue;
  94. }
  95. $pos = strrpos($files[$key], '.');
  96. if ($pos === false) {
  97. unset($files[$key]);
  98. continue;
  99. }
  100. $extension = substr($files[$key], $pos + 1);
  101. if (!in_array($extension, $allowed)) {
  102. unset($files[$key]);
  103. }
  104. }
  105. sort($files);
  106. if ($files) {
  107. // Split the array based on current page number and max number of items per page of 10
  108. $images = array_slice($files, ($page - 1) * 16, 16 - count($data['directories']));
  109. foreach ($images as $image) {
  110. if (substr(str_replace('\\', '/', realpath($image)), 0, strlen(DIR_IMAGE . 'catalog')) == DIR_IMAGE . 'catalog') {
  111. $name = basename($image);
  112. $data['images'][] = [
  113. 'thumb' => $this->model_tool_image->resize(utf8_substr($image, utf8_strlen(DIR_IMAGE)), 136, 136),
  114. 'name' => $name,
  115. 'path' => utf8_substr($image, utf8_strlen(DIR_IMAGE)),
  116. 'href' => HTTP_CATALOG . 'image/' . utf8_substr($image, utf8_strlen(DIR_IMAGE))
  117. ];
  118. }
  119. }
  120. }
  121. if (isset($this->request->get['directory'])) {
  122. $data['directory'] = urldecode($this->request->get['directory']);
  123. } else {
  124. $data['directory'] = '';
  125. }
  126. if (isset($this->request->get['filter_name'])) {
  127. $data['filter_name'] = $this->request->get['filter_name'];
  128. } else {
  129. $data['filter_name'] = '';
  130. }
  131. // Parent
  132. $url = '';
  133. if (isset($this->request->get['directory'])) {
  134. $pos = strrpos($this->request->get['directory'], '/');
  135. if ($pos) {
  136. $url .= '&directory=' . urlencode(substr($this->request->get['directory'], 0, $pos));
  137. }
  138. }
  139. if (isset($this->request->get['target'])) {
  140. $url .= '&target=' . $this->request->get['target'];
  141. }
  142. if (isset($this->request->get['thumb'])) {
  143. $url .= '&thumb=' . $this->request->get['thumb'];
  144. }
  145. if (isset($this->request->get['ckeditor'])) {
  146. $url .= '&ckeditor=' . $this->request->get['ckeditor'];
  147. }
  148. $data['parent'] = $this->url->link('common/filemanager|list', 'user_token=' . $this->session->data['user_token'] . $url);
  149. // Refresh
  150. $url = '';
  151. if (isset($this->request->get['directory'])) {
  152. $url .= '&directory=' . urlencode(html_entity_decode($this->request->get['directory'], ENT_QUOTES, 'UTF-8'));
  153. }
  154. if (isset($this->request->get['filter_name'])) {
  155. $url .= '&filter_name=' . urlencode(html_entity_decode($this->request->get['filter_name'], ENT_QUOTES, 'UTF-8'));
  156. }
  157. if (isset($this->request->get['target'])) {
  158. $url .= '&target=' . $this->request->get['target'];
  159. }
  160. if (isset($this->request->get['thumb'])) {
  161. $url .= '&thumb=' . $this->request->get['thumb'];
  162. }
  163. if (isset($this->request->get['ckeditor'])) {
  164. $url .= '&ckeditor=' . $this->request->get['ckeditor'];
  165. }
  166. if (isset($this->request->get['page'])) {
  167. $url .= '&page=' . $this->request->get['page'];
  168. }
  169. $data['refresh'] = $this->url->link('common/filemanager|list', 'user_token=' . $this->session->data['user_token'] . $url);
  170. $url = '';
  171. if (isset($this->request->get['directory'])) {
  172. $url .= '&directory=' . urlencode(html_entity_decode($this->request->get['directory'], ENT_QUOTES, 'UTF-8'));
  173. }
  174. if (isset($this->request->get['filter_name'])) {
  175. $url .= '&filter_name=' . urlencode(html_entity_decode($this->request->get['filter_name'], ENT_QUOTES, 'UTF-8'));
  176. }
  177. if (isset($this->request->get['target'])) {
  178. $url .= '&target=' . $this->request->get['target'];
  179. }
  180. if (isset($this->request->get['thumb'])) {
  181. $url .= '&thumb=' . $this->request->get['thumb'];
  182. }
  183. if (isset($this->request->get['ckeditor'])) {
  184. $url .= '&ckeditor=' . $this->request->get['ckeditor'];
  185. }
  186. // Get total number of files and directories
  187. $data['pagination'] = $this->load->controller('common/pagination', [
  188. 'total' => count(array_merge((array)$directories, (array)$files)),
  189. 'page' => $page,
  190. 'limit' => 16,
  191. 'url' => $this->url->link('common/filemanager|list', 'user_token=' . $this->session->data['user_token'] . $url . '&page={page}')
  192. ]);
  193. $this->response->setOutput($this->load->view('common/filemanager_list', $data));
  194. }
  195. public function upload(): void {
  196. $this->load->language('common/filemanager');
  197. $json = [];
  198. // Check user has permission
  199. if (!$this->user->hasPermission('modify', 'common/filemanager')) {
  200. $json['error'] = $this->language->get('error_permission');
  201. }
  202. // Make sure we have the correct directory
  203. if (isset($this->request->get['directory'])) {
  204. $directory = DIR_IMAGE . 'catalog/' . html_entity_decode($this->request->get['directory'], ENT_QUOTES, 'UTF-8') . '/';
  205. } else {
  206. $directory = DIR_IMAGE . 'catalog/';
  207. }
  208. // Check its a directory
  209. if (!is_dir($directory) || substr(str_replace('\\', '/', realpath($directory)), 0, strlen(DIR_IMAGE . 'catalog')) != DIR_IMAGE . 'catalog') {
  210. $json['error'] = $this->language->get('error_directory');
  211. }
  212. if (!$json) {
  213. // Check if multiple files are uploaded or just one
  214. $files = [];
  215. if (!empty($this->request->files['file']['name']) && is_array($this->request->files['file']['name'])) {
  216. foreach (array_keys($this->request->files['file']['name']) as $key) {
  217. $files[] = [
  218. 'name' => $this->request->files['file']['name'][$key],
  219. 'type' => $this->request->files['file']['type'][$key],
  220. 'tmp_name' => $this->request->files['file']['tmp_name'][$key],
  221. 'error' => $this->request->files['file']['error'][$key],
  222. 'size' => $this->request->files['file']['size'][$key]
  223. ];
  224. }
  225. }
  226. foreach ($files as $file) {
  227. if (is_file($file['tmp_name'])) {
  228. // Sanitize the filename
  229. $filename = preg_replace('[/\\?%*:|"<>]', '', basename(html_entity_decode($file['name'], ENT_QUOTES, 'UTF-8')));
  230. // Validate the filename length
  231. if ((utf8_strlen($filename) < 4) || (utf8_strlen($filename) > 255)) {
  232. $json['error'] = $this->language->get('error_filename');
  233. }
  234. // Allowed file extension types
  235. $allowed = [
  236. 'ico',
  237. 'jpg',
  238. 'jpeg',
  239. 'png',
  240. 'gif',
  241. 'webp',
  242. 'JPG',
  243. 'JPEG',
  244. 'PNG',
  245. 'GIF'
  246. ];
  247. if (!in_array(substr($filename, strrpos($filename, '.') + 1), $allowed)) {
  248. $json['error'] = $this->language->get('error_filetype');
  249. }
  250. // Allowed file mime types
  251. $allowed = [
  252. 'image/x-icon',
  253. 'image/jpeg',
  254. 'image/pjpeg',
  255. 'image/png',
  256. 'image/x-png',
  257. 'image/gif',
  258. 'image/webp'
  259. ];
  260. if (!in_array($file['type'], $allowed)) {
  261. $json['error'] = $this->language->get('error_filetype');
  262. }
  263. // Return any upload error
  264. if ($file['error'] != UPLOAD_ERR_OK) {
  265. $json['error'] = $this->language->get('error_upload_' . $file['error']);
  266. }
  267. } else {
  268. $json['error'] = $this->language->get('error_upload');
  269. }
  270. if (!$json) {
  271. move_uploaded_file($file['tmp_name'], $directory . $filename);
  272. }
  273. }
  274. }
  275. if (!$json) {
  276. $json['success'] = $this->language->get('text_uploaded');
  277. }
  278. $this->response->addHeader('Content-Type: application/json');
  279. $this->response->setOutput(json_encode($json));
  280. }
  281. public function folder(): void {
  282. $this->load->language('common/filemanager');
  283. $json = [];
  284. // Check user has permission
  285. if (!$this->user->hasPermission('modify', 'common/filemanager')) {
  286. $json['error'] = $this->language->get('error_permission');
  287. }
  288. // Make sure we have the correct directory
  289. if (isset($this->request->get['directory'])) {
  290. $directory = DIR_IMAGE . 'catalog/' . html_entity_decode($this->request->get['directory'], ENT_QUOTES, 'UTF-8') . '/';
  291. } else {
  292. $directory = DIR_IMAGE . 'catalog/';
  293. }
  294. // Check its a directory
  295. if (!is_dir($directory) || substr(str_replace('\\', '/', realpath($directory)), 0, strlen(DIR_IMAGE . 'catalog')) != DIR_IMAGE . 'catalog') {
  296. $json['error'] = $this->language->get('error_directory');
  297. }
  298. if ($this->request->server['REQUEST_METHOD'] == 'POST') {
  299. // Sanitize the folder name
  300. $folder = preg_replace('[/\\?%*&:|"<>]', '', basename(html_entity_decode($this->request->post['folder'], ENT_QUOTES, 'UTF-8')));
  301. // Validate the filename length
  302. if ((utf8_strlen($folder) < 3) || (utf8_strlen($folder) > 128)) {
  303. $json['error'] = $this->language->get('error_folder');
  304. }
  305. // Check if directory already exists or not
  306. if (is_dir($directory . '/' . $folder)) {
  307. $json['error'] = $this->language->get('error_exists');
  308. }
  309. }
  310. if (!$json) {
  311. mkdir($directory . '/' . $folder, 0777);
  312. chmod($directory . '/' . $folder, 0777);
  313. @touch($directory . '/' . $folder . '/' . 'index.html');
  314. $json['success'] = $this->language->get('text_directory');
  315. }
  316. $this->response->addHeader('Content-Type: application/json');
  317. $this->response->setOutput(json_encode($json));
  318. }
  319. public function delete(): void {
  320. $this->load->language('common/filemanager');
  321. $json = [];
  322. // Check user has permission
  323. if (!$this->user->hasPermission('modify', 'common/filemanager')) {
  324. $json['error'] = $this->language->get('error_permission');
  325. }
  326. if (isset($this->request->post['path'])) {
  327. $paths = $this->request->post['path'];
  328. } else {
  329. $paths = [];
  330. }
  331. // Loop through each path to run validations
  332. foreach ($paths as $path) {
  333. // Convert any html encoded characters.
  334. $path = html_entity_decode($path, ENT_QUOTES, 'UTF-8');
  335. // Check path exists
  336. if (($path == DIR_IMAGE . 'catalog') || (substr(str_replace('\\', '/', realpath(DIR_IMAGE . $path)), 0, strlen(DIR_IMAGE . 'catalog')) != DIR_IMAGE . 'catalog')) {
  337. $json['error'] = $this->language->get('error_delete');
  338. break;
  339. }
  340. }
  341. if (!$json) {
  342. // Loop through each path
  343. foreach ($paths as $path) {
  344. $path = rtrim(DIR_IMAGE . html_entity_decode($path, ENT_QUOTES, 'UTF-8'), '/');
  345. // If path is just a file delete it
  346. if (is_file($path)) {
  347. unlink($path);
  348. // If path is a directory begin deleting each file and sub folder
  349. } elseif (is_dir($path)) {
  350. $files = [];
  351. // Make path into an array
  352. $path = [$path];
  353. // While the path array is still populated keep looping through
  354. while (count($path) != 0) {
  355. $next = array_shift($path);
  356. foreach (glob($next) as $file) {
  357. // If directory add to path array
  358. if (is_dir($file)) {
  359. $path[] = $file . '/*';
  360. }
  361. // Add the file to the files to be deleted array
  362. $files[] = $file;
  363. }
  364. }
  365. // Reverse sort the file array
  366. rsort($files);
  367. foreach ($files as $file) {
  368. // If file just delete
  369. if (is_file($file)) {
  370. unlink($file);
  371. // If directory use the remove directory function
  372. } elseif (is_dir($file)) {
  373. rmdir($file);
  374. }
  375. }
  376. }
  377. }
  378. $json['success'] = $this->language->get('text_delete');
  379. }
  380. $this->response->addHeader('Content-Type: application/json');
  381. $this->response->setOutput(json_encode($json));
  382. }
  383. }