Subversion-Projekte lars-tiefland.ci

Revision

Revision 2128 | Revision 2131 | Zur aktuellen Revision | Details | Vergleich mit vorheriger | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
2121 lars 1
<?php
2
 
3
/*
4
* jQuery File Upload Plugin PHP Class
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
* https://opensource.org/licenses/MIT
12
*/
13
 
2130 lars 14
if (preg_match("/\.local$/", $_SERVER["SERVER_NAME"])) {
2121 lars 15
	//$GLOBALS["site"] .= ".local";
16
}
17
$options = null;
18
 
19
$real_url = getDokDomain();
20
$real_url .= "/images/upload/";
2124 lars 21
$real_folder = $GLOBALS["webs"]["verzeichnis"] . "/images/upload/";
2121 lars 22
 
23
$folder = "";
24
$GLOBALS["folder"] = "";
2130 lars 25
if (isset($_POST["folder"]) && $_POST["folder"]) {
2121 lars 26
	$folder = Weban_Utils::clean_global_input("folder");
2130 lars 27
} elseif (isset($_GET["folder"]) && $_GET["folder"]) {
2121 lars 28
	$folder = Weban_Utils::clean_global_input("folder", "get");
29
}
30
 
31
$bvKonf = "";
2130 lars 32
if (isset($GLOBALS["web_rechte"]["admin"]["toolbox"]["bildverwaltung"])) {
2121 lars 33
	$bvKonf = $GLOBALS["web_rechte"]["admin"]["toolbox"]["bildverwaltung"];
34
}
2130 lars 35
if (!$bvKonf) {
2121 lars 36
	$bvKonf = "Bild;;651;651";
37
}
38
$GLOBALS["Imagedaten"] = array_chunk(explode(";", $bvKonf), 4);
2130 lars 39
if ($folder) {
2121 lars 40
	$folder = rtrim($folder, "/");
41
	$GLOBALS["folder"] = $folder;
42
	$folder .= "/";
43
	$real_folder .= $folder;
44
	$real_url .= $folder;
45
	$options["upload_dir"] = $real_folder;
46
	$options["upload_url"] = $real_url;
2130 lars 47
	foreach ($GLOBALS["Imagedaten"] as $set) {
2121 lars 48
		$options["image_versions"][$set[0]] = array(
49
			"upload_dir" => $real_folder . $set[1] . "/",
50
			"upload_url" => $real_url . $set[1] . "/",
51
			"max_width" => $set[2],
52
			"max_height" => $set[3],
53
			);
54
	}
2130 lars 55
	if (!file_exists($options["upload_dir"] . "/orig/")) {
2121 lars 56
		mkdir($options["upload_dir"] . "/orig/", 0755, true);
57
	}
58
}
59
 
