1<?php
2
3/*
4 * jQuery File Upload Plugin PHP Example 5.2.9
5 * https://github.com/blueimp/jQuery-File-Upload
6 *
7 * Copyright 2010, Sebastian Tschan
8 * https://blueimp.net
9 *
10 * Licensed under the MIT license:
11 * http://creativecommons.org/licenses/MIT/
12 */
13
14define('OFFSET_PATH', 3);
15require_once(dirname(dirname(dirname(__FILE__))) . '/admin-globals.php');
16
17$_zp_loggedin = NULL;
18if (isset($_POST['auth'])) {
19	$hash = sanitize($_POST['auth']);
20	$id = sanitize($_POST['id']);
21	$_zp_loggedin = $_zp_authority->checkAuthorization($hash, $id);
22}
23
24admin_securityChecks(UPLOAD_RIGHTS, $return = currentRelativeURL());
25
26$folder = zp_apply_filter('admin_upload_process', sanitize_path($_POST['folder']));
27$types = array_keys($_zp_extra_filetypes);
28if (function_exists('zip_open')) {
29	$types[] = 'ZIP';
30}
31$types = array_merge($_zp_supported_images, $types);
32$types = zp_apply_filter('upload_filetypes', $types);
33
34$options = array(
35				'upload_dir'				 => $targetPath = ALBUM_FOLDER_SERVERPATH . internalToFilesystem($folder) . '/',
36				'upload_url'				 => imgSrcURI(ALBUM_FOLDER_WEBPATH . $folder) . '/',
37				'accept_file_types'	 => '/(' . implode('|\.', $types) . ')$/i'
38);
39
40$new = !is_dir($targetPath);
41if (!empty($folder)) {
42	if ($new) {
43		$rightsalbum = newAlbum(dirname($folder), true, true);
44	} else {
45		$rightsalbum = newAlbum($folder, true, true);
46	}
47	if ($rightsalbum->exists) {
48		if (!$rightsalbum->isMyItem(UPLOAD_RIGHTS)) {
49			if (!zp_apply_filter('admin_managed_albums_access', false, $return)) {
50				redirectURL(FULLWEBPATH . '/' . ZENFOLDER . '/admin.php');
51			}
52		}
53	} else {
54		// upload to the root
55		if (!zp_loggedin(MANAGE_ALL_ALBUM_RIGHTS)) {
56			redirectURL(FULLWEBPATH . '/' . ZENFOLDER . '/admin.php');
57		}
58	}
59	if ($new) {
60		mkdir_recursive($targetPath, FOLDER_MOD);
61		$album = newAlbum($folder);
62		$album->setShow((int) !empty($_POST['publishalbum']));
63		$album->setTitle(sanitize($_POST['albumtitle']));
64		$album->setOwner($_zp_current_admin_obj->getUser());
65		$album->save();
66	}
67	@chmod($targetPath, FOLDER_MOD);
68}
69
70class UploadHandler {
71
72	private $options;
73
74	function __construct($options = null) {
75		$this->options = array(
76						'script_url'							 => $_SERVER['PHP_SELF'],
77						'upload_dir'							 => dirname(__FILE__) . '/files/',
78						'upload_url'							 => dirname($_SERVER['PHP_SELF']) . '/files/',
79						'param_name'							 => 'files',
80						// The php.ini settings upload_max_filesize and post_max_size
81						// take precedence over the following max_file_size setting:
82						'max_file_size'						 => null,
83						'min_file_size'						 => 1,
84						'accept_file_types'				 => '/.+$/i',
85						'max_number_of_files'			 => null,
86						'discard_aborted_uploads'	 => true,
87						'image_versions'					 => array(
88						// Uncomment the following version to restrict the size of
89						// uploaded images. You can also add additional versions with
90						// their own upload directories:
91						/*
92						  'large' => array(
93						  'upload_dir' => dirname(__FILE__).'/files/',
94						  'upload_url' => dirname($_SERVER['PHP_SELF']).'/files/',
95						  'max_width' => 1920,
96						  'max_height' => 1200
97						  ),
98
99						  'thumbnail' => array(
100						  'upload_dir' => dirname(__FILE__).'/thumbnails/',
101						  'upload_url' => dirname($_SERVER['PHP_SELF']).'/thumbnails/',
102						  'max_width' => 80,
103						  'max_height' => 80
104						  )
105						 */
106						)
107		);
108		if ($options) {
109			$this->options = array_replace_recursive($this->options, $options);
110		}
111	}
112
113	private function get_file_object($file_name) {
114		$file_path = $this->options['upload_dir'] . $file_name;
115		if (is_file($file_path) && $file_name[0] !== '.') {
116			$file = new stdClass();
117			$file->name = $file_name;
118			$file->size = filesize($file_path);
119			$file->url = $this->options['upload_url'] . rawurlencode($file->name);
120			foreach ($this->options['image_versions'] as $version => $options) {
121				if (is_file($options['upload_dir'] . $file_name)) {
122					$file->{$version . '_url'} = $options['upload_url']
123									. rawurlencode($file->name);
124				}
125			}
126			$file->delete_url = $this->options['script_url']
127							. '?file=' . rawurlencode($file->name);
128			$file->delete_type = 'DELETE';
129			return $file;
130		}
131		return null;
132	}
133
134	private function get_file_objects() {
135		return array_values(array_filter(array_map(
136														array($this, 'get_file_object'), scandir($this->options['upload_dir'])
137		)));
138	}
139
140	private function create_scaled_image($file_name, $options) {
141		$file_path = $this->options['upload_dir'] . $file_name;
142		$new_file_path = $options['upload_dir'] . $file_name;
143		list($img_width, $img_height) = @getimagesize($file_path);
144		if (!$img_width || !$img_height) {
145			return false;
146		}
147		$scale = min(
148						$options['max_width'] / $img_width, $options['max_height'] / $img_height
149		);
150		if ($scale > 1) {
151			$scale = 1;
152		}
153		$new_width = $img_width * $scale;
154		$new_height = $img_height * $scale;
155		$new_img = @imagecreatetruecolor($new_width, $new_height);
156		switch (strtolower(substr(strrchr($file_name, '.'), 1))) {
157			case 'jpg':
158			case 'jpeg':
159				$src_img = @imagecreatefromjpeg($file_path);
160				$write_image = 'imagejpeg';
161				break;
162			case 'gif':
163				@imagecolortransparent($new_img, @imagecolorallocate($new_img, 0, 0, 0));
164				$src_img = @imagecreatefromgif($file_path);
165				$write_image = 'imagegif';
166				break;
167			case 'png':
168				@imagecolortransparent($new_img, @imagecolorallocate($new_img, 0, 0, 0));
169				@imagealphablending($new_img, false);
170				@imagesavealpha($new_img, true);
171				$src_img = @imagecreatefrompng($file_path);
172				$write_image = 'imagepng';
173				break;
174			default:
175				$src_img = $image_method = null;
176		}
177		$success = $src_img && @imagecopyresampled(
178										$new_img, $src_img, 0, 0, 0, 0, $new_width, $new_height, $img_width, $img_height
179						) && $write_image($new_img, $new_file_path);
180		// Free up memory (imagedestroy does not delete files):
181		@imagedestroy($src_img);
182		@imagedestroy($new_img);
183		return $success;
184	}
185
186	private function has_error($uploaded_file, $file, $error) {
187		if ($error) {
188			return $error;
189		}
190		if (!preg_match($this->options['accept_file_types'], $file->name)) {
191			return 'acceptFileTypes';
192		}
193		if ($uploaded_file && is_uploaded_file($uploaded_file)) {
194			$file_size = filesize($uploaded_file);
195		} else {
196			$file_size = $_SERVER['CONTENT_LENGTH'];
197		}
198		if ($this->options['max_file_size'] && (
199						$file_size > $this->options['max_file_size'] ||
200						$file->size > $this->options['max_file_size'])
201		) {
202			return 'maxFileSize';
203		}
204		if ($this->options['min_file_size'] &&
205						$file_size < $this->options['min_file_size']) {
206			return 'minFileSize';
207		}
208		if (is_int($this->options['max_number_of_files']) && (
209						count($this->get_file_objects()) >= $this->options['max_number_of_files'])
210		) {
211			return 'maxNumberOfFiles';
212		}
213		return $error;
214	}
215
216	private function trim_file_name($name, $type) {
217		// Remove path information and dots around the filename, to prevent uploading
218		// into different directories or replacing hidden system files.
219		// Also remove control characters and spaces (\x00..\x20) around the filename:
220		$file_name = trim(basename(stripslashes($name)), ".\x00..\x20");
221		// Add missing file extension for known image types:
222		if (strpos($file_name, '.') === false &&
223						preg_match('/^image\/(gif|jpe?g|png)/', $type, $matches)) {
224			$file_name .= '.' . $matches[1];
225		}
226		return $file_name;
227	}
228
229	private function handle_file_upload($uploaded_file, $name, $size, $type, $error) {
230		global $folder, $targetPath, $_zp_current_admin_obj;
231		$file = new stdClass();
232		$name = $this->trim_file_name($name, $type);
233		$seoname = seoFriendly($name);
234		if (strrpos($seoname, '.') === 0)
235			$seoname = sha1($name) . $seoname; // soe stripped out all the name.
236		$targetFile = $targetPath . '/' . internalToFilesystem($seoname);
237		if (file_exists($targetFile)) {
238			$append = '_' . time();
239			$seoname = stripSuffix($seoname) . $append . '.' . getSuffix($seoname);
240			$targetFile = $targetPath . '/' . internalToFilesystem($seoname);
241		}
242		$file->name = $seoname;
243
244		$file->size = intval($size);
245		$file->type = $type;
246		$error = $this->has_error($uploaded_file, $file, $error);
247		if (!$error && $file->name) {
248			$file_path = $this->options['upload_dir'] . $file->name;
249			$append_file = !$this->options['discard_aborted_uploads'] &&
250							is_file($file_path) && $file->size > filesize($file_path);
251			clearstatcache();
252			if ($uploaded_file && is_uploaded_file($uploaded_file)) {
253				// multipart/formdata uploads (POST method uploads)
254				if ($append_file) {
255					file_put_contents($file_path, fopen($uploaded_file, 'r'), FILE_APPEND);
256				} else {
257					move_uploaded_file($uploaded_file, $file_path);
258					if (Gallery::validImage($name) || Gallery::validImageAlt($name)) {
259						@chmod($targetFile, FILE_MOD);
260						$album = newAlbum($folder);
261						$image = newImage($album, $seoname);
262						$image->setOwner($_zp_current_admin_obj->getUser());
263						if ($name != $seoname && $image->getTitle() == substr($seoname, 0, strrpos($seoname, '.'))) {
264							$image->setTitle(stripSuffix($name, '.'));
265						}
266						$image->save();
267					} else if (is_zip($targetFile)) {
268						unzip($targetFile, $targetPath);
269						unlink($targetFile);
270					} else {
271						$file->error = $error = UPLOAD_ERR_EXTENSION; // invalid file uploaded
272					}
273				}
274			} else {
275				// Non-multipart uploads (PUT method support)
276				file_put_contents(
277								$file_path, fopen('php://input', 'r'), $append_file ? FILE_APPEND : 0);
278			}
279			$file_size = filesize($file_path);
280			if ($file_size === $file->size) {
281				$file->url = $this->options['upload_url'] . rawurlencode($file->name);
282				foreach ($this->options['image_versions'] as $version => $options) {
283					if ($this->create_scaled_image($file->name, $options)) {
284						$file->{$version . '_url'} = $options['upload_url'] . rawurlencode($file->name);
285					}
286				}
287			} else if ($this->options['discard_aborted_uploads']) {
288				@chmod($file_path, 0777);
289				unlink($file_path);
290				$file->error = 'abort';
291			}
292			$file->size = $file_size;
293			$file->delete_url = $this->options['script_url'] . '?file=' . rawurlencode($file->name);
294			$file->delete_type = 'DELETE';
295		} else {
296			$file->error = $error;
297		}
298		return $file;
299	}
300
301	public function get() {
302		$file_name = isset($_REQUEST['file']) ?
303						basename(stripslashes($_REQUEST['file'])) : null;
304		if ($file_name) {
305			$info = $this->get_file_object($file_name);
306		} else {
307			$info = $this->get_file_objects();
308		}
309		header('Content-type: application/json');
310		echo json_encode($info);
311	}
312
313	public function post() {
314		$upload = isset($_FILES[$this->options['param_name']]) ?
315						$_FILES[$this->options['param_name']] : null;
316		$info = array();
317		if ($upload && is_array($upload['tmp_name'])) {
318			foreach ($upload['tmp_name'] as $index => $value) {
319				$info[] = $this->handle_file_upload(
320								$upload['tmp_name'][$index], isset($_SERVER['HTTP_X_FILE_NAME']) ?
321												$_SERVER['HTTP_X_FILE_NAME'] : $upload['name'][$index], isset($_SERVER['HTTP_X_FILE_SIZE']) ?
322												$_SERVER['HTTP_X_FILE_SIZE'] : $upload['size'][$index], isset($_SERVER['HTTP_X_FILE_TYPE']) ?
323												$_SERVER['HTTP_X_FILE_TYPE'] : $upload['type'][$index], $upload['error'][$index]
324				);
325			}
326		} elseif ($upload) {
327			$info[] = $this->handle_file_upload(
328							$upload['tmp_name'], isset($_SERVER['HTTP_X_FILE_NAME']) ?
329											$_SERVER['HTTP_X_FILE_NAME'] : $upload['name'], isset($_SERVER['HTTP_X_FILE_SIZE']) ?
330											$_SERVER['HTTP_X_FILE_SIZE'] : $upload['size'], isset($_SERVER['HTTP_X_FILE_TYPE']) ?
331											$_SERVER['HTTP_X_FILE_TYPE'] : $upload['type'], $upload['error']
332			);
333		}
334		header('Vary: Accept');
335		if (isset($_SERVER['HTTP_ACCEPT']) && (strpos($_SERVER['HTTP_ACCEPT'], 'application/json') !== false)) {
336			header('Content-type: application/json');
337		} else {
338			header('Content-type: text/plain');
339		}
340		echo json_encode($info);
341	}
342
343}
344
345$upload_handler = new UploadHandler($options);
346
347header('Pragma: no-cache');
348header('Cache-Control: private, no-cache');
349header('Content-Disposition: inline; filename="files.json"');
350header('X-Content-Type-Options: nosniff');
351
352switch ($_SERVER['REQUEST_METHOD']) {
353	case 'POST':
354		$upload_handler->post();
355		break;
356	case 'OPTIONS':
357		break;
358	default:
359		header('HTTP/1.0 405 Method Not Allowed');
360}
361?>