PageRenderTime 66ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/application/protected/extensions/widgets/editor/source/kcfinder/core/uploader.php

https://bitbucket.org/dinhtrung/yiicorecms/
PHP | 566 lines | 469 code | 60 blank | 37 comment | 93 complexity | 53a95e85da5900cbd2e3ea5028b0f8b2 MD5 | raw file
Possible License(s): GPL-3.0, BSD-3-Clause, CC0-1.0, BSD-2-Clause, GPL-2.0, LGPL-2.1, LGPL-3.0
  1. <?php
  2. /** This file is part of KCFinder project
  3. *
  4. * @desc Uploader class
  5. * @package KCFinder
  6. * @version 2.41
  7. * @author Pavel Tzonkov <pavelc@users.sourceforge.net>
  8. * @copyright 2010, 2011 KCFinder Project
  9. * @license http://www.opensource.org/licenses/gpl-2.0.php GPLv2
  10. * @license http://www.opensource.org/licenses/lgpl-2.1.php LGPLv2
  11. * @link http://kcfinder.sunhater.com
  12. */
  13. class uploader {
  14. const VERSION = "2.41";
  15. protected $config = array();
  16. protected $opener = array();
  17. protected $type;
  18. protected $typeDir;
  19. protected $typeURL;
  20. protected $types = array();
  21. protected $typeSettings = array('disabled', 'theme', 'dirPerms', 'filePerms', 'denyZipDownload', 'maxImageWidth', 'maxImageHeight', 'thumbWidth', 'thumbHeight', 'jpegQuality', 'access', 'filenameChangeChars', 'dirnameChangeChars', 'denyExtensionRename', 'deniedExts');
  22. protected $charset;
  23. protected $lang = 'en';
  24. protected $langInputNames = array('lang', 'langCode', 'lng', 'language', 'lang_code');
  25. protected $file;
  26. protected $dateTimeFull; // Currently not used
  27. protected $dateTimeMid; // Currently not used
  28. protected $dateTimeSmall;
  29. protected $labels = array();
  30. protected $get;
  31. protected $post;
  32. protected $cookie;
  33. protected $session;
  34. public function __get($property) {
  35. return property_exists($this, $property) ? $this->$property : null;
  36. }
  37. public function __construct() {
  38. // DISABLE MAGIC QUOTES
  39. if (function_exists('set_magic_quotes_runtime'))
  40. @set_magic_quotes_runtime(false);
  41. // INPUT INIT
  42. $input = new input();
  43. $this->get = &$input->get;
  44. $this->post = &$input->post;
  45. $this->cookie = &$input->cookie;
  46. // LINKING UPLOADED FILE
  47. if (count($_FILES))
  48. $this->file = &$_FILES[key($_FILES)];
  49. // LOAD DEFAULT CONFIGURATION
  50. require "config.php";
  51. // SETTING UP SESSION
  52. if (isset($_CONFIG['_sessionLifetime']))
  53. ini_set('session.gc_maxlifetime', $_CONFIG['_sessionLifetime'] * 60);
  54. if (isset($_CONFIG['_sessionDir']))
  55. ini_set('session.save_path', $_CONFIG['_sessionDir']);
  56. if (isset($_CONFIG['_sessionDomain']))
  57. ini_set('session.cookie_domain', $_CONFIG['_sessionDomain']);
  58. session_start();
  59. // RELOAD DEFAULT CONFIGURATION
  60. require "config.php";
  61. $this->config = $_CONFIG;
  62. // LOAD SESSION CONFIGURATION IF EXISTS
  63. if (isset($_CONFIG['_sessionVar']) &&
  64. is_array($_CONFIG['_sessionVar'])
  65. ) {
  66. foreach ($_CONFIG['_sessionVar'] as $key => $val)
  67. if ((substr($key, 0, 1) != "_") && isset($_CONFIG[$key]))
  68. $this->config[$key] = $val;
  69. if (!isset($this->config['_sessionVar']['self']))
  70. $this->config['_sessionVar']['self'] = array();
  71. $this->session = &$this->config['_sessionVar']['self'];
  72. } else
  73. $this->session = &$_SESSION;
  74. // GET TYPE DIRECTORY
  75. $this->types = &$this->config['types'];
  76. $firstType = array_keys($this->types);
  77. $firstType = $firstType[0];
  78. $this->type = (
  79. isset($this->get['type']) &&
  80. isset($this->types[$this->get['type']])
  81. )
  82. ? $this->get['type'] : $firstType;
  83. // LOAD TYPE DIRECTORY SPECIFIC CONFIGURATION IF EXISTS
  84. if (is_array($this->types[$this->type])) {
  85. foreach ($this->types[$this->type] as $key => $val)
  86. if (in_array($key, $this->typeSettings))
  87. $this->config[$key] = $val;
  88. $this->types[$this->type] = isset($this->types[$this->type]['type'])
  89. ? $this->types[$this->type]['type'] : "";
  90. }
  91. // COOKIES INIT
  92. if (!strlen($this->config['cookieDomain']))
  93. $this->config['cookieDomain'] = $_SERVER['HTTP_HOST'];
  94. if (!strlen($this->config['cookiePath']))
  95. $this->config['cookiePath'] = "/";
  96. // UPLOAD FOLDER INIT
  97. // FULL URL
  98. if (preg_match('/^([a-z]+)\:\/\/([^\/^\:]+)(\:(\d+))?\/(.+)\/?$/',
  99. $this->config['uploadURL'], $patt)
  100. ) {
  101. list($unused, $protocol, $domain, $unused, $port, $path) = $patt;
  102. $path = path::normalize($path);
  103. $this->config['uploadURL'] = "$protocol://$domain" . (strlen($port) ? ":$port" : "") . "/$path";
  104. $this->config['uploadDir'] = strlen($this->config['uploadDir'])
  105. ? path::normalize($this->config['uploadDir'])
  106. : path::url2fullPath("/$path");
  107. $this->typeDir = "{$this->config['uploadDir']}/{$this->type}";
  108. $this->typeURL = "{$this->config['uploadURL']}/{$this->type}";
  109. // SITE ROOT
  110. } elseif ($this->config['uploadURL'] == "/") {
  111. $this->config['uploadDir'] = strlen($this->config['uploadDir'])
  112. ? path::normalize($this->config['uploadDir'])
  113. : path::normalize($_SERVER['DOCUMENT_ROOT']);
  114. $this->typeDir = "{$this->config['uploadDir']}/{$this->type}";
  115. $this->typeURL = "/{$this->type}";
  116. // ABSOLUTE & RELATIVE
  117. } else {
  118. $this->config['uploadURL'] = (substr($this->config['uploadURL'], 0, 1) === "/")
  119. ? path::normalize($this->config['uploadURL'])
  120. : path::rel2abs_url($this->config['uploadURL']);
  121. $this->config['uploadDir'] = strlen($this->config['uploadDir'])
  122. ? path::normalize($this->config['uploadDir'])
  123. : path::url2fullPath($this->config['uploadURL']);
  124. $this->typeDir = "{$this->config['uploadDir']}/{$this->type}";
  125. $this->typeURL = "{$this->config['uploadURL']}/{$this->type}";
  126. }
  127. if (!is_dir($this->config['uploadDir']))
  128. @mkdir($this->config['uploadDir'], $this->config['dirPerms']);
  129. // HOST APPLICATIONS INIT
  130. if (isset($this->get['CKEditorFuncNum']))
  131. $this->opener['CKEditor']['funcNum'] = $this->get['CKEditorFuncNum'];
  132. if (isset($this->get['opener']) &&
  133. (strtolower($this->get['opener']) == "tinymce") &&
  134. isset($this->config['_tinyMCEPath']) &&
  135. strlen($this->config['_tinyMCEPath'])
  136. )
  137. $this->opener['TinyMCE'] = true;
  138. // LOCALIZATION
  139. foreach ($this->langInputNames as $key)
  140. if (isset($this->get[$key]) &&
  141. preg_match('/^[a-z][a-z\._\-]*$/i', $this->get[$key]) &&
  142. file_exists("lang/" . strtolower($this->get[$key]) . ".php")
  143. ) {
  144. $this->lang = $this->get[$key];
  145. break;
  146. }
  147. $this->localize($this->lang);
  148. // CHECK & MAKE DEFAULT .htaccess
  149. if (isset($this->config['_check4htaccess']) &&
  150. $this->config['_check4htaccess']
  151. ) {
  152. $htaccess = "{$this->config['uploadDir']}/.htaccess";
  153. if (!file_exists($htaccess)) {
  154. if (!@file_put_contents($htaccess, $this->get_htaccess()))
  155. $this->backMsg("Cannot write to upload folder. {$this->config['uploadDir']}");
  156. } else {
  157. if (false === ($data = @file_get_contents($htaccess)))
  158. $this->backMsg("Cannot read .htaccess");
  159. if (($data != $this->get_htaccess()) && !@file_put_contents($htaccess, $data))
  160. $this->backMsg("Incorrect .htaccess file. Cannot rewrite it!");
  161. }
  162. }
  163. // CHECK & CREATE UPLOAD FOLDER
  164. if (!is_dir($this->typeDir)) {
  165. if (!mkdir($this->typeDir, $this->config['dirPerms']))
  166. $this->backMsg("Cannot create {dir} folder.", array('dir' => $this->type));
  167. } elseif (!is_readable($this->typeDir))
  168. $this->backMsg("Cannot read upload folder.");
  169. }
  170. public function upload() {
  171. $config = &$this->config;
  172. $file = &$this->file;
  173. $url = $message = "";
  174. if ($config['disabled'] || !$config['access']['files']['upload']) {
  175. if (isset($file['tmp_name'])) @unlink($file['tmp_name']);
  176. $message = $this->label("You don't have permissions to upload files.");
  177. } elseif (true === ($message = $this->checkUploadedFile())) {
  178. $message = "";
  179. $dir = "{$this->typeDir}/";
  180. if (isset($this->get['dir']) &&
  181. (false !== ($gdir = $this->checkInputDir($this->get['dir'])))
  182. ) {
  183. $udir = path::normalize("$dir$gdir");
  184. if (substr($udir, 0, strlen($dir)) !== $dir)
  185. $message = $this->label("Unknown error.");
  186. else {
  187. $l = strlen($dir);
  188. $dir = "$udir/";
  189. $udir = substr($udir, $l);
  190. }
  191. }
  192. if (!strlen($message)) {
  193. if (!is_dir(path::normalize($dir)))
  194. @mkdir(path::normalize($dir), $this->config['dirPerms'], true);
  195. $filename = $this->normalizeFilename($file['name']);
  196. $target = file::getInexistantFilename($dir . $filename);
  197. if (!@move_uploaded_file($file['tmp_name'], $target) &&
  198. !@rename($file['tmp_name'], $target) &&
  199. !@copy($file['tmp_name'], $target)
  200. )
  201. $message = $this->label("Cannot move uploaded file to target folder.");
  202. else {
  203. if (function_exists('chmod'))
  204. @chmod($target, $this->config['filePerms']);
  205. $this->makeThumb($target);
  206. $url = $this->typeURL;
  207. if (isset($udir)) $url .= "/$udir";
  208. $url .= "/" . basename($target);
  209. if (preg_match('/^([a-z]+)\:\/\/([^\/^\:]+)(\:(\d+))?\/(.+)$/', $url, $patt)) {
  210. list($unused, $protocol, $domain, $unused, $port, $path) = $patt;
  211. $base = "$protocol://$domain" . (strlen($port) ? ":$port" : "") . "/";
  212. $url = $base . path::urlPathEncode($path);
  213. } else
  214. $url = path::urlPathEncode($url);
  215. }
  216. }
  217. }
  218. if (strlen($message) &&
  219. isset($this->file['tmp_name']) &&
  220. file_exists($this->file['tmp_name'])
  221. )
  222. @unlink($this->file['tmp_name']);
  223. if (strlen($message) && method_exists($this, 'errorMsg'))
  224. $this->errorMsg($message);
  225. $this->callBack($url, $message);
  226. }
  227. protected function normalizeFilename($filename) {
  228. if (isset($this->config['filenameChangeChars']) &&
  229. is_array($this->config['filenameChangeChars'])
  230. )
  231. $filename = strtr($filename, $this->config['filenameChangeChars']);
  232. return $filename;
  233. }
  234. protected function normalizeDirname($dirname) {
  235. if (isset($this->config['dirnameChangeChars']) &&
  236. is_array($this->config['dirnameChangeChars'])
  237. )
  238. $dirname = strtr($dirname, $this->config['dirnameChangeChars']);
  239. return $dirname;
  240. }
  241. protected function checkUploadedFile(array $aFile=null) {
  242. $config = &$this->config;
  243. $file = ($aFile === null) ? $this->file : $aFile;
  244. if (!is_array($file) || !isset($file['name']))
  245. return $this->label("Unknown error");
  246. if (is_array($file['name'])) {
  247. foreach ($file['name'] as $i => $name) {
  248. $return = $this->checkUploadedFile(array(
  249. 'name' => $name,
  250. 'tmp_name' => $file['tmp_name'][$i],
  251. 'error' => $file['error'][$i]
  252. ));
  253. if ($return !== true)
  254. return "$name: $return";
  255. }
  256. return true;
  257. }
  258. $extension = file::getExtension($file['name']);
  259. $typePatt = strtolower(text::clearWhitespaces($this->types[$this->type]));
  260. // CHECK FOR UPLOAD ERRORS
  261. if ($file['error'])
  262. return
  263. ($file['error'] == UPLOAD_ERR_INI_SIZE) ?
  264. $this->label("The uploaded file exceeds {size} bytes.",
  265. array('size' => ini_get('upload_max_filesize'))) : (
  266. ($file['error'] == UPLOAD_ERR_FORM_SIZE) ?
  267. $this->label("The uploaded file exceeds {size} bytes.",
  268. array('size' => $this->get['MAX_FILE_SIZE'])) : (
  269. ($file['error'] == UPLOAD_ERR_PARTIAL) ?
  270. $this->label("The uploaded file was only partially uploaded.") : (
  271. ($file['error'] == UPLOAD_ERR_NO_FILE) ?
  272. $this->label("No file was uploaded.") : (
  273. ($file['error'] == UPLOAD_ERR_NO_TMP_DIR) ?
  274. $this->label("Missing a temporary folder.") : (
  275. ($file['error'] == UPLOAD_ERR_CANT_WRITE) ?
  276. $this->label("Failed to write file.") :
  277. $this->label("Unknown error.")
  278. )))));
  279. // HIDDEN FILENAMES CHECK
  280. elseif (substr($file['name'], 0, 1) == ".")
  281. return $this->label("File name shouldn't begins with '.'");
  282. // EXTENSION CHECK
  283. elseif (!$this->validateExtension($extension, $this->type))
  284. return $this->label("Denied file extension.");
  285. // SPECIAL DIRECTORY TYPES CHECK (e.g. *img)
  286. elseif (preg_match('/^\*([^ ]+)(.*)?$/s', $typePatt, $patt)) {
  287. list($typePatt, $type, $params) = $patt;
  288. if (class_exists("type_$type")) {
  289. $class = "type_$type";
  290. $type = new $class();
  291. $cfg = $config;
  292. $cfg['filename'] = $file['name'];
  293. if (strlen($params))
  294. $cfg['params'] = trim($params);
  295. $response = $type->checkFile($file['tmp_name'], $cfg);
  296. if ($response !== true)
  297. return $this->label($response);
  298. } else
  299. return $this->label("Non-existing directory type.");
  300. }
  301. // IMAGE RESIZE
  302. $gd = new gd($file['tmp_name']);
  303. if (!$gd->init_error && !$this->imageResize($gd, $file['tmp_name']))
  304. return $this->label("The image is too big and/or cannot be resized.");
  305. return true;
  306. }
  307. protected function checkInputDir($dir, $inclType=true, $existing=true) {
  308. $dir = path::normalize($dir);
  309. if (substr($dir, 0, 1) == "/")
  310. $dir = substr($dir, 1);
  311. if ((substr($dir, 0, 1) == ".") || (substr(basename($dir), 0, 1) == "."))
  312. return false;
  313. if ($inclType) {
  314. $first = explode("/", $dir);
  315. $first = $first[0];
  316. if ($first != $this->type)
  317. return false;
  318. $return = $this->removeTypeFromPath($dir);
  319. } else {
  320. $return = $dir;
  321. $dir = "{$this->type}/$dir";
  322. }
  323. if (!$existing)
  324. return $return;
  325. $path = "{$this->config['uploadDir']}/$dir";
  326. return (is_dir($path) && is_readable($path)) ? $return : false;
  327. }
  328. protected function validateExtension($ext, $type) {
  329. $ext = trim(strtolower($ext));
  330. if (!isset($this->types[$type]))
  331. return false;
  332. $exts = strtolower(text::clearWhitespaces($this->config['deniedExts']));
  333. if (strlen($exts)) {
  334. $exts = explode(" ", $exts);
  335. if (in_array($ext, $exts))
  336. return false;
  337. }
  338. $exts = trim($this->types[$type]);
  339. if (!strlen($exts) || substr($exts, 0, 1) == "*")
  340. return true;
  341. if (substr($exts, 0, 1) == "!") {
  342. $exts = explode(" ", trim(strtolower(substr($exts, 1))));
  343. return !in_array($ext, $exts);
  344. }
  345. $exts = explode(" ", trim(strtolower($exts)));
  346. return in_array($ext, $exts);
  347. }
  348. protected function getTypeFromPath($path) {
  349. return preg_match('/^([^\/]*)\/.*$/', $path, $patt)
  350. ? $patt[1] : $path;
  351. }
  352. protected function removeTypeFromPath($path) {
  353. return preg_match('/^[^\/]*\/(.*)$/', $path, $patt)
  354. ? $patt[1] : "";
  355. }
  356. protected function imageResize($image, $file=null) {
  357. if (!($image instanceof gd)) {
  358. $gd = new gd($image);
  359. if ($gd->init_error) return false;
  360. $file = $image;
  361. } elseif ($file === null)
  362. return false;
  363. else
  364. $gd = $image;
  365. if ((!$this->config['maxImageWidth'] && !$this->config['maxImageHeight']) ||
  366. (
  367. ($gd->get_width() <= $this->config['maxImageWidth']) &&
  368. ($gd->get_height() <= $this->config['maxImageHeight'])
  369. )
  370. )
  371. return true;
  372. if ((!$this->config['maxImageWidth'] || !$this->config['maxImageHeight'])) {
  373. if ($this->config['maxImageWidth']) {
  374. $width = $this->config['maxImageWidth'];
  375. $height = $gd->get_prop_height($width);
  376. } else {
  377. $height = $this->config['maxImageHeight'];
  378. $width = $gd->get_prop_width($height);
  379. }
  380. if (!$gd->resize($width, $height))
  381. return false;
  382. } elseif (!$gd->resize_fit(
  383. $this->config['maxImageWidth'], $this->config['maxImageHeight']
  384. ))
  385. return false;
  386. return $gd->imagejpeg($file, $this->config['jpegQuality']);
  387. }
  388. protected function makeThumb($file, $overwrite=true) {
  389. $gd = new gd($file);
  390. // Drop files which are not GD handled images
  391. if ($gd->init_error)
  392. return true;
  393. $thumb = substr($file, strlen($this->config['uploadDir']));
  394. $thumb = $this->config['uploadDir'] . "/" . $this->config['thumbsDir'] . "/" . $thumb;
  395. $thumb = path::normalize($thumb);
  396. $thumbDir = dirname($thumb);
  397. if (!is_dir($thumbDir) && !@mkdir($thumbDir, $this->config['dirPerms'], true))
  398. return false;
  399. if (!$overwrite && is_file($thumb))
  400. return true;
  401. // Images with smaller resolutions than thumbnails
  402. if (($gd->get_width() <= $this->config['thumbWidth']) &&
  403. ($gd->get_height() <= $this->config['thumbHeight'])
  404. ) {
  405. $browsable = array(IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG);
  406. // Drop only browsable types
  407. if (in_array($gd->type, $browsable))
  408. return true;
  409. // Resize image
  410. } elseif (!$gd->resize_fit($this->config['thumbWidth'], $this->config['thumbHeight']))
  411. return false;
  412. // Save thumbnail
  413. return $gd->imagejpeg($thumb, $this->config['jpegQuality']);
  414. }
  415. protected function localize($langCode) {
  416. require "lang/{$langCode}.php";
  417. setlocale(LC_ALL, $lang['_locale']);
  418. $this->charset = $lang['_charset'];
  419. $this->dateTimeFull = $lang['_dateTimeFull'];
  420. $this->dateTimeMid = $lang['_dateTimeMid'];
  421. $this->dateTimeSmall = $lang['_dateTimeSmall'];
  422. unset($lang['_locale']);
  423. unset($lang['_charset']);
  424. unset($lang['_dateTimeFull']);
  425. unset($lang['_dateTimeMid']);
  426. unset($lang['_dateTimeSmall']);
  427. $this->labels = $lang;
  428. }
  429. protected function label($string, array $data=null) {
  430. $return = isset($this->labels[$string]) ? $this->labels[$string] : $string;
  431. if (is_array($data))
  432. foreach ($data as $key => $val)
  433. $return = str_replace("{{$key}}", $val, $return);
  434. return $return;
  435. }
  436. protected function backMsg($message, array $data=null) {
  437. $message = $this->label($message, $data);
  438. if (isset($this->file['tmp_name']) && file_exists($this->file['tmp_name']))
  439. @unlink($this->file['tmp_name']);
  440. $this->callBack("", $message);
  441. die;
  442. }
  443. protected function callBack($url, $message="") {
  444. $message = text::jsValue($message);
  445. $CKfuncNum = isset($this->opener['CKEditor']['funcNum'])
  446. ? $this->opener['CKEditor']['funcNum'] : 0;
  447. if (!$CKfuncNum) $CKfuncNum = 0;
  448. header("Content-Type: text/html; charset={$this->charset}");
  449. ?><html>
  450. <body>
  451. <script type='text/javascript'>
  452. var kc_CKEditor = (window.parent && window.parent.CKEDITOR)
  453. ? window.parent.CKEDITOR.tools.callFunction
  454. : ((window.opener && window.opener.CKEDITOR)
  455. ? window.opener.CKEDITOR.tools.callFunction
  456. : false);
  457. var kc_FCKeditor = (window.opener && window.opener.OnUploadCompleted)
  458. ? window.opener.OnUploadCompleted
  459. : ((window.parent && window.parent.OnUploadCompleted)
  460. ? window.parent.OnUploadCompleted
  461. : false);
  462. var kc_Custom = (window.parent && window.parent.KCFinder)
  463. ? window.parent.KCFinder.callBack
  464. : ((window.opener && window.opener.KCFinder)
  465. ? window.opener.KCFinder.callBack
  466. : false);
  467. if (kc_CKEditor)
  468. kc_CKEditor(<?php echo $CKfuncNum ?>, '<?php echo $url ?>', '<?php echo $message ?>');
  469. if (kc_FCKeditor)
  470. kc_FCKeditor(<?php echo strlen($message) ? 1 : 0 ?>, '<?php echo $url ?>', '', '<?php echo $message ?>');
  471. if (kc_Custom) {
  472. if (<?php echo strlen($message) ?>) alert('<?php echo $message ?>');
  473. kc_Custom('<?php echo $url ?>');
  474. }
  475. if (!kc_CKEditor && !kc_FCKeditor && !kc_Custom)
  476. alert("<?php echo $message ?>");
  477. </script>
  478. </body>
  479. </html><?php
  480. }
  481. protected function get_htaccess() {
  482. return "<IfModule mod_php4.c>
  483. php_value engine off
  484. </IfModule>
  485. <IfModule mod_php5.c>
  486. php_value engine off
  487. </IfModule>
  488. ";
  489. }
  490. }
  491. ?>