60
class UploadHandler
61
{
62
 
63
	protected $options;
64
 
65
	// PHP File Upload error message codes:
66
	// http://php.net/manual/en/features.file-upload.errors.php
67
	protected $error_messages = array(
68
		1 => 'The uploaded file exceeds the upload_max_filesize directive in php.ini',
69
		2 => 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form',
70
		3 => 'The uploaded file was only partially uploaded',
71
		4 => 'No file was uploaded',
72
		6 => 'Missing a temporary folder',
73
		7 => 'Failed to write file to disk',
74
		8 => 'A PHP extension stopped the file upload',
75
		'post_max_size' => 'The uploaded file exceeds the post_max_size directive in php.ini',
76
		'max_file_size' => 'File is too big',
77
		'min_file_size' => 'File is too small',
78
		'accept_file_types' => 'Filetype not allowed',
79
		'max_number_of_files' => 'Maximum number of files exceeded',
80
		'max_width' => 'Image exceeds maximum width',
81
		'min_width' => 'Image requires a minimum width',
82
		'max_height' => 'Image exceeds maximum height',
83
		'min_height' => 'Image requires a minimum height',
84
		'abort' => 'File upload aborted',
85
		'image_resize' => 'Failed to resize image');
86
 
87
	protected $image_objects = array();
88
 
89
	public function __construct($options = null, $initialize = true, $error_messages = null)
90
	{
2128 lars 91
		$real_url = getDokDomain();
92
		$real_url .= "/images/upload/";
93
		$real_folder = $GLOBALS["webs"]["verzeichnis"] . '/images/upload/';
2121 lars 94
		$this->response = array();
95
		$this->options = array(
96
			'script_url' => $this->get_full_url() . '/' . $this->basename($this->
97
				get_server_var('SCRIPT_NAME')),
2128 lars 98
			'upload_dir' => $real_folder . "orig/",
99
			'upload_url' => $real_url . "orig/",
2121 lars 100
			'input_stream' => 'php://input',
101
			'user_dirs' => false,
102
			'mkdir_mode' => 0755,
103
			'param_name' => 'files',
104
			// Set the following option to 'POST', if your server does not support
105
			// DELETE requests. This is a parameter sent to the client:
106
			'delete_type' => 'DELETE',
107
			'access_control_allow_origin' => '*',
108
			'access_control_allow_credentials' => false,
109
			'access_control_allow_methods' => array(
110
				'OPTIONS',
111
				'HEAD',
112
				'GET',
113
				'POST',
114
				'PUT',
115
				'PATCH',
2130 lars 116
				'DELETE',
117
				),
2121 lars 118
			'access_control_allow_headers' => array(
119
				'Content-Type',
120
				'Content-Range',
2130 lars 121
				'Content-Disposition',
122
				),
2121 lars 123
			// By default, allow redirects to the referer protocol+host:
124
			'redirect_allow_target' => '/^' . preg_quote(parse_url($this->get_server_var('HTTP_REFERER'),
125
				PHP_URL_SCHEME) . '://' . parse_url($this->get_server_var('HTTP_REFERER'),
126
				PHP_URL_HOST) . '/', // Trailing slash to not match subdomains by mistake
127
				'/' // preg_quote delimiter param
128
				) . '/',
129
			// Enable to provide file downloads via GET requests to the PHP script:
130
			//     1. Set to 1 to download files via readfile method through PHP
131
			//     2. Set to 2 to send a X-Sendfile header for lighttpd/Apache
132
			//     3. Set to 3 to send a X-Accel-Redirect header for nginx
133
			// If set to 2 or 3, adjust the upload_url option to the base path of
134
			// the redirect parameter, e.g. '/files/'.
135
			'download_via_php' => false,
136
			// Read files in chunks to avoid memory limits when download_via_php
137
			// is enabled, set to 0 to disable chunked reading of files:
138
			'readfile_chunk_size' => 10 * 1024 * 1024, // 10 MiB
139
			// Defines which files can be displayed inline when downloaded:
2130 lars 140
			'inline_file_types' => '/\.(gif|jpe?g|png|svg)$/i',
2121 lars 141
			// Defines which files (based on their names) are accepted for upload:
142
			'accept_file_types' => '/.+$/i',
143
			// The php.ini settings upload_max_filesize and post_max_size
144
			// take precedence over the following max_file_size setting:
145
			'max_file_size' => null,
146
			'min_file_size' => 1,
147
			// The maximum number of files for the upload directory:
148
			'max_number_of_files' => null,
149
			// Defines which files are handled as image files:
150
			'image_file_types' => '/\.(gif|jpe?g|png)$/i',
151
			// Use exif_imagetype on all files to correct file extensions:
152
			'correct_image_extensions' => false,
153
			// Image resolution restrictions:
154
			'max_width' => null,
155
			'max_height' => null,
156
			'min_width' => 1,
157
			'min_height' => 1,
158
			// Set the following option to false to enable resumable uploads:
159
			'discard_aborted_uploads' => true,
160
			// Set to 0 to use the GD library to scale and orient images,
161
			// set to 1 to use imagick (if installed, falls back to GD),
162
			// set to 2 to use the ImageMagick convert binary directly:
163
			'image_library' => 1,
164
			// Uncomment the following to define an array of resource limits
165
			// for imagick:
166
			/*
167
			'imagick_resource_limits' => array(
168
			imagick::RESOURCETYPE_MAP => 32,
169
			imagick::RESOURCETYPE_MEMORY => 32
170
			),
171
			*/
172
			// Command or path for to the ImageMagick convert binary:
173
			'convert_bin' => 'convert',
174
			// Uncomment the following to add parameters in front of each
175
			// ImageMagick convert call (the limit constraints seem only
176
			// to have an effect if put in front):
177
			/*
178
			'convert_params' => '-limit memory 32MiB -limit map 32MiB',
179
			*/
180
			// Command or path for to the ImageMagick identify binary:
181
			'identify_bin' => 'identify',
182
			'print_response' => true);
2130 lars 183
		foreach ($GLOBALS["Imagedaten"] as $set) {
2121 lars 184
			$this->options["image_versions"][$set[0]] = array(
185
				"upload_dir" => $real_folder . $set[1] . "/",
186
				"upload_url" => $real_url . $set[1] . "/",
187
				"max_width" => $set[2],
188
				"max_height" => $set[3],
189
				);
190
		}
2130 lars 191
		if ($options) {
2121 lars 192
			$this->options = $options + $this->options;
193
		}
2130 lars 194
		if ($error_messages) {
2121 lars 195
			$this->error_messages = $error_messages + $this->error_messages;
196
		}
2130 lars 197
		if ($initialize) {
2121 lars 198
			$this->initialize();
199
		}
200
	}
201
 
202
	protected function initialize()
203
	{
2130 lars 204
		switch ($this->get_server_var('REQUEST_METHOD')) {
2121 lars 205
			case 'OPTIONS':
206
			case 'HEAD':
207
				$this->head();
208
				break;
209
			case 'GET':
210
				$this->get($this->options['print_response']);
211
				break;
212
			case 'PATCH':
213
			case 'PUT':
214
			case 'POST':
215
				$this->post($this->options['print_response']);
216
				break;
217
			case 'DELETE':
218
				$this->delete($this->options['print_response']);
219
				break;
220
			default:
221
				$this->header('HTTP/1.1 405 Method Not Allowed');
222
		}
223
	}
224
 
225
	protected function get_full_url()
226
	{
227
		$https = !empty($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'], 'on') === 0 ||
228
			!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && strcasecmp($_SERVER['HTTP_X_FORWARDED_PROTO'],
229
			'https') === 0;
230
		return ($https ? 'https://' : 'http://') . (!empty($_SERVER['REMOTE_USER']) ? $_SERVER['REMOTE_USER'] .
231
			'@' : '') . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : ($_SERVER['SERVER_NAME'] .
232
			($https && $_SERVER['SERVER_PORT'] === 443 || $_SERVER['SERVER_PORT'] === 80 ?
233
			'' : ':' . $_SERVER['SERVER_PORT']))) . substr($_SERVER['SCRIPT_NAME'], 0,
234
			strrpos($_SERVER['SCRIPT_NAME'], '/'));
235
	}
236
 
237
	protected function get_user_id()
238
	{
239
		@session_start();
240
		return session_id();
241
	}
242
 
243
	protected function get_user_path()
244
	{
2130 lars 245
		if ($this->options['user_dirs']) {
2121 lars 246
			return $this->get_user_id() . '/';
247
		}
248
		return '';
249
	}
250
 
251
	protected function get_upload_path($file_name = null, $version = null)
252
	{
253
		$file_name = $file_name ? $file_name : '';
2130 lars 254
		if (empty($version)) {
2121 lars 255
			$version_path = '';
2130 lars 256
		} else {
2121 lars 257
			$version_dir = @$this->options['image_versions'][$version]['upload_dir'];
2130 lars 258
			if ($version_dir) {
2121 lars 259
				return $version_dir . $this->get_user_path() . $file_name;
260
			}
261
			$version_path = $version . '/';
262
		}
263
		return $this->options['upload_dir'] . $this->get_user_path() . $version_path . $file_name;
264
	}
265
 
266
	protected function get_query_separator($url)
267
	{
268
		return strpos($url, '?') === false ? '?' : '&';
269
	}
270
 
271
	protected function get_download_url($file_name, $version = null, $direct = false)
272
	{
2130 lars 273
		if (!$direct && $this->options['download_via_php']) {
2121 lars 274
			$url = $this->options['script_url'] . $this->get_query_separator($this->options['script_url']) .
275
				$this->get_singular_param_name() . '=' . rawurlencode($file_name);
2130 lars 276
			if ($version) {
2121 lars 277
				$url .= '&version=' . rawurlencode($version);
278
			}
279
			return $url . '&download=1';
280
		}
2130 lars 281
		if (empty($version)) {
2121 lars 282
			$version_path = '';
2130 lars 283
		} else {
2121 lars 284
			$version_url = @$this->options['image_versions'][$version]['upload_url'];
2130 lars 285
			if ($version_url) {
2121 lars 286
				return $version_url . $this->get_user_path() . rawurlencode($file_name);
287
			}
288
			$version_path = rawurlencode($version) . '/';
289
		}
290
		return $this->options['upload_url'] . $this->get_user_path() . $version_path .
291
			rawurlencode($file_name);
292
	}
293
 
294
	protected function set_additional_file_properties($file)
295
	{
296
		$file->deleteUrl = $this->options['script_url'] . $this->get_query_separator($this->
297
			options['script_url']) . $this->get_singular_param_name() . '=' . rawurlencode($file->
298
			name);
299
		$file->deleteType = $this->options['delete_type'];
2130 lars 300
		if ($file->deleteType !== 'DELETE') {
2121 lars 301
			$file->deleteUrl .= '&_method=DELETE';
302
		}
2130 lars 303
        trigger_error($file->deleteUrl);
304
		if ($this->options['access_control_allow_credentials']) {
2121 lars 305
			$file->deleteWithCredentials = true;
306
		}
307
	}
308
 
309
	// Fix for overflowing signed 32 bit integers,
310
	// works for sizes up to 2^32-1 bytes (4 GiB - 1):
311
	protected function fix_integer_overflow($size)
312
	{
2130 lars 313
		if ($size < 0) {
2121 lars 314
			$size += 2.0 * (PHP_INT_MAX + 1);
315
		}
316
		return $size;
317
	}
318
 
319
	protected function get_file_size($file_path, $clear_stat_cache = false)
320
	{
2130 lars 321
		if ($clear_stat_cache) {
322
			if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
2121 lars 323
				clearstatcache(true, $file_path);
2130 lars 324
			} else {
2121 lars 325
				clearstatcache();
326
			}
327
		}
328
		return $this->fix_integer_overflow(filesize($file_path));
329
	}
330
 
331
	protected function is_valid_file_object($file_name)
332
	{
333
		$file_path = $this->get_upload_path($file_name);
2130 lars 334
		if (is_file($file_path) && $file_name[0] !== '.') {
2121 lars 335
			return true;
336
		}
337
		return false;
338
	}
339
 
340
	protected function get_file_object($file_name)
341
	{
2130 lars 342
		if ($this->is_valid_file_object($file_name)) {
2121 lars 343
			$file = new \stdClass();
344
			$file->name = $file_name;
345
			$file->size = $this->get_file_size($this->get_upload_path($file_name));
346
			$file->url = $this->get_download_url($file->name);
2130 lars 347
			foreach ($this->options['image_versions'] as $version => $options) {
348
				if (!empty($version)) {
349
					if (is_file($this->get_upload_path($file_name, $version))) {
2121 lars 350
						$file->{$version . 'Url'} = $this->get_download_url($file->name, $version);
351
					}
352
				}
353
			}
354
			$this->set_additional_file_properties($file);
355
			return $file;
356
		}
357
		return null;
358
	}
