PageRenderTime 53ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/inc/classes/upload.class.php

https://github.com/Laurelai/tsukiboards
PHP | 439 lines | 369 code | 34 blank | 36 comment | 104 complexity | da6f57dd94c9ebff7aa873c6ed6a4bab MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1
  1. <?php
  2. /*
  3. * This file is part of arcNET
  4. *
  5. * arcNET uses core code from Kusaba X and Oneechan
  6. *
  7. * tsukihi.me kusabax.cultnet.net oneechan.org
  8. *
  9. * arcNET is free software; you can redistribute it and/or modify it under the
  10. * terms of the GNU General Public License as published by the Free Software
  11. * Foundation; either version 2 of the License, or (at your option) any later
  12. * version.
  13. *
  14. * kusaba is distributed in the hope that it will be useful, but WITHOUT ANY
  15. * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  16. * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License along with
  19. * kusaba; if not, write to the Free Software Foundation, Inc.,
  20. * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  21. *
  22. * credits to jmyeom for improving this
  23. *
  24. */
  25. class Upload {
  26. var $file_name = '';
  27. var $original_file_name = '';
  28. var $file_type = '';
  29. var $file_md5 = '';
  30. var $file_location = '';
  31. var $file_thumb_location = '';
  32. var $file_is_special = false;
  33. var $imgWidth = 0;
  34. var $imgHeight = 0;
  35. var $file_size = 0;
  36. var $imgWidth_thumb = 0;
  37. var $imgHeight_thumb = 0;
  38. var $isreply = false;
  39. function HandleUpload() {
  40. global $tc_db, $board_class, $is_oekaki, $oekaki, $posting_class;
  41. if (!$is_oekaki) {
  42. if ($board_class->board['type'] == 0 || $board_class->board['type'] == 2 || $board_class->board['type'] == 3) {
  43. $imagefile_name = isset($_FILES['imagefile']) ? $_FILES['imagefile']['name'] : '';
  44. if ($imagefile_name != '') {
  45. if (strpos($_FILES['imagefile']['name'], ',') != false) {
  46. exitWithErrorPage(_gettext('Please select only one image to upload.'));
  47. }
  48. if ($_FILES['imagefile']['size'] > $board_class->board['maximagesize']) {
  49. exitWithErrorPage(sprintf(_gettext('Please make sure your file is smaller than %dB'), $board_class->board['maximagesize']));
  50. }
  51. switch ($_FILES['imagefile']['error']) {
  52. case UPLOAD_ERR_OK:
  53. break;
  54. case UPLOAD_ERR_INI_SIZE:
  55. exitWithErrorPage(sprintf(_gettext('The uploaded file exceeds the upload_max_filesize directive (%s) in php.ini.')), ini_get('upload_max_filesize'));
  56. break;
  57. case UPLOAD_ERR_FORM_SIZE:
  58. exitWithErrorPage(sprintf(_gettext('Please make sure your file is smaller than %dB'), $board_class->board['maximagesize']));
  59. break;
  60. case UPLOAD_ERR_PARTIAL:
  61. exitWithErrorPage(_gettext('The uploaded file was only partially uploaded.'));
  62. break;
  63. case UPLOAD_ERR_NO_FILE:
  64. exitWithErrorPage(_gettext('No file was uploaded.'));
  65. break;
  66. case UPLOAD_ERR_NO_TMP_DIR:
  67. exitWithErrorPage(_gettext('Missing a temporary folder.'));
  68. break;
  69. case UPLOAD_ERR_CANT_WRITE:
  70. exitWithErrorPage(_gettext('Failed to write file to disk'));
  71. break;
  72. default:
  73. exitWithErrorPage(_gettext('Unknown File Error'));
  74. }
  75. $this->file_type = preg_replace('/.*(\..+)/','\1',$_FILES['imagefile']['name']);
  76. if ($this->file_type == '.jpeg') {
  77. /* Fix for the rarely used 4-char format */
  78. $this->file_type = '.jpg';
  79. }
  80. $pass = true;
  81. if (!is_file($_FILES['imagefile']['tmp_name']) || !is_readable($_FILES['imagefile']['tmp_name'])) {
  82. $pass = false;
  83. } else {
  84. if ($this->file_type == '.jpg' || $this->file_type == '.gif' || $this->file_type == '.png') {
  85. if (!@getimagesize($_FILES['imagefile']['tmp_name'])) {
  86. $pass = false;
  87. }
  88. }
  89. }
  90. if (!$pass) {
  91. exitWithErrorPage(_gettext('File transfer failure. Please go back and try again.'));
  92. }
  93. $this->file_name = substr(htmlspecialchars(preg_replace('/(.*)\..+/','\1',$_FILES['imagefile']['name']), ENT_QUOTES), 0, 50);
  94. $this->file_name = str_replace('.','_',$this->file_name);
  95. $this->original_file_name = $this->file_name;
  96. $this->file_md5 = md5_file($_FILES['imagefile']['tmp_name']);
  97. $exists_thread = checkMd5($this->file_md5, $board_class->board['name'], $board_class->board['id']);
  98. if (is_array($exists_thread)) {
  99. exitWithErrorPage(_gettext('Duplicate file entry detected.'), sprintf(_gettext('Already posted %shere%s.'),'<a href="' . KU_BOARDSPATH . '/' . $board_class->board['name'] . '/res/' . $exists_thread[0] . '.html#' . $exists_thread[1] . '">','</a>'));
  100. }
  101. if (strtolower($this->file_type) == 'svg') {
  102. require_once 'svg.class.php';
  103. $svg = new Svg($_FILES['imagefile']['tmp_name']);
  104. $this->imgWidth = $svg->width;
  105. $this->imgHeight = $svg->height;
  106. } else {
  107. $imageDim = getimagesize($_FILES['imagefile']['tmp_name']);
  108. $this->imgWidth = $imageDim[0];
  109. $this->imgHeight = $imageDim[1];
  110. }
  111. $this->file_type = strtolower($this->file_type);
  112. $this->file_size = $_FILES['imagefile']['size'];
  113. $filetype_forcethumb = $tc_db->GetOne("SELECT " . KU_DBPREFIX . "filetypes.force_thumb FROM " . KU_DBPREFIX . "boards, " . KU_DBPREFIX . "filetypes, " . KU_DBPREFIX . "board_filetypes WHERE " . KU_DBPREFIX . "boards.id = " . KU_DBPREFIX . "board_filetypes.boardid AND " . KU_DBPREFIX . "filetypes.id = " . KU_DBPREFIX . "board_filetypes.typeid AND " . KU_DBPREFIX . "boards.name = '" . $board_class->board['name'] . "' and " . KU_DBPREFIX . "filetypes.filetype = '" . substr($this->file_type, 1) . "';");
  114. if ($filetype_forcethumb != '') {
  115. if ($filetype_forcethumb == 0) {
  116. $this->file_name = time() . mt_rand(1, 99);
  117. /* If this board has a load balance url and password configured for it, attempt to use it */
  118. if ($board_class->board['loadbalanceurl'] != '' && $board_class->board['loadbalancepassword'] != '') {
  119. require_once KU_ROOTDIR . 'inc/classes/loadbalancer.class.php';
  120. $loadbalancer = new Load_Balancer;
  121. $loadbalancer->url = $board_class->board['loadbalanceurl'];
  122. $loadbalancer->password = $board_class->board['loadbalancepassword'];
  123. $response = $loadbalancer->Send('thumbnail', base64_encode(file_get_contents($_FILES['imagefile']['tmp_name'])), 'src/' . $this->file_name . $this->file_type, 'thumb/' . $this->file_name . 's' . $this->file_type, 'thumb/' . $this->file_name . 'c' . $this->file_type, '', $this->isreply, true);
  124. if ($response != 'failure' && $response != '') {
  125. $response_unserialized = unserialize($response);
  126. $this->imgWidth_thumb = $response_unserialized['imgw_thumb'];
  127. $this->imgHeight_thumb = $response_unserialized['imgh_thumb'];
  128. $imageused = true;
  129. } else {
  130. exitWithErrorPage(_gettext('File was not properly thumbnailed').': ' . $response);
  131. }
  132. /* Otherwise, use this script alone */
  133. } else {
  134. $this->file_location = KU_BOARDSDIR . $board_class->board['name'] . '/src/' . $this->file_name . $this->file_type;
  135. $this->file_thumb_location = KU_BOARDSDIR . $board_class->board['name'] . '/thumb/' . $this->file_name . 's' . $this->file_type;
  136. $this->file_thumb_cat_location = KU_BOARDSDIR . $board_class->board['name'] . '/thumb/' . $this->file_name . 'c' . $this->file_type;
  137. if (!move_uploaded_file($_FILES['imagefile']['tmp_name'], $this->file_location)) {
  138. exitWithErrorPage(_gettext('Could not copy uploaded image.'));
  139. }
  140. chmod($this->file_location, 0644);
  141. if ($_FILES['imagefile']['size'] == filesize($this->file_location)) {
  142. if( $posting_class->IsSpoilerImage() )
  143. {
  144. // RH - Spoiler image thumbnailing. Really we should have a single static image path, but for now it's easier to stupidly
  145. // create copies with the names other parts of arcNet expect ... I guess it should at least be small (optimised e.g. with pngcrush)
  146. $spoiler = KU_ROOTDIR . 'spoiler.png';
  147. $spoiler_catalog = KU_ROOTDIR . 'spoiler_catalog.png';
  148. copy( $spoiler, $this->file_thumb_location );
  149. copy( $spoiler_catalog, $this->file_thumb_cat_location );
  150. if ( ! $this->isreply ) {
  151. $this->imgWidth_thumb = 200; // Spoiler posted fullsize, as OP of a thread
  152. $this->imgHeight_thumb = 162;
  153. } else {
  154. $this->imgWidth_thumb = 125; // In-thread images are smaller
  155. $this->imgHeight_thumb = 101;
  156. }
  157. $imageused = true;
  158. }
  159. else
  160. {
  161. // Normal thumbnailing
  162. if ((!$this->isreply && ($this->imgWidth > KU_THUMBWIDTH || $this->imgHeight > KU_THUMBHEIGHT)) || ($this->isreply && ($this->imgWidth > KU_REPLYTHUMBWIDTH || $this->imgHeight > KU_REPLYTHUMBHEIGHT))) {
  163. if (!$this->isreply) {
  164. if (!createThumbnail($this->file_location, $this->file_thumb_location, KU_THUMBWIDTH, KU_THUMBHEIGHT)) {
  165. exitWithErrorPage(_gettext('Could not create thumbnail.'));
  166. }
  167. } else {
  168. if (!createThumbnail($this->file_location, $this->file_thumb_location, KU_REPLYTHUMBWIDTH, KU_REPLYTHUMBHEIGHT)) {
  169. exitWithErrorPage(_gettext('Could not create thumbnail.'));
  170. }
  171. }
  172. } else {
  173. if (!createThumbnail($this->file_location, $this->file_thumb_location, $this->imgWidth, $this->imgHeight)) {
  174. exitWithErrorPage(_gettext('Could not create thumbnail.'));
  175. }
  176. }
  177. if (!createThumbnail($this->file_location, $this->file_thumb_cat_location, KU_CATTHUMBWIDTH, KU_CATTHUMBHEIGHT)) {
  178. exitWithErrorPage(_gettext('Could not create thumbnail.'));
  179. }
  180. $imageDim_thumb = getimagesize($this->file_thumb_location);
  181. $this->imgWidth_thumb = $imageDim_thumb[0];
  182. $this->imgHeight_thumb = $imageDim_thumb[1];
  183. $imageused = true;
  184. }
  185. }
  186. else
  187. {
  188. exitWithErrorPage(_gettext('File was not fully uploaded. Please go back and try again.'));
  189. }
  190. }
  191. } else {
  192. /* Fetch the mime requirement for this special filetype */
  193. $filetype_required_mime = $tc_db->GetOne("SELECT `mime` FROM `" . KU_DBPREFIX . "filetypes` WHERE `filetype` = " . $tc_db->qstr(substr($this->file_type, 1)));
  194. $this->file_name = htmlspecialchars_decode($this->file_name, ENT_QUOTES);
  195. $this->file_name = stripslashes($this->file_name);
  196. $this->file_name = str_replace("\x80", " ", $this->file_name);
  197. $this->file_name = str_replace(' ', '_', $this->file_name);
  198. $this->file_name = str_replace('#', '(number)', $this->file_name);
  199. $this->file_name = str_replace('@', '(at)', $this->file_name);
  200. $this->file_name = str_replace('/', '(fwslash)', $this->file_name);
  201. $this->file_name = str_replace('\\', '(bkslash)', $this->file_name);
  202. /* If this board has a load balance url and password configured for it, attempt to use it */
  203. if ($board_class->board['loadbalanceurl'] != '' && $board_class->board['loadbalancepassword'] != '') {
  204. require_once KU_ROOTDIR . 'inc/classes/loadbalancer.class.php';
  205. $loadbalancer = new Load_Balancer;
  206. $loadbalancer->url = $board_class->board['loadbalanceurl'];
  207. $loadbalancer->password = $board_class->board['loadbalancepassword'];
  208. if ($filetype_required_mime != '') {
  209. $checkmime = $filetype_required_mime;
  210. } else {
  211. $checkmime = '';
  212. }
  213. $response = $loadbalancer->Send('direct', $_FILES['imagefile']['tmp_name'], 'src/' . $this->file_name . $this->file_type, '', '', $checkmime, false, true);
  214. $this->file_is_special = true;
  215. /* Otherwise, use this script alone */
  216. } else {
  217. $this->file_location = KU_BOARDSDIR . $board_class->board['name'] . '/src/' . $this->file_name . $this->file_type;
  218. if (file_exists($this->file_location)) {
  219. exitWithErrorPage(_gettext('A file by that name already exists'));
  220. die();
  221. }
  222. if($this->file_type == '.mp3') {
  223. require_once(KU_ROOTDIR . 'lib/getid3/getid3.php');
  224. $getID3 = new getID3;
  225. $getID3->analyze($_FILES['imagefile']['tmp_name']);
  226. if (isset($getID3->info['id3v2']['APIC'][0]['data']) && isset($getID3->info['id3v2']['APIC'][0]['image_mime'])) {
  227. $source_data = $getID3->info['id3v2']['APIC'][0]['data'];
  228. $mime = $getID3->info['id3v2']['APIC'][0]['image_mime'];
  229. }
  230. elseif (isset($getID3->info['id3v2']['PIC'][0]['data']) && isset($getID3->info['id3v2']['PIC'][0]['image_mime'])) {
  231. $source_data = $getID3->info['id3v2']['PIC'][0]['data'];
  232. $mime = $getID3->info['id3v2']['PIC'][0]['image_mime'];
  233. }
  234. if($source_data) {
  235. $im = imagecreatefromstring($source_data);
  236. if (preg_match("/png/", $mime)) {
  237. $ext = ".png";
  238. imagepng($im,$this->file_location.".tmp",0,PNG_ALL_FILTERS);
  239. } else if (preg_match("/jpg|jpeg/", $mime)) {
  240. $ext = ".jpg";
  241. imagejpeg($im, $this->file_location.".tmp");
  242. } else if (preg_match("/gif/", $mime)) {
  243. $ext = ".gif";
  244. imagegif($im, $this->file_location.".tmp");
  245. }
  246. $this->file_thumb_location = KU_BOARDSDIR . $board_class->board['name'] . '/thumb/' . $this->file_name .'s'. $ext;
  247. if (!$this->isreply) {
  248. if (!createThumbnail($this->file_location.".tmp", $this->file_thumb_location, KU_THUMBWIDTH, KU_THUMBHEIGHT)) {
  249. exitWithErrorPage(_gettext('Could not create thumbnail.'));
  250. }
  251. } else {
  252. if (!createThumbnail($this->file_location.".tmp", $this->file_thumb_location, KU_REPLYTHUMBWIDTH, KU_REPLYTHUMBHEIGHT)) {
  253. exitWithErrorPage(_gettext('Could not create thumbnail.'));
  254. }
  255. }
  256. $imageDim_thumb = getimagesize($this->file_thumb_location);
  257. $this->imgWidth_thumb = $imageDim_thumb[0];
  258. $this->imgHeight_thumb = $imageDim_thumb[1];
  259. $imageused = true;
  260. unlink($this->file_location.".tmp");
  261. }
  262. }
  263. /* Move the file from the post data to the server */
  264. if (!move_uploaded_file($_FILES['imagefile']['tmp_name'], $this->file_location)) {
  265. exitWithErrorPage(_gettext('Could not copy uploaded image.'));
  266. }
  267. /* Check if the filetype provided comes with a MIME restriction */
  268. if ($filetype_required_mime != '') {
  269. /* Check if the MIMEs don't match up */
  270. if (mime_content_type($this->file_location) != $filetype_required_mime) {
  271. /* Delete the file we just uploaded and kill the script */
  272. unlink($this->file_location);
  273. exitWithErrorPage(_gettext('Invalid MIME type for this filetype.'));
  274. }
  275. }
  276. /* Make sure the entire file was uploaded */
  277. if ($_FILES['imagefile']['size'] == filesize($this->file_location)) {
  278. $imageused = true;
  279. } else {
  280. exitWithErrorPage(_gettext('File transfer failure. Please go back and try again.'));
  281. }
  282. /* Flag that the file used isn't an internally supported type */
  283. $this->file_is_special = true;
  284. }
  285. }
  286. } else {
  287. exitWithErrorPage(_gettext('Sorry, that filetype is not allowed on this board.'));
  288. }
  289. } elseif (isset($_POST['embed'])) {
  290. if ($_POST['embed'] != '') {
  291. $_POST['embed'] = strip_tags(substr($_POST['embed'], 0, 20));
  292. $video_id = $_POST['embed'];
  293. $this->file_name = $video_id;
  294. if ($video_id != '' && strpos($video_id, '@') == false && strpos($video_id, '&') == false) {
  295. $embeds = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "embeds`");
  296. $worked = false;
  297. foreach ($embeds as $line) {
  298. if ((strtolower($_POST['embedtype']) == strtolower($line['name'])) && in_array($line['filetype'], explode(',', $board_class->board['embeds_allowed']))) {
  299. $worked = true;
  300. $videourl_start = $line['videourl'];
  301. $this->file_type = '.' . strtolower($line['filetype']);
  302. }
  303. }
  304. if (!$worked) {
  305. exitWithErrorPage(_gettext('Invalid video type.'));
  306. }
  307. $results = $tc_db->GetOne("SELECT COUNT(*) FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $board_class->board['id'] . " AND `file` = " . $tc_db->qstr($video_id) . " AND `IS_DELETED` = 0");
  308. if ($results[0] == 0) {
  309. $video_check = check_link($videourl_start . $video_id);
  310. switch ($video_check[1]) {
  311. case 404:
  312. exitWithErrorPage(_gettext('Unable to connect to') .': '. $videourl_start . $video_id);
  313. break;
  314. case 303:
  315. exitWithErrorPage(_gettext('Invalid video ID.'));
  316. break;
  317. case 302:
  318. // Continue
  319. break;
  320. case 301:
  321. // Continue
  322. break;
  323. case 200:
  324. // Continue
  325. break;
  326. default:
  327. exitWithErrorPage(_gettext('Invalid response code ') .':'. $video_check[1]);
  328. break;
  329. }
  330. } else {
  331. $results = $tc_db->GetAll("SELECT `id`,`parentid` FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $board_class->board['id'] . " AND `file` = " . $tc_db->qstr($video_id) . " AND `IS_DELETED` = 0 LIMIT 1");
  332. foreach ($results as $line) {
  333. $real_threadid = ($line[1] == 0) ? $line[0] : $line[1];
  334. exitWithErrorPage(sprintf(_gettext('That video ID has already been posted %shere%s.'),'<a href="' . KU_BOARDSFOLDER . '/' . $board_class->board['name'] . '/res/' . $real_threadid . '.html#' . $line[1] . '">','</a>'));
  335. }
  336. }
  337. } else {
  338. exitWithErrorPage(_gettext('Invalid ID'));
  339. }
  340. }
  341. }
  342. }
  343. } else {
  344. $this->file_name = time() . mt_rand(1, 99);
  345. $this->original_file_name = $this->file_name;
  346. $this->file_md5 = md5_file($oekaki);
  347. $this->file_type = '.png';
  348. $this->file_size = filesize($oekaki);
  349. $imageDim = getimagesize($oekaki);
  350. $this->imgWidth = $imageDim[0];
  351. $this->imgHeight = $imageDim[1];
  352. if (!copy($oekaki, KU_BOARDSDIR . $board_class->board['name'] . '/src/' . $this->file_name . $this->file_type)) {
  353. exitWithErrorPage(_gettext('Could not copy uploaded image.'));
  354. }
  355. $oekaki_animation = substr($oekaki, 0, -4) . '.pch';
  356. if (file_exists($oekaki_animation)) {
  357. if (!copy($oekaki_animation, KU_BOARDSDIR . $board_class->board['name'] . '/src/' . $this->file_name . '.pch')) {
  358. exitWithErrorPage(_gettext('Could not copy animation.'));
  359. }
  360. unlink($oekaki_animation);
  361. }
  362. $thumbpath = KU_BOARDSDIR . $board_class->board['name'] . '/thumb/' . $this->file_name . 's' . $this->file_type;
  363. $thumbpath_cat = KU_BOARDSDIR . $board_class->board['name'] . '/thumb/' . $this->file_name . 'c' . $this->file_type;
  364. if (
  365. (!$this->isreply && ($this->imgWidth > KU_THUMBWIDTH || $this->imgHeight > KU_THUMBHEIGHT)) ||
  366. ($this->isreply && ($this->imgWidth > KU_REPLYTHUMBWIDTH || $this->imgHeight > KU_REPLYTHUMBHEIGHT))
  367. ) {
  368. if (!$this->isreply) {
  369. if (!createThumbnail($oekaki, $thumbpath, KU_THUMBWIDTH, KU_THUMBHEIGHT)) {
  370. exitWithErrorPage(_gettext('Could not create thumbnail.'));
  371. }
  372. } else {
  373. if (!createThumbnail($oekaki, $thumbpath, KU_REPLYTHUMBWIDTH, KU_REPLYTHUMBHEIGHT)) {
  374. exitWithErrorPage(_gettext('Could not create thumbnail.'));
  375. }
  376. }
  377. } else {
  378. if (!createThumbnail($oekaki, $thumbpath, $this->imgWidth, $this->imgHeight)) {
  379. exitWithErrorPage(_gettext('Could not create thumbnail.'));
  380. }
  381. }
  382. if (!createThumbnail($oekaki, $thumbpath_cat, KU_CATTHUMBWIDTH, KU_CATTHUMBHEIGHT)) {
  383. exitWithErrorPage(_gettext('Could not create thumbnail.'));
  384. }
  385. $imgDim_thumb = getimagesize($thumbpath);
  386. $this->imgWidth_thumb = $imgDim_thumb[0];
  387. $this->imgHeight_thumb = $imgDim_thumb[1];
  388. unlink($oekaki);
  389. }
  390. }
  391. }
  392. ?>