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