359
 
360
	protected function get_file_objects($iteration_method = 'get_file_object')
361
	{
362
		$upload_dir = $this->get_upload_path();
2130 lars 363
		if (!is_dir($upload_dir)) {
2121 lars 364
			return array();
365
		}
366
		return array_values(array_filter(array_map(array($this, $iteration_method),
367
			scandir($upload_dir))));
368
	}
369
 
370
	protected function count_file_objects()
371
	{
372
		return count($this->get_file_objects('is_valid_file_object'));
373
	}
374
 
375
	protected function get_error_message($error)
376
	{
377
		return isset($this->error_messages[$error]) ? $this->error_messages[$error] : $error;
378
	}
379
 
380
	public function get_config_bytes($val)
381
	{
382
		$val = trim($val);
383
		$last = strtolower($val[strlen($val) - 1]);
384
		$val = (int)$val;
2130 lars 385
		switch ($last) {
2121 lars 386
			case 'g':
387
				$val *= 1024;
388
			case 'm':
389
				$val *= 1024;
390
			case 'k':
391
				$val *= 1024;
392
		}
393
		return $this->fix_integer_overflow($val);
394
	}
395
 
396
	protected function validate($uploaded_file, $file, $error, $index)
397
	{
2130 lars 398
		if ($error) {
2121 lars 399
			$file->error = $this->get_error_message($error);
400
			return false;
401
		}
402
		$content_length = $this->fix_integer_overflow((int)$this->get_server_var('CONTENT_LENGTH'));
403
		$post_max_size = $this->get_config_bytes(ini_get('post_max_size'));
2130 lars 404
		if ($post_max_size && ($content_length > $post_max_size)) {
2121 lars 405
			$file->error = $this->get_error_message('post_max_size');
406
			return false;
407
		}
2130 lars 408
		if (!preg_match($this->options['accept_file_types'], $file->name)) {
2121 lars 409
			$file->error = $this->get_error_message('accept_file_types');
410
			return false;
411
		}
2130 lars 412
		if ($uploaded_file && is_uploaded_file($uploaded_file)) {
2121 lars 413
			$file_size = $this->get_file_size($uploaded_file);
2130 lars 414
		} else {
2121 lars 415
			$file_size = $content_length;
416
		}
417
		if ($this->options['max_file_size'] && ($file_size > $this->options['max_file_size'] ||
2130 lars 418
			$file->size > $this->options['max_file_size'])) {
2121 lars 419
			$file->error = $this->get_error_message('max_file_size');
420
			return false;
421
		}
2130 lars 422
		if ($this->options['min_file_size'] && $file_size < $this->options['min_file_size']) {
2121 lars 423
			$file->error = $this->get_error_message('min_file_size');
424
			return false;
425
		}
426
		if (is_int($this->options['max_number_of_files']) && ($this->count_file_objects
427
			() >= $this->options['max_number_of_files']) &&
428
			// Ignore additional chunks of existing files:
2130 lars 429
			!is_file($this->get_upload_path($file->name))) {
2121 lars 430
			$file->error = $this->get_error_message('max_number_of_files');
431
			return false;
432
		}
433
		$max_width = @$this->options['max_width'];
434
		$max_height = @$this->options['max_height'];
435
		$min_width = @$this->options['min_width'];
436
		$min_height = @$this->options['min_height'];
437
		if (($max_width || $max_height || $min_width || $min_height) && preg_match($this->
2130 lars 438
			options['image_file_types'], $file->name)) {
2121 lars 439
			list($img_width, $img_height) = $this->get_image_size($uploaded_file);
440
 
441
			// If we are auto rotating the image by default, do the checks on
442
			// the correct orientation
443
			if (@$this->options['image_versions']['']['auto_orient'] && function_exists('exif_read_data') &&
2130 lars 444
				($exif = @exif_read_data($uploaded_file)) && (((int)@$exif['Orientation']) >= 5)) {
2121 lars 445
				$tmp = $img_width;
446
				$img_width = $img_height;
447
				$img_height = $tmp;
448
				unset($tmp);
449
			}
450
 
451
		}
2130 lars 452
		if (!empty($img_width)) {
453
			if ($max_width && $img_width > $max_width) {
2121 lars 454
				$file->error = $this->get_error_message('max_width');
455
				return false;
456
			}
2130 lars 457
			if ($max_height && $img_height > $max_height) {
2121 lars 458
				$file->error = $this->get_error_message('max_height');
459
				return false;
460
			}
2130 lars 461
			if ($min_width && $img_width < $min_width) {
2121 lars 462
				$file->error = $this->get_error_message('min_width');
463
				return false;
464
			}
2130 lars 465
			if ($min_height && $img_height < $min_height) {
2121 lars 466
				$file->error = $this->get_error_message('min_height');
467
				return false;
468
			}
469
		}
470
		return true;
471
	}
472
 
473
	protected function upcount_name_callback($matches)
474
	{
475
		$index = isset($matches[1]) ? ((int)$matches[1]) + 1 : 1;
476
		$ext = isset($matches[2]) ? $matches[2] : '';
477
		return ' (' . $index . ')' . $ext;
478
	}
479
 
480
	protected function upcount_name($name)
481
	{
482
		return preg_replace_callback('/(?:(?: \(([\d]+)\))?(\.[^.]+))?$/', array($this,
483
				'upcount_name_callback'), $name, 1);
484
	}
485
 
486
	protected function get_unique_filename($file_path, $name, $size, $type, $error,
487
		$index, $content_range)
488
	{
2130 lars 489
		while (is_dir($this->get_upload_path($name))) {
2121 lars 490
			$name = $this->upcount_name($name);
491
		}
492
		// Keep an existing filename if this is part of a chunked upload:
493
		$uploaded_bytes = $this->fix_integer_overflow((int)$content_range[1]);
2130 lars 494
		while (is_file($this->get_upload_path($name))) {
495
			if ($uploaded_bytes === $this->get_file_size($this->get_upload_path($name))) {
2121 lars 496
				break;
497
			}
498
			$name = $this->upcount_name($name);
499
		}
500
		return $name;
501
	}
502
 
503
	protected function fix_file_extension($file_path, $name, $size, $type, $error, $index,
504
		$content_range)
505
	{
506
		// Add missing file extension for known image types:
507
		if (strpos($name, '.') === false && preg_match('/^image\/(gif|jpe?g|png)/', $type,
2130 lars 508
			$matches)) {
2121 lars 509
			$name .= '.' . $matches[1];
510
		}
2130 lars 511
		if ($this->options['correct_image_extensions'] && function_exists('exif_imagetype')) {
512
			switch (@exif_imagetype($file_path)) {
2121 lars 513
				case IMAGETYPE_JPEG:
514
					$extensions = array('jpg', 'jpeg');
515
					break;
516
				case IMAGETYPE_PNG:
517
					$extensions = array('png');
518
					break;
519
				case IMAGETYPE_GIF:
520
					$extensions = array('gif');
521
					break;
522
			}
523
			// Adjust incorrect image file extensions:
2130 lars 524
			if (!empty($extensions)) {
2121 lars 525
				$parts = explode('.', $name);
526
				$extIndex = count($parts) - 1;
527
				$ext = strtolower(@$parts[$extIndex]);
2130 lars 528
				if (!in_array($ext, $extensions)) {
2121 lars 529
					$parts[$extIndex] = $extensions[0];
530
					$name = implode('.', $parts);
531
				}
532
			}
533
		}
534
		return $name;
535
	}
