aboutsummaryrefslogtreecommitdiffstats
path: root/library/blueimp_upload/server/php
diff options
context:
space:
mode:
Diffstat (limited to 'library/blueimp_upload/server/php')
-rw-r--r--library/blueimp_upload/server/php/Dockerfile38
-rwxr-xr-xlibrary/blueimp_upload/server/php/UploadHandler.php250
-rw-r--r--library/blueimp_upload/server/php/docker-compose.yml6
-rw-r--r--library/blueimp_upload/server/php/files/.htaccess14
-rw-r--r--library/blueimp_upload/server/php/index.php4
5 files changed, 207 insertions, 105 deletions
diff --git a/library/blueimp_upload/server/php/Dockerfile b/library/blueimp_upload/server/php/Dockerfile
new file mode 100644
index 000000000..ca88d3d0d
--- /dev/null
+++ b/library/blueimp_upload/server/php/Dockerfile
@@ -0,0 +1,38 @@
+FROM php:7.0-apache
+
+# Enable the Apache Headers module:
+RUN ln -s /etc/apache2/mods-available/headers.load \
+ /etc/apache2/mods-enabled/headers.load
+
+# Enable the Apache Rewrite module:
+RUN ln -s /etc/apache2/mods-available/rewrite.load \
+ /etc/apache2/mods-enabled/rewrite.load
+
+# Install GD, Imagick and ImageMagick as image conversion options:
+RUN DEBIAN_FRONTEND=noninteractive \
+ apt-get update && apt-get install -y --no-install-recommends \
+ libpng-dev \
+ libjpeg-dev \
+ libmagickwand-dev \
+ imagemagick \
+ && pecl install \
+ imagick \
+ && docker-php-ext-enable \
+ imagick \
+ && docker-php-ext-configure \
+ gd --with-jpeg-dir=/usr/include/ \
+ && docker-php-ext-install \
+ gd \
+ # Uninstall obsolete packages:
+ && apt-get autoremove -y \
+ libpng-dev \
+ libjpeg-dev \
+ libmagickwand-dev \
+ # Remove obsolete files:
+ && apt-get clean \
+ && rm -rf \
+ /tmp/* \
+ /usr/share/doc/* \
+ /var/cache/* \
+ /var/lib/apt/lists/* \
+ /var/tmp/*
diff --git a/library/blueimp_upload/server/php/UploadHandler.php b/library/blueimp_upload/server/php/UploadHandler.php
index fb77be1d0..1380d4739 100755
--- a/library/blueimp_upload/server/php/UploadHandler.php
+++ b/library/blueimp_upload/server/php/UploadHandler.php
@@ -1,13 +1,13 @@
<?php
/*
- * jQuery File Upload Plugin PHP Class 8.1.0
+ * jQuery File Upload Plugin PHP Class
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2010, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*/
class UploadHandler
@@ -40,11 +40,13 @@ class UploadHandler
protected $image_objects = array();
- function __construct($options = null, $initialize = true, $error_messages = null) {
+ public function __construct($options = null, $initialize = true, $error_messages = null) {
+ $this->response = array();
$this->options = array(
- 'script_url' => $this->get_full_url().'/',
+ 'script_url' => $this->get_full_url().'/'.$this->basename($this->get_server_var('SCRIPT_NAME')),
'upload_dir' => dirname($this->get_server_var('SCRIPT_FILENAME')).'/files/',
'upload_url' => $this->get_full_url().'/files/',
+ 'input_stream' => 'php://input',
'user_dirs' => false,
'mkdir_mode' => 0755,
'param_name' => 'files',
@@ -67,6 +69,14 @@ class UploadHandler
'Content-Range',
'Content-Disposition'
),
+ // By default, allow redirects to the referer protocol+host:
+ 'redirect_allow_target' => '/^'.preg_quote(
+ parse_url($this->get_server_var('HTTP_REFERER'), PHP_URL_SCHEME)
+ .'://'
+ .parse_url($this->get_server_var('HTTP_REFERER'), PHP_URL_HOST)
+ .'/', // Trailing slash to not match subdomains by mistake
+ '/' // preg_quote delimiter param
+ ).'/',
// Enable to provide file downloads via GET requests to the PHP script:
// 1. Set to 1 to download files via readfile method through PHP
// 2. Set to 2 to send a X-Sendfile header for lighttpd/Apache
@@ -147,7 +157,8 @@ class UploadHandler
'max_width' => 80,
'max_height' => 80
)
- )
+ ),
+ 'print_response' => true
);
if ($options) {
$this->options = $options + $this->options;
@@ -167,15 +178,15 @@ class UploadHandler
$this->head();
break;
case 'GET':
- $this->get();
+ $this->get($this->options['print_response']);
break;
case 'PATCH':
case 'PUT':
case 'POST':
- $this->post();
+ $this->post($this->options['print_response']);
break;
case 'DELETE':
- $this->delete();
+ $this->delete($this->options['print_response']);
break;
default:
$this->header('HTTP/1.1 405 Method Not Allowed');
@@ -300,7 +311,7 @@ class UploadHandler
$this->get_upload_path($file_name)
);
$file->url = $this->get_download_url($file->name);
- foreach($this->options['image_versions'] as $version => $options) {
+ foreach ($this->options['image_versions'] as $version => $options) {
if (!empty($version)) {
if (is_file($this->get_upload_path($file_name, $version))) {
$file->{$version.'Url'} = $this->get_download_url(
@@ -332,14 +343,15 @@ class UploadHandler
}
protected function get_error_message($error) {
- return array_key_exists($error, $this->error_messages) ?
+ return isset($this->error_messages[$error]) ?
$this->error_messages[$error] : $error;
}
- function get_config_bytes($val) {
+ public function get_config_bytes($val) {
$val = trim($val);
$last = strtolower($val[strlen($val)-1]);
- switch($last) {
+ $val = (int)$val;
+ switch ($last) {
case 'g':
$val *= 1024;
case 'm':
@@ -355,9 +367,9 @@ class UploadHandler
$file->error = $this->get_error_message($error);
return false;
}
- $content_length = $this->fix_integer_overflow(intval(
- $this->get_server_var('CONTENT_LENGTH')
- ));
+ $content_length = $this->fix_integer_overflow(
+ (int)$this->get_server_var('CONTENT_LENGTH')
+ );
$post_max_size = $this->get_config_bytes(ini_get('post_max_size'));
if ($post_max_size && ($content_length > $post_max_size)) {
$file->error = $this->get_error_message('post_max_size');
@@ -398,6 +410,21 @@ class UploadHandler
if (($max_width || $max_height || $min_width || $min_height)
&& preg_match($this->options['image_file_types'], $file->name)) {
list($img_width, $img_height) = $this->get_image_size($uploaded_file);
+
+ // If we are auto rotating the image by default, do the checks on
+ // the correct orientation
+ if (
+ @$this->options['image_versions']['']['auto_orient'] &&
+ function_exists('exif_read_data') &&
+ ($exif = @exif_read_data($uploaded_file)) &&
+ (((int) @$exif['Orientation']) >= 5)
+ ) {
+ $tmp = $img_width;
+ $img_width = $img_height;
+ $img_height = $tmp;
+ unset($tmp);
+ }
+
}
if (!empty($img_width)) {
if ($max_width && $img_width > $max_width) {
@@ -421,7 +448,7 @@ class UploadHandler
}
protected function upcount_name_callback($matches) {
- $index = isset($matches[1]) ? intval($matches[1]) + 1 : 1;
+ $index = isset($matches[1]) ? ((int)$matches[1]) + 1 : 1;
$ext = isset($matches[2]) ? $matches[2] : '';
return ' ('.$index.')'.$ext;
}
@@ -441,8 +468,8 @@ class UploadHandler
$name = $this->upcount_name($name);
}
// Keep an existing filename if this is part of a chunked upload:
- $uploaded_bytes = $this->fix_integer_overflow(intval($content_range[1]));
- while(is_file($this->get_upload_path($name))) {
+ $uploaded_bytes = $this->fix_integer_overflow((int)$content_range[1]);
+ while (is_file($this->get_upload_path($name))) {
if ($uploaded_bytes === $this->get_file_size(
$this->get_upload_path($name))) {
break;
@@ -461,7 +488,7 @@ class UploadHandler
}
if ($this->options['correct_image_extensions'] &&
function_exists('exif_imagetype')) {
- switch(@exif_imagetype($file_path)){
+ switch (@exif_imagetype($file_path)){
case IMAGETYPE_JPEG:
$extensions = array('jpg', 'jpeg');
break;
@@ -491,7 +518,7 @@ class UploadHandler
// Remove path information and dots around the filename, to prevent uploading
// into different directories or replacing hidden system files.
// Also remove control characters and spaces (\x00..\x20) around the filename:
- $name = trim(basename(stripslashes($name)), ".\x00..\x20");
+ $name = trim($this->basename(stripslashes($name)), ".\x00..\x20");
// Use a timestamp for empty filenames:
if (!$name) {
$name = str_replace('.', '-', microtime(true));
@@ -515,10 +542,6 @@ class UploadHandler
);
}
- protected function handle_form_data($file, $index) {
- // Handle form data, e.g. $_REQUEST['description'][$index]
- }
-
protected function get_scaled_image_file_paths($file_name, $version) {
$file_path = $this->get_upload_path($file_name);
if (!empty($version)) {
@@ -601,7 +624,7 @@ class UploadHandler
if ($exif === false) {
return false;
}
- $orientation = intval(@$exif['Orientation']);
+ $orientation = (int)@$exif['Orientation'];
if ($orientation < 2 || $orientation > 8) {
return false;
}
@@ -825,7 +848,7 @@ class UploadHandler
$this->get_scaled_image_file_paths($file_name, $version);
$image = $this->imagick_get_image_object(
$file_path,
- !empty($options['no_cache'])
+ !empty($options['crop']) || !empty($options['no_cache'])
);
if ($image->getImageFormat() === 'GIF') {
// Handle animated GIFs:
@@ -955,7 +978,7 @@ class UploadHandler
return $dimensions;
}
return false;
- } catch (Exception $e) {
+ } catch (\Exception $e) {
error_log($e->getMessage());
}
}
@@ -965,7 +988,7 @@ class UploadHandler
exec($cmd, $output, $error);
if (!$error && !empty($output)) {
// image.jpg JPEG 1920x1080 1920x1080+0+0 8-bit sRGB 465KB 0.000u 0:00.000
- $infos = preg_split('/\s+/', $output[0]);
+ $infos = preg_split('/\s+/', substr($output[0], strlen($file_path)));
$dimensions = preg_split('/x/', $infos[2]);
return $dimensions;
}
@@ -1008,7 +1031,7 @@ class UploadHandler
protected function handle_image_file($file_path, $file) {
$failed_versions = array();
- foreach($this->options['image_versions'] as $version => $options) {
+ foreach ($this->options['image_versions'] as $version => $options) {
if ($this->create_scaled_image($file->name, $version, $options)) {
if (!empty($version)) {
$file->{$version.'Url'} = $this->get_download_url(
@@ -1024,7 +1047,7 @@ class UploadHandler
}
if (count($failed_versions)) {
$file->error = $this->get_error_message('image_resize')
- .' ('.implode($failed_versions,', ').')';
+ .' ('.implode($failed_versions, ', ').')';
}
// Free memory:
$this->destroy_image_object($file_path);
@@ -1035,7 +1058,7 @@ class UploadHandler
$file = new \stdClass();
$file->name = $this->get_file_name($uploaded_file, $name, $size, $type, $error,
$index, $content_range);
- $file->size = $this->fix_integer_overflow(intval($size));
+ $file->size = $this->fix_integer_overflow((int)$size);
$file->type = $type;
if ($this->validate($uploaded_file, $file, $error, $index)) {
$this->handle_form_data($file, $index);
@@ -1061,7 +1084,7 @@ class UploadHandler
// Non-multipart uploads (PUT method support)
file_put_contents(
$file_path,
- fopen('php://input', 'r'),
+ fopen($this->options['input_stream'], 'r'),
$append_file ? FILE_APPEND : 0
);
}
@@ -1102,41 +1125,33 @@ class UploadHandler
protected function body($str) {
echo $str;
}
-
+
protected function header($str) {
header($str);
}
+ protected function get_upload_data($id) {
+ return @$_FILES[$id];
+ }
+
+ protected function get_post_param($id) {
+ return @$_POST[$id];
+ }
+
+ protected function get_query_param($id) {
+ return @$_GET[$id];
+ }
+
protected function get_server_var($id) {
- return isset($_SERVER[$id]) ? $_SERVER[$id] : '';
+ return @$_SERVER[$id];
}
- protected function generate_response($content, $print_response = true) {
- if ($print_response) {
- $json = json_encode($content);
- $redirect = isset($_REQUEST['redirect']) ?
- stripslashes($_REQUEST['redirect']) : null;
- if ($redirect) {
- $this->header('Location: '.sprintf($redirect, rawurlencode($json)));
- return;
- }
- $this->head();
- if ($this->get_server_var('HTTP_CONTENT_RANGE')) {
- $files = isset($content[$this->options['param_name']]) ?
- $content[$this->options['param_name']] : null;
- if ($files && is_array($files) && is_object($files[0]) && $files[0]->size) {
- $this->header('Range: 0-'.(
- $this->fix_integer_overflow(intval($files[0]->size)) - 1
- ));
- }
- }
- $this->body($json);
- }
- return $content;
+ protected function handle_form_data($file, $index) {
+ // Handle form data, e.g. $_POST['description'][$index]
}
protected function get_version_param() {
- return isset($_GET['version']) ? basename(stripslashes($_GET['version'])) : null;
+ return $this->basename(stripslashes($this->get_query_param('version')));
}
protected function get_singular_param_name() {
@@ -1145,14 +1160,16 @@ class UploadHandler
protected function get_file_name_param() {
$name = $this->get_singular_param_name();
- return isset($_REQUEST[$name]) ? basename(stripslashes($_REQUEST[$name])) : null;
+ return $this->basename(stripslashes($this->get_query_param($name)));
}
protected function get_file_names_params() {
- $params = isset($_REQUEST[$this->options['param_name']]) ?
- $_REQUEST[$this->options['param_name']] : array();
+ $params = $this->get_query_param($this->options['param_name']);
+ if (!$params) {
+ return null;
+ }
foreach ($params as $key => $value) {
- $params[$key] = basename(stripslashes($value));
+ $params[$key] = $this->basename(stripslashes($value));
}
return $params;
}
@@ -1232,6 +1249,34 @@ class UploadHandler
.implode(', ', $this->options['access_control_allow_headers']));
}
+ public function generate_response($content, $print_response = true) {
+ $this->response = $content;
+ if ($print_response) {
+ $json = json_encode($content);
+ $redirect = stripslashes($this->get_post_param('redirect'));
+ if ($redirect && preg_match($this->options['redirect_allow_target'], $redirect)) {
+ $this->header('Location: '.sprintf($redirect, rawurlencode($json)));
+ return;
+ }
+ $this->head();
+ if ($this->get_server_var('HTTP_CONTENT_RANGE')) {
+ $files = isset($content[$this->options['param_name']]) ?
+ $content[$this->options['param_name']] : null;
+ if ($files && is_array($files) && is_object($files[0]) && $files[0]->size) {
+ $this->header('Range: 0-'.(
+ $this->fix_integer_overflow((int)$files[0]->size) - 1
+ ));
+ }
+ }
+ $this->body($json);
+ }
+ return $content;
+ }
+
+ public function get_response () {
+ return $this->response;
+ }
+
public function head() {
$this->header('Pragma: no-cache');
$this->header('Cache-Control: no-store, no-cache, must-revalidate');
@@ -1245,7 +1290,7 @@ class UploadHandler
}
public function get($print_response = true) {
- if ($print_response && isset($_GET['download'])) {
+ if ($print_response && $this->get_query_param('download')) {
return $this->download();
}
$file_name = $this->get_file_name_param();
@@ -1262,58 +1307,59 @@ class UploadHandler
}
public function post($print_response = true) {
- if (isset($_REQUEST['_method']) && $_REQUEST['_method'] === 'DELETE') {
+ if ($this->get_query_param('_method') === 'DELETE') {
return $this->delete($print_response);
}
- $upload = isset($_FILES[$this->options['param_name']]) ?
- $_FILES[$this->options['param_name']] : null;
+ $upload = $this->get_upload_data($this->options['param_name']);
// Parse the Content-Disposition header, if available:
- $file_name = $this->get_server_var('HTTP_CONTENT_DISPOSITION') ?
+ $content_disposition_header = $this->get_server_var('HTTP_CONTENT_DISPOSITION');
+ $file_name = $content_disposition_header ?
rawurldecode(preg_replace(
'/(^[^"]+")|("$)/',
'',
- $this->get_server_var('HTTP_CONTENT_DISPOSITION')
+ $content_disposition_header
)) : null;
// Parse the Content-Range header, which has the following form:
// Content-Range: bytes 0-524287/2000000
- $content_range = $this->get_server_var('HTTP_CONTENT_RANGE') ?
- preg_split('/[^0-9]+/', $this->get_server_var('HTTP_CONTENT_RANGE')) : null;
+ $content_range_header = $this->get_server_var('HTTP_CONTENT_RANGE');
+ $content_range = $content_range_header ?
+ preg_split('/[^0-9]+/', $content_range_header) : null;
$size = $content_range ? $content_range[3] : null;
$files = array();
- if ($upload && is_array($upload['tmp_name'])) {
- // param_name is an array identifier like "files[]",
- // $_FILES is a multi-dimensional array:
- foreach ($upload['tmp_name'] as $index => $value) {
+ if ($upload) {
+ if (is_array($upload['tmp_name'])) {
+ // param_name is an array identifier like "files[]",
+ // $upload is a multi-dimensional array:
+ foreach ($upload['tmp_name'] as $index => $value) {
+ $files[] = $this->handle_file_upload(
+ $upload['tmp_name'][$index],
+ $file_name ? $file_name : $upload['name'][$index],
+ $size ? $size : $upload['size'][$index],
+ $upload['type'][$index],
+ $upload['error'][$index],
+ $index,
+ $content_range
+ );
+ }
+ } else {
+ // param_name is a single object identifier like "file",
+ // $upload is a one-dimensional array:
$files[] = $this->handle_file_upload(
- $upload['tmp_name'][$index],
- $file_name ? $file_name : $upload['name'][$index],
- $size ? $size : $upload['size'][$index],
- $upload['type'][$index],
- $upload['error'][$index],
- $index,
+ isset($upload['tmp_name']) ? $upload['tmp_name'] : null,
+ $file_name ? $file_name : (isset($upload['name']) ?
+ $upload['name'] : null),
+ $size ? $size : (isset($upload['size']) ?
+ $upload['size'] : $this->get_server_var('CONTENT_LENGTH')),
+ isset($upload['type']) ?
+ $upload['type'] : $this->get_server_var('CONTENT_TYPE'),
+ isset($upload['error']) ? $upload['error'] : null,
+ null,
$content_range
);
}
- } else {
- // param_name is a single object identifier like "file",
- // $_FILES is a one-dimensional array:
- $files[] = $this->handle_file_upload(
- isset($upload['tmp_name']) ? $upload['tmp_name'] : null,
- $file_name ? $file_name : (isset($upload['name']) ?
- $upload['name'] : null),
- $size ? $size : (isset($upload['size']) ?
- $upload['size'] : $this->get_server_var('CONTENT_LENGTH')),
- isset($upload['type']) ?
- $upload['type'] : $this->get_server_var('CONTENT_TYPE'),
- isset($upload['error']) ? $upload['error'] : null,
- null,
- $content_range
- );
}
- return $this->generate_response(
- array($this->options['param_name'] => $files),
- $print_response
- );
+ $response = array($this->options['param_name'] => $files);
+ return $this->generate_response($response, $print_response);
}
public function delete($print_response = true) {
@@ -1322,11 +1368,11 @@ class UploadHandler
$file_names = array($this->get_file_name_param());
}
$response = array();
- foreach($file_names as $file_name) {
+ foreach ($file_names as $file_name) {
$file_path = $this->get_upload_path($file_name);
$success = is_file($file_path) && $file_name[0] !== '.' && unlink($file_path);
if ($success) {
- foreach($this->options['image_versions'] as $version => $options) {
+ foreach ($this->options['image_versions'] as $version => $options) {
if (!empty($version)) {
$file = $this->get_upload_path($file_name, $version);
if (is_file($file)) {
@@ -1340,4 +1386,8 @@ class UploadHandler
return $this->generate_response($response, $print_response);
}
+ protected function basename($filepath, $suffix = null) {
+ $splited = preg_split('/\//', rtrim ($filepath, '/ '));
+ return substr(basename('X'.$splited[count($splited)-1], $suffix), 1);
+ }
}
diff --git a/library/blueimp_upload/server/php/docker-compose.yml b/library/blueimp_upload/server/php/docker-compose.yml
new file mode 100644
index 000000000..691ea9caa
--- /dev/null
+++ b/library/blueimp_upload/server/php/docker-compose.yml
@@ -0,0 +1,6 @@
+apache:
+ build: ./
+ ports:
+ - "80:80"
+ volumes:
+ - "../../:/var/www/html"
diff --git a/library/blueimp_upload/server/php/files/.htaccess b/library/blueimp_upload/server/php/files/.htaccess
index 56689f0bb..6f454afb9 100644
--- a/library/blueimp_upload/server/php/files/.htaccess
+++ b/library/blueimp_upload/server/php/files/.htaccess
@@ -1,8 +1,16 @@
-# The following directives force the content-type application/octet-stream
-# and force browsers to display a download dialog for non-image files.
-# This prevents the execution of script files in the context of the website:
+# To enable the Headers module, execute the following command and reload Apache:
+# sudo a2enmod headers
+
+# The following directives prevent the execution of script files
+# in the context of the website.
+# They also force the content-type application/octet-stream and
+# force browsers to display a download dialog for non-image files.
+SetHandler default-handler
ForceType application/octet-stream
Header set Content-Disposition attachment
+
+# The following unsets the forced type and Content-Disposition headers
+# for known image files:
<FilesMatch "(?i)\.(gif|jpe?g|png)$">
ForceType none
Header unset Content-Disposition
diff --git a/library/blueimp_upload/server/php/index.php b/library/blueimp_upload/server/php/index.php
index 3ae1295ef..6caabb710 100644
--- a/library/blueimp_upload/server/php/index.php
+++ b/library/blueimp_upload/server/php/index.php
@@ -1,13 +1,13 @@
<?php
/*
- * jQuery File Upload Plugin PHP Example 5.14
+ * jQuery File Upload Plugin PHP Example
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2010, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*/
error_reporting(E_ALL | E_STRICT);