536
 
537
	protected function trim_file_name($file_path, $name, $size, $type, $error, $index,
538
		$content_range)
539
	{
540
		// Remove path information and dots around the filename, to prevent uploading
541
		// into different directories or replacing hidden system files.
542
		// Also remove control characters and spaces (\x00..\x20) around the filename:
543
		$name = trim($this->basename(stripslashes($name)), ".\x00..\x20");
544
		// Use a timestamp for empty filenames:
2130 lars 545
		if (!$name) {
2121 lars 546
			$name = str_replace('.', '-', microtime(true));
547
		}
548
		return $name;
549
	}
550
 
551
	protected function get_file_name($file_path, $name, $size, $type, $error, $index,
552
		$content_range)
553
	{
554
		$name = $this->trim_file_name($file_path, $name, $size, $type, $error, $index, $content_range);
555
		return $this->get_unique_filename($file_path, $this->fix_file_extension($file_path,
556
			$name, $size, $type, $error, $index, $content_range), $size, $type, $error, $index,
557
			$content_range);
558
	}
559
 
560
	protected function get_scaled_image_file_paths($file_name, $version)
561
	{
562
		$file_path = $this->get_upload_path($file_name);
2130 lars 563
		if (!empty($version)) {
2121 lars 564
			$version_dir = $this->get_upload_path(null, $version);
2130 lars 565
			if (!is_dir($version_dir)) {
2121 lars 566
				mkdir($version_dir, $this->options['mkdir_mode'], true);
567
			}
568
			$new_file_path = $version_dir . '/' . $file_name;
2130 lars 569
		} else {
2121 lars 570
			$new_file_path = $file_path;
571
		}
572
		return array($file_path, $new_file_path);
573
	}
574
 
575
	protected function gd_get_image_object($file_path, $func, $no_cache = false)
576
	{
2130 lars 577
		if (empty($this->image_objects[$file_path]) || $no_cache) {
2121 lars 578
			$this->gd_destroy_image_object($file_path);
579
			$this->image_objects[$file_path] = $func($file_path);
580
		}
581
		return $this->image_objects[$file_path];
582
	}
583
 
584
	protected function gd_set_image_object($file_path, $image)
585
	{
586
		$this->gd_destroy_image_object($file_path);
587
		$this->image_objects[$file_path] = $image;
588
	}
589
 
590
	protected function gd_destroy_image_object($file_path)
591
	{
592
		$image = (isset($this->image_objects[$file_path])) ? $this->image_objects[$file_path] : null;
593
		return $image && imagedestroy($image);
594
	}
595
 
596
	protected function gd_imageflip($image, $mode)
597
	{
2130 lars 598
		if (function_exists('imageflip')) {
2121 lars 599
			return imageflip($image, $mode);
600
		}
601
		$new_width = $src_width = imagesx($image);
602
		$new_height = $src_height = imagesy($image);
603
		$new_img = imagecreatetruecolor($new_width, $new_height);
604
		$src_x = 0;
605
		$src_y = 0;
2130 lars 606
		switch ($mode) {
2121 lars 607
			case '1': // flip on the horizontal axis
608
				$src_y = $new_height - 1;
609
				$src_height = -$new_height;
610
				break;
611
			case '2': // flip on the vertical axis
612
				$src_x = $new_width - 1;
613
				$src_width = -$new_width;
614
				break;
615
			case '3': // flip on both axes
616
				$src_y = $new_height - 1;
617
				$src_height = -$new_height;
618
				$src_x = $new_width - 1;
619
				$src_width = -$new_width;
620
				break;
621
			default:
622
				return $image;
623
		}
624
		imagecopyresampled($new_img, $image, 0, 0, $src_x, $src_y, $new_width, $new_height,
625
			$src_width, $src_height);
626
		return $new_img;
627
	}
628
 
629
	protected function gd_orient_image($file_path, $src_img)
630
	{
2130 lars 631
		if (!function_exists('exif_read_data')) {
2121 lars 632
			return false;
633
		}
634
		$exif = @exif_read_data($file_path);
2130 lars 635
		if ($exif === false) {
2121 lars 636
			return false;
637
		}
638
		$orientation = (int)@$exif['Orientation'];
2130 lars 639
		if ($orientation < 2 || $orientation > 8) {
2121 lars 640
			return false;
641
		}
2130 lars 642
		switch ($orientation) {
2121 lars 643
			case 2:
644
				$new_img = $this->gd_imageflip($src_img, defined('IMG_FLIP_VERTICAL') ?
645
					IMG_FLIP_VERTICAL : 2);
646
				break;
647
			case 3:
648
				$new_img = imagerotate($src_img, 180, 0);
649
				break;
650
			case 4:
651
				$new_img = $this->gd_imageflip($src_img, defined('IMG_FLIP_HORIZONTAL') ?
652
					IMG_FLIP_HORIZONTAL : 1);
653
				break;
654
			case 5:
655
				$tmp_img = $this->gd_imageflip($src_img, defined('IMG_FLIP_HORIZONTAL') ?
656
					IMG_FLIP_HORIZONTAL : 1);
657
				$new_img = imagerotate($tmp_img, 270, 0);
658
				imagedestroy($tmp_img);
659
				break;
660
			case 6:
661
				$new_img = imagerotate($src_img, 270, 0);
662
				break;
663
			case 7:
664
				$tmp_img = $this->gd_imageflip($src_img, defined('IMG_FLIP_VERTICAL') ?
665
					IMG_FLIP_VERTICAL : 2);
666
				$new_img = imagerotate($tmp_img, 270, 0);
667
				imagedestroy($tmp_img);
668
				break;
669
			case 8:
670
				$new_img = imagerotate($src_img, 90, 0);
671
				break;
672
			default:
673
				return false;
674
		}
675
		$this->gd_set_image_object($file_path, $new_img);
676
		return true;
677
	}
678
 
679
	protected function gd_create_scaled_image($file_name, $version, $options)
680
	{
2130 lars 681
		if (!function_exists('imagecreatetruecolor')) {
2121 lars 682
			error_log('Function not found: imagecreatetruecolor');
683
			return false;
684
		}
685
		list($file_path, $new_file_path) = $this->get_scaled_image_file_paths($file_name,
686
			$version);
687
		$type = strtolower(substr(strrchr($file_name, '.'), 1));
2130 lars 688
		switch ($type) {
2121 lars 689
			case 'jpg':
690
			case 'jpeg':
691
				$src_func = 'imagecreatefromjpeg';
692
				$write_func = 'imagejpeg';
693
				$image_quality = isset($options['jpeg_quality']) ? $options['jpeg_quality'] : 75;
694
				break;
695
			case 'gif':
696
				$src_func = 'imagecreatefromgif';
697
				$write_func = 'imagegif';
698
				$image_quality = null;
699
				break;
700
			case 'png':
701
				$src_func = 'imagecreatefrompng';
702
				$write_func = 'imagepng';
703
				$image_quality = isset($options['png_quality']) ? $options['png_quality'] : 9;
704
				break;
705
			default:
706
				return false;
707
		}
708
		$src_img = $this->gd_get_image_object($file_path, $src_func, !empty($options['no_cache']));
709
		$image_oriented = false;
2130 lars 710
		if (!empty($options['auto_orient']) && $this->gd_orient_image($file_path, $src_img)) {
2121 lars 711
			$image_oriented = true;
712
			$src_img = $this->gd_get_image_object($file_path, $src_func);
713
		}
714
		$max_width = $img_width = imagesx($src_img);
715
		$max_height = $img_height = imagesy($src_img);
2130 lars 716
		if (!empty($options['max_width'])) {
2121 lars 717
			$max_width = $options['max_width'];
718
		}
2130 lars 719
		if (!empty($options['max_height'])) {
2121 lars 720
			$max_height = $options['max_height'];
721
		}
722
		$scale = min($max_width / $img_width, $max_height / $img_height);
2130 lars 723
		if ($scale >= 1) {
724
			if ($image_oriented) {
2121 lars 725
				return $write_func($src_img, $new_file_path, $image_quality);
726
			}
2130 lars 727
			if ($file_path !== $new_file_path) {
2121 lars 728
				return copy($file_path, $new_file_path);
729
			}
730
			return true;
731
		}
2130 lars 732
		if (empty($options['crop'])) {
2121 lars 733
			$new_width = $img_width * $scale;
734
			$new_height = $img_height * $scale;
735
			$dst_x = 0;
736
			$dst_y = 0;
737
			$new_img = imagecreatetruecolor($new_width, $new_height);
2130 lars 738
		} else {
739
			if (($img_width / $img_height) >= ($max_width / $max_height)) {
2121 lars 740
				$new_width = $img_width / ($img_height / $max_height);
741
				$new_height = $max_height;
2130 lars 742
			} else {
2121 lars 743
				$new_width = $max_width;
744
				$new_height = $img_height / ($img_width / $max_width);
745
			}
746
			$dst_x = 0 - ($new_width - $max_width) / 2;
747
			$dst_y = 0 - ($new_height - $max_height) / 2;
748
			$new_img = imagecreatetruecolor($max_width, $max_height);
749
		}
750
		// Handle transparency in GIF and PNG images:
2130 lars 751
		switch ($type) {
2121 lars 752
			case 'gif':
753
			case 'png':
754
				imagecolortransparent($new_img, imagecolorallocate($new_img, 0, 0, 0));
755
			case 'png':
756
				imagealphablending($new_img, false);
757
				imagesavealpha($new_img, true);
758
				break;
759
		}
760
		$success = imagecopyresampled($new_img, $src_img, $dst_x, $dst_y, 0, 0, $new_width,
761
			$new_height, $img_width, $img_height) && $write_func($new_img, $new_file_path, $image_quality);
762
		$this->gd_set_image_object($file_path, $new_img);
763
		return $success;
764
	}
765
 
766
	protected function imagick_get_image_object($file_path, $no_cache = false)
767
	{
2130 lars 768
		if (empty($this->image_objects[$file_path]) || $no_cache) {
2121 lars 769
			$this->imagick_destroy_image_object($file_path);
770
			$image = new \Imagick();
2130 lars 771
			if (!empty($this->options['imagick_resource_limits'])) {
772
				foreach ($this->options['imagick_resource_limits'] as $type => $limit) {
2121 lars 773
					$image->setResourceLimit($type, $limit);
774
				}
775
			}
776
			$image->readImage($file_path);
777
			$this->image_objects[$file_path] = $image;
778
		}
779
		return $this->image_objects[$file_path];
780
	}
781
 
782
	protected function imagick_set_image_object($file_path, $image)
783
	{
784
		$this->imagick_destroy_image_object($file_path);
785
		$this->image_objects[$file_path] = $image;
786
	}
787
 
788
	protected function imagick_destroy_image_object($file_path)
789
	{
790
		$image = (isset($this->image_objects[$file_path])) ? $this->image_objects[$file_path] : null;
791
		return $image && $image->destroy();
792
	}
793
 
794
	protected function imagick_orient_image($image)
795
	{
796
		$orientation = $image->getImageOrientation();
797
		$background = new \ImagickPixel('none');
2130 lars 798
		switch ($orientation) {
2121 lars 799
			case \imagick::ORIENTATION_TOPRIGHT: // 2
800
				$image->flopImage(); // horizontal flop around y-axis
801
				break;
802
			case \imagick::ORIENTATION_BOTTOMRIGHT: // 3
803
				$image->rotateImage($background, 180);
804
				break;
805
			case \imagick::ORIENTATION_BOTTOMLEFT: // 4
806
				$image->flipImage(); // vertical flip around x-axis
807
				break;
808
			case \imagick::ORIENTATION_LEFTTOP: // 5
809
				$image->flopImage(); // horizontal flop around y-axis
810
				$image->rotateImage($background, 270);
811
				break;
812
			case \imagick::ORIENTATION_RIGHTTOP: // 6
813
				$image->rotateImage($background, 90);
814
				break;
815
			case \imagick::ORIENTATION_RIGHTBOTTOM: // 7
816
				$image->flipImage(); // vertical flip around x-axis
817
				$image->rotateImage($background, 270);
818
				break;
819
			case \imagick::ORIENTATION_LEFTBOTTOM: // 8
820
				$image->rotateImage($background, 270);
821
				break;
822
			default:
823
				return false;
824
		}
825
		$image->setImageOrientation(\imagick::ORIENTATION_TOPLEFT); // 1
826
		return true;
827
	}
828
 
829
	protected function imagick_create_scaled_image($file_name, $version, $options)
830
	{
831
		list($file_path, $new_file_path) = $this->get_scaled_image_file_paths($file_name,
832
			$version);
833
		$image = $this->imagick_get_image_object($file_path, !empty($options['crop']) ||
834
			!empty($options['no_cache']));
2130 lars 835
		if ($image->getImageFormat() === 'GIF') {
2121 lars 836
			// Handle animated GIFs:
837
			$images = $image->coalesceImages();
2130 lars 838
			foreach ($images as $frame) {
2121 lars 839
				$image = $frame;
840
				$this->imagick_set_image_object($file_name, $image);
841
				break;
842
			}
843
		}
844
		$image_oriented = false;
2130 lars 845
		if (!empty($options['auto_orient'])) {
2121 lars 846
			$image_oriented = $this->imagick_orient_image($image);
847
		}
848
		$new_width = $max_width = $img_width = $image->getImageWidth();
849
		$new_height = $max_height = $img_height = $image->getImageHeight();
2130 lars 850
		if (!empty($options['max_width'])) {
2121 lars 851
			$new_width = $max_width = $options['max_width'];
852
		}
2130 lars 853
		if (!empty($options['max_height'])) {
2121 lars 854
			$new_height = $max_height = $options['max_height'];
855
		}
856
		$image_strip = false;
2130 lars 857
		if (!empty($options["strip"])) {
2121 lars 858
			$image_strip = $options["strip"];
859
		}
860
		if (!$image_oriented && ($max_width >= $img_width) && ($max_height >= $img_height) &&
2130 lars 861
			!$image_strip && empty($options["jpeg_quality"])) {
862
			if ($file_path !== $new_file_path) {
2121 lars 863
				return copy($file_path, $new_file_path);
864
			}
865
			return true;
866
		}
867
		$crop = !empty($options['crop']);
2130 lars 868
		if ($crop) {
2121 lars 869
			$x = 0;
870
			$y = 0;
2130 lars 871
			if (($img_width / $img_height) >= ($max_width / $max_height)) {
2121 lars 872
				$new_width = 0; // Enables proportional scaling based on max_height
873
				$x = ($img_width / ($img_height / $max_height) - $max_width) / 2;
2130 lars 874
			} else {
2121 lars 875
				$new_height = 0; // Enables proportional scaling based on max_width
876
				$y = ($img_height / ($img_width / $max_width) - $max_height) / 2;
877
			}
878
		}
879
		$success = $image->resizeImage($new_width, $new_height, isset($options['filter']) ?
880
			$options['filter'] : \imagick::FILTER_LANCZOS, isset($options['blur']) ? $options['blur'] :
881
			1, $new_width && $new_height // fit image into constraints if not to be cropped
882
			);
2130 lars 883
		if ($success && $crop) {
2121 lars 884
			$success = $image->cropImage($max_width, $max_height, $x, $y);
2130 lars 885
			if ($success) {
2121 lars 886
				$success = $image->setImagePage($max_width, $max_height, 0, 0);
887
			}
888
		}
889
		$type = strtolower(substr(strrchr($file_name, '.'), 1));
2130 lars 890
		switch ($type) {
2121 lars 891
			case 'jpg':
892
			case 'jpeg':
2130 lars 893
				if (!empty($options['jpeg_quality'])) {
2121 lars 894
					$image->setImageCompression(\imagick::COMPRESSION_JPEG);
895
					$image->setImageCompressionQuality($options['jpeg_quality']);
896
				}
897
				break;
898
		}
2130 lars 899
		if ($image_strip) {
2121 lars 900
			$image->stripImage();
901
		}
902
		return $success && $image->writeImage($new_file_path);
903
	}
904
 
905
	protected function imagemagick_create_scaled_image($file_name, $version, $options)
906
	{
907
		list($file_path, $new_file_path) = $this->get_scaled_image_file_paths($file_name,
908
			$version);
909
		$resize = @$options['max_width'] . (empty($options['max_height']) ? '' : 'X' . $options['max_height']);
2130 lars 910
		if (!$resize && empty($options['auto_orient'])) {
911
			if ($file_path !== $new_file_path) {
2121 lars 912
				return copy($file_path, $new_file_path);
913
			}
914
			return true;
915
		}
916
		$cmd = $this->options['convert_bin'];
2130 lars 917
		if (!empty($this->options['convert_params'])) {
2121 lars 918
			$cmd .= ' ' . $this->options['convert_params'];
919
		}
920
		$cmd .= ' ' . escapeshellarg($file_path);
2130 lars 921
		if (!empty($options['auto_orient'])) {
2121 lars 922
			$cmd .= ' -auto-orient';
923
		}
2130 lars 924
		if ($resize) {
2121 lars 925
			// Handle animated GIFs:
926
			$cmd .= ' -coalesce';
2130 lars 927
			if (empty($options['crop'])) {
2121 lars 928
				$cmd .= ' -resize ' . escapeshellarg($resize . '>');
2130 lars 929
			} else {
2121 lars 930
				$cmd .= ' -resize ' . escapeshellarg($resize . '^');
931
				$cmd .= ' -gravity center';
932
				$cmd .= ' -crop ' . escapeshellarg($resize . '+0+0');
933
			}
934
			// Make sure the page dimensions are correct (fixes offsets of animated GIFs):
935
			$cmd .= ' +repage';
936
		}
2130 lars 937
		if (!empty($options['convert_params'])) {
2121 lars 938
			$cmd .= ' ' . $options['convert_params'];
939
		}
940
		$cmd .= ' ' . escapeshellarg($new_file_path);
941
		exec($cmd, $output, $error);
2130 lars 942
		if ($error) {
2121 lars 943
			error_log(implode('\n', $output));
944
			return false;
945
		}
946
		return true;
947
	}
948
 
949
	protected function get_image_size($file_path)
950
	{
2130 lars 951
		if ($this->options['image_library']) {
952
			if (extension_loaded('imagick')) {
2121 lars 953
				$image = new \Imagick();
2130 lars 954
				try {
955
					if (@$image->pingImage($file_path)) {
2121 lars 956
						$dimensions = array($image->getImageWidth(), $image->getImageHeight());
957
						$image->destroy();
958
						return $dimensions;
959
					}
960
					return false;
961
				}
2130 lars 962
				catch (\Exception $e) {
2121 lars 963
					error_log($e->getMessage());
964
				}
965
			}
2130 lars 966
			if ($this->options['image_library'] === 2) {
2121 lars 967
				$cmd = $this->options['identify_bin'];
968
				$cmd .= ' -ping ' . escapeshellarg($file_path);
969
				exec($cmd, $output, $error);
2130 lars 970
				if (!$error && !empty($output)) {
2121 lars 971
					// image.jpg JPEG 1920x1080 1920x1080+0+0 8-bit sRGB 465KB 0.000u 0:00.000
972
					$infos = preg_split('/\s+/', substr($output[0], strlen($file_path)));
973
					$dimensions = preg_split('/x/', $infos[2]);
974
					return $dimensions;
975
				}
976
				return false;
977
			}
978
		}
2130 lars 979
		if (!function_exists('getimagesize')) {
2121 lars 980
			error_log('Function not found: getimagesize');
981
			return false;
982
		}
983
		return @getimagesize($file_path);
984
	}
985
 
986
	protected function create_scaled_image($file_name, $version, $options)
987
	{
2130 lars 988
		if ($this->options['image_library'] === 2) {
2121 lars 989
			return $this->imagemagick_create_scaled_image($file_name, $version, $options);
990
		}
2130 lars 991
		if ($this->options['image_library'] && extension_loaded('imagick')) {
2121 lars 992
			return $this->imagick_create_scaled_image($file_name, $version, $options);
993
		}
994
		return $this->gd_create_scaled_image($file_name, $version, $options);
995
	}
996
 
997
	protected function destroy_image_object($file_path)
998
	{
2130 lars 999
		if ($this->options['image_library'] && extension_loaded('imagick')) {
2121 lars 1000
			return $this->imagick_destroy_image_object($file_path);
1001
		}
1002
	}
1003
 
1004
	protected function is_valid_image_file($file_path)
1005
	{
2130 lars 1006
		if (!preg_match($this->options['image_file_types'], $file_path)) {
2121 lars 1007
			return false;
1008
		}
2130 lars 1009
		if (function_exists('exif_imagetype')) {
2121 lars 1010
			return @exif_imagetype($file_path);
1011
		}
1012
		$image_info = $this->get_image_size($file_path);
1013
		return $image_info && $image_info[0] && $image_info[1];
1014
	}
1015
 
1016
	protected function handle_image_file($file_path, $file)
1017
	{
1018
		$failed_versions = array();
2130 lars 1019
		foreach ($this->options['image_versions'] as $version => $options) {
1020
			if ($this->create_scaled_image($file->name, $version, $options)) {
1021
				if (!empty($version)) {
2121 lars 1022
					$file->{$version . 'Url'} = $this->get_download_url($file->name, $version);
2130 lars 1023
				} else {
2121 lars 1024
					$file->size = $this->get_file_size($file_path, true);
1025
				}
2130 lars 1026
			} else {
2121 lars 1027
				$failed_versions[] = $version ? $version : 'original';
1028
			}
1029
		}
2130 lars 1030
		if (count($failed_versions)) {
2121 lars 1031
			$file->error = $this->get_error_message('image_resize') . ' (' . implode($failed_versions,
1032
				', ') . ')';
1033
		}
1034
		// Free memory:
1035
		$this->destroy_image_object($file_path);
1036
	}
1037
 
1038
	protected function handle_file_upload($uploaded_file, $name, $size, $type, $error,
1039
		$index = null, $content_range = null)
1040
	{
1041
		$file = new \stdClass();
1042
		$file->name = $this->get_file_name($uploaded_file, $name, $size, $type, $error,
1043
			$index, $content_range);
1044
		$file->size = $this->fix_integer_overflow((int)$size);
1045
		$file->type = $type;
2130 lars 1046
		if ($this->validate($uploaded_file, $file, $error, $index)) {
2121 lars 1047
			$this->handle_form_data($file, $index);
1048
			$upload_dir = $this->get_upload_path();
2130 lars 1049
			if (!is_dir($upload_dir)) {
2121 lars 1050
				mkdir($upload_dir, $this->options['mkdir_mode'], true);
1051
			}
1052
			$file_path = $this->get_upload_path($file->name);
1053
			$append_file = $content_range && is_file($file_path) && $file->size > $this->
1054
				get_file_size($file_path);
2130 lars 1055
			if ($uploaded_file && is_uploaded_file($uploaded_file)) {
2121 lars 1056
				// multipart/formdata uploads (POST method uploads)
2130 lars 1057
				if ($append_file) {
2121 lars 1058
					file_put_contents($file_path, fopen($uploaded_file, 'r'), FILE_APPEND);
2130 lars 1059
				} else {
2121 lars 1060
					move_uploaded_file($uploaded_file, $file_path);
1061
				}
2130 lars 1062
			} else {
2121 lars 1063
				// Non-multipart uploads (PUT method support)
1064
				file_put_contents($file_path, fopen($this->options['input_stream'], 'r'), $append_file ?
1065
					FILE_APPEND : 0);
1066
			}
1067
			$file_size = $this->get_file_size($file_path, $append_file);
2130 lars 1068
			$videos = array(
1069
				"wmf",
1070
				"flv",
1071
				"swf",
1072
				);
1073
			$docs = array(
1074
				"pdf",
1075
				"doc",
1076
				"docx",
1077
				"xls",
1078
				"xlsx",
1079
				);
1080
			if ($file_size === $file->size) {
2121 lars 1081
				$file->url = $this->get_download_url($file->name);
2130 lars 1082
				if ($this->is_valid_image_file($file_path)) {
2121 lars 1083
					$this->handle_image_file($file_path, $file);
1084
				}
2130 lars 1085
				$mt = mime_content_type($file_path);
1086
				$info = pathinfo($file_path);
1087
				$ext = strtolower($info["extension"]);
1088
				$typ = 4;
1089
				if (substr($mt, 0, 5) == "image") {
1090
					$typ = 1;
1091
					foreach ($this->options['image_versions'] as $version => $options) {
1092
						if ($this->create_scaled_image($fName, $options)) {
1093
							$file->{$version . '_url'} = $options['upload_url'] . $fName;
1094
						}
1095
					}
1096
				} elseif (in_array($ext, $docs)) {
1097
					$typ = 2;
1098
				} elseif (in_array($ext, $videos)) {
1099
					$typ = 3;
1100
				}
1101
				$f = $GLOBALS["folder"];
1102
				$sql = "INSERT INTO
1103
                        medien
1104
                    SET
1105
                        name='" . $fName . "',
1106
                        folder='" . $f . "',
1107
                        erstellt_am=UNIX_TIMESTAMP(),
1108
                        erstellt_von='" . $_SERVER["PHP_AUTH_USER"] . "',
1109
                        typ=" . $typ . "
1110
                ";
1111
				$this->db->query($sql);
1112
			} else {
2121 lars 1113
				$file->size = $file_size;
2130 lars 1114
				if (!$content_range && $this->options['discard_aborted_uploads']) {
2121 lars 1115
					unlink($file_path);
1116
					$file->error = $this->get_error_message('abort');
1117
				}
1118
			}
1119
			$this->set_additional_file_properties($file);
1120
		}
1121
		return $file;
1122
	}
1123
 
1124
	protected function readfile($file_path)
1125
	{
1126
		$file_size = $this->get_file_size($file_path);
1127
		$chunk_size = $this->options['readfile_chunk_size'];
2130 lars 1128
		if ($chunk_size && $file_size > $chunk_size) {
2121 lars 1129
			$handle = fopen($file_path, 'rb');
2130 lars 1130
			while (!feof($handle)) {
2121 lars 1131
				echo fread($handle, $chunk_size);
1132
				@ob_flush();
1133
				@flush();
1134
			}
1135
			fclose($handle);
1136
			return $file_size;
1137
		}
1138
		return readfile($file_path);
1139
	}
1140
 
1141
	protected function body($str)
1142
	{
1143
		echo $str;
1144
	}
1145
 
1146
	protected function header($str)
1147
	{
1148
		header($str);
1149
	}
1150
 
1151
	protected function get_upload_data($id)
1152
	{
1153
		return @$_FILES[$id];
1154
	}
1155
 
1156
	protected function get_post_param($id)
1157
	{
1158
		return @$_POST[$id];
1159
	}
1160
 
1161
	protected function get_query_param($id)
1162
	{
1163
		return @$_GET[$id];
1164
	}
1165
 
1166
	protected function get_server_var($id)
1167
	{
1168
		return @$_SERVER[$id];
1169
	}
1170
 
1171
	protected function handle_form_data($file, $index)
1172
	{
1173
		// Handle form data, e.g. $_POST['description'][$index]
1174
	}
1175
 
1176
	protected function get_version_param()
1177
	{
1178
		return $this->basename(stripslashes($this->get_query_param('version')));
1179
	}
1180
 
1181
	protected function get_singular_param_name()
1182
	{
1183
		return substr($this->options['param_name'], 0, -1);
1184
	}
1185
 
1186
	protected function get_file_name_param()
1187
	{
1188
		$name = $this->get_singular_param_name();
1189
		return $this->basename(stripslashes($this->get_query_param($name)));
1190
	}
1191
 
1192
	protected function get_file_names_params()
1193
	{
1194
		$params = $this->get_query_param($this->options['param_name']);
2130 lars 1195
		if (!$params) {
2121 lars 1196
			return null;
1197
		}
2130 lars 1198
		foreach ($params as $key => $value) {
2121 lars 1199
			$params[$key] = $this->basename(stripslashes($value));
1200
		}
1201
		return $params;
1202
	}
1203
 
1204
	protected function get_file_type($file_path)
1205
	{
2130 lars 1206
		switch (strtolower(pathinfo($file_path, PATHINFO_EXTENSION))) {
2121 lars 1207
			case 'jpeg':
1208
			case 'jpg':
1209
				return 'image/jpeg';
1210
			case 'png':
1211
				return 'image/png';
1212
			case 'gif':
1213
				return 'image/gif';
2130 lars 1214
			case 'svg':
1215
				return 'image/svg';
2121 lars 1216
			default:
1217
				return '';
1218
		}
1219
	}
1220
 
1221
	protected function download()
1222
	{
2130 lars 1223
		switch ($this->options['download_via_php']) {
2121 lars 1224
			case 1:
1225
				$redirect_header = null;
1226
				break;
1227
			case 2:
1228
				$redirect_header = 'X-Sendfile';
1229
				break;
1230
			case 3:
1231
				$redirect_header = 'X-Accel-Redirect';
1232
				break;
1233
			default:
1234
				return $this->header('HTTP/1.1 403 Forbidden');
1235
		}
1236
		$file_name = $this->get_file_name_param();
2130 lars 1237
		if (!$this->is_valid_file_object($file_name)) {
2121 lars 1238
			return $this->header('HTTP/1.1 404 Not Found');
1239
		}
2130 lars 1240
		if ($redirect_header) {
2121 lars 1241
			return $this->header($redirect_header . ': ' . $this->get_download_url($file_name,
1242
				$this->get_version_param(), true));
1243
		}
1244
		$file_path = $this->get_upload_path($file_name, $this->get_version_param());
1245
		// Prevent browsers from MIME-sniffing the content-type:
1246
		$this->header('X-Content-Type-Options: nosniff');
2130 lars 1247
		if (!preg_match($this->options['inline_file_types'], $file_name)) {
2121 lars 1248
			$this->header('Content-Type: application/octet-stream');
1249
			$this->header('Content-Disposition: attachment; filename="' . $file_name . '"');
2130 lars 1250
		} else {
2121 lars 1251
			$this->header('Content-Type: ' . $this->get_file_type($file_path));
1252
			$this->header('Content-Disposition: inline; filename="' . $file_name . '"');
1253
		}
1254
		$this->header('Content-Length: ' . $this->get_file_size($file_path));
1255
		$this->header('Last-Modified: ' . gmdate('D, d M Y H:i:s T', filemtime($file_path)));
1256
		$this->readfile($file_path);
1257
	}
1258
 
1259
	protected function send_content_type_header()
1260
	{
1261
		$this->header('Vary: Accept');
2130 lars 1262
		if (strpos($this->get_server_var('HTTP_ACCEPT'), 'application/json') !== false) {
2121 lars 1263
			$this->header('Content-type: application/json');
2130 lars 1264
		} else {
2121 lars 1265
			$this->header('Content-type: text/plain');
1266
		}
1267
	}
1268
 
1269
	protected function send_access_control_headers()
1270
	{
1271
		$this->header('Access-Control-Allow-Origin: ' . $this->options['access_control_allow_origin']);
1272
		$this->header('Access-Control-Allow-Credentials: ' . ($this->options['access_control_allow_credentials'] ?
1273
			'true' : 'false'));
1274
		$this->header('Access-Control-Allow-Methods: ' . implode(', ', $this->options['access_control_allow_methods']));
1275
		$this->header('Access-Control-Allow-Headers: ' . implode(', ', $this->options['access_control_allow_headers']));
1276
	}
1277
 
1278
	public function generate_response($content, $print_response = true)
1279
	{
1280
		$this->response = $content;
2130 lars 1281
		if ($print_response) {
2121 lars 1282
			$json = json_encode($content);
1283
			$redirect = stripslashes($this->get_post_param('redirect'));
2130 lars 1284
			if ($redirect && preg_match($this->options['redirect_allow_target'], $redirect)) {
2121 lars 1285
				$this->header('Location: ' . sprintf($redirect, rawurlencode($json)));
1286
				return;
1287
			}
1288
			$this->head();
2130 lars 1289
			if ($this->get_server_var('HTTP_CONTENT_RANGE')) {
2121 lars 1290
				$files = isset($content[$this->options['param_name']]) ? $content[$this->
1291
					options['param_name']] : null;
2130 lars 1292
				if ($files && is_array($files) && is_object($files[0]) && $files[0]->size) {
2121 lars 1293
					$this->header('Range: 0-' . ($this->fix_integer_overflow((int)$files[0]->size) -
1294
						1));
1295
				}
1296
			}
1297
			$this->body($json);
1298
		}
1299
		return $content;
1300
	}
1301
 
1302
	public function get_response()
1303
	{
1304
		return $this->response;
1305
	}
1306
 
1307
	public function head()
1308
	{
1309
		$this->header('Pragma: no-cache');
1310
		$this->header('Cache-Control: no-store, no-cache, must-revalidate');
1311
		$this->header('Content-Disposition: inline; filename="files.json"');
1312
		// Prevent Internet Explorer from MIME-sniffing the content-type:
1313
		$this->header('X-Content-Type-Options: nosniff');
2130 lars 1314
		if ($this->options['access_control_allow_origin']) {
2121 lars 1315
			$this->send_access_control_headers();
1316
		}
1317
		$this->send_content_type_header();
1318
	}
1319
 
1320
	public function get($print_response = true)
1321
	{
2130 lars 1322
		if ($print_response && $this->get_query_param('download')) {
2121 lars 1323
			return $this->download();
1324
		}
1325
		$file_name = $this->get_file_name_param();
2130 lars 1326
		if ($file_name) {
2121 lars 1327
			$response = array($this->get_singular_param_name() => $this->get_file_object($file_name));
2130 lars 1328
		} else {
2121 lars 1329
			$response = array($this->options['param_name'] => $this->get_file_objects());
1330
		}
1331
		return $this->generate_response($response, $print_response);
1332
	}
1333
 
1334
	public function post($print_response = true)
1335
	{
2130 lars 1336
		if ($this->get_query_param('_method') === 'DELETE') {
2121 lars 1337
			return $this->delete($print_response);
1338
		}
1339
		$upload = $this->get_upload_data($this->options['param_name']);
1340
		// Parse the Content-Disposition header, if available:
1341
		$content_disposition_header = $this->get_server_var('HTTP_CONTENT_DISPOSITION');
1342
		$file_name = $content_disposition_header ? rawurldecode(preg_replace('/(^[^"]+")|("$)/',
1343
			'', $content_disposition_header)) : null;
1344
		// Parse the Content-Range header, which has the following form:
1345
		// Content-Range: bytes 0-524287/2000000
1346
		$content_range_header = $this->get_server_var('HTTP_CONTENT_RANGE');
1347
		$content_range = $content_range_header ? preg_split('/[^0-9]+/', $content_range_header) : null;
1348
		$size = $content_range ? $content_range[3] : null;
1349
		$files = array();
2130 lars 1350
		if ($upload) {
1351
			if (is_array($upload['tmp_name'])) {
2121 lars 1352
				// param_name is an array identifier like "files[]",
1353
				// $upload is a multi-dimensional array:
2130 lars 1354
				foreach ($upload['tmp_name'] as $index => $value) {
2121 lars 1355
					$files[] = $this->handle_file_upload($upload['tmp_name'][$index], $file_name ? $file_name :
1356
						$upload['name'][$index], $size ? $size : $upload['size'][$index], $upload['type'][$index],
1357
						$upload['error'][$index], $index, $content_range);
1358
				}
2130 lars 1359
			} else {
2121 lars 1360
				// param_name is a single object identifier like "file",
1361
				// $upload is a one-dimensional array:
1362
				$files[] = $this->handle_file_upload(isset($upload['tmp_name']) ? $upload['tmp_name'] : null,
1363
					$file_name ? $file_name : (isset($upload['name']) ? $upload['name'] : null), $size ?
1364
					$size : (isset($upload['size']) ? $upload['size'] : $this->get_server_var('CONTENT_LENGTH')),
1365
					isset($upload['type']) ? $upload['type'] : $this->get_server_var('CONTENT_TYPE'),
1366
					isset($upload['error']) ? $upload['error'] : null, null, $content_range);
1367
			}
1368
		}
1369
		$response = array($this->options['param_name'] => $files);
1370
		return $this->generate_response($response, $print_response);
1371
	}
1372
 
1373
	public function delete($print_response = true)
1374
	{
1375
		$file_names = $this->get_file_names_params();
2130 lars 1376
		if (empty($file_names)) {
2121 lars 1377
			$file_names = array($this->get_file_name_param());
1378
		}
1379
		$response = array();
2130 lars 1380
		foreach ($file_names as $file_name) {
2121 lars 1381
			$file_path = $this->get_upload_path($file_name);
1382
			$success = is_file($file_path) && $file_name[0] !== '.' && unlink($file_path);
2130 lars 1383
			if ($success) {
1384
				foreach ($this->options['image_versions'] as $version => $options) {
1385
					if (!empty($version)) {
2121 lars 1386
						$file = $this->get_upload_path($file_name, $version);
2130 lars 1387
						if (is_file($file)) {
2121 lars 1388
							unlink($file);
1389
						}
1390
					}
1391
				}
1392
			}
1393
			$response[$file_name] = $success;
1394
		}
1395
		return $this->generate_response($response, $print_response);
1396
	}
1397
 
1398
	protected function basename($filepath, $suffix = null)
1399
	{
1400
		$splited = preg_split('/\//', rtrim($filepath, '/ '));
1401
		return substr(basename('X' . $splited[count($splited) - 1], $suffix), 1);
1402
	}
1403
}