card-mod-script 0.13.2 → 0.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/assets/script/decko/components.js.coffee +3 -0
  3. data/assets/script/decko/decko.js.coffee +0 -15
  4. data/assets/script/decko/editor.js.coffee +3 -1
  5. data/assets/script/decko/filter.js.coffee +14 -7
  6. data/assets/script/decko/filter_links.js.coffee +2 -2
  7. data/assets/script/decko/mod.js.coffee +2 -8
  8. data/assets/script/decko/name_editor.js.coffee +0 -18
  9. data/assets/script/decko/overlay.js.coffee +0 -3
  10. data/assets/script/{script_pointer_config.js.coffee → decko/pointer_config.js.coffee} +1 -2
  11. data/assets/script/{script_pointer_list_editor.js.coffee → decko/pointer_list_editor.js.coffee} +0 -0
  12. data/assets/script/decko/slot.js.coffee +3 -3
  13. data/assets/script/decko/slot_ready.js.coffee +1 -0
  14. data/assets/script/decko/slotter.js.coffee +23 -31
  15. data/assets/script/decko/type_editor.js.coffee +21 -0
  16. data/assets/script/decko/upload.js.coffee +12 -5
  17. data/assets/script/jquery-ui.min.js +13 -0
  18. data/assets/script/manifest.yml +16 -3
  19. data/init/early/init_execjs.rb +3 -0
  20. data/set/abstract/00_script.rb +30 -31
  21. data/set/abstract/01_asset_script.rb +0 -16
  22. data/set/abstract/{script_asset_list.rb → script_group.rb} +12 -13
  23. data/set/all/head_javascript.rb +12 -8
  24. data/set/right/script.rb +1 -14
  25. data/set/type/local_script_folder_group.rb +2 -2
  26. data/set/type/local_script_manifest_group.rb +1 -1
  27. data/set/type_plus_right/mod/script.rb +56 -0
  28. data/set/type_plus_right/set/script.rb +7 -0
  29. data/vendor/jquery_file_upload/LICENSE.txt +11 -12
  30. data/vendor/jquery_file_upload/README.md +189 -72
  31. data/vendor/jquery_file_upload/SECURITY.md +227 -0
  32. data/vendor/jquery_file_upload/VULNERABILITIES.md +118 -0
  33. data/vendor/jquery_file_upload/cors/postmessage.html +68 -58
  34. data/vendor/jquery_file_upload/cors/result.html +12 -10
  35. data/vendor/jquery_file_upload/css/jquery.fileupload-ui.css +24 -13
  36. data/vendor/jquery_file_upload/css/jquery.fileupload.css +3 -4
  37. data/vendor/jquery_file_upload/docker-compose.yml +55 -0
  38. data/vendor/jquery_file_upload/index.html +332 -230
  39. data/vendor/jquery_file_upload/js/cors/jquery.postmessage-transport.js +109 -109
  40. data/vendor/jquery_file_upload/js/cors/jquery.xdr-transport.js +81 -73
  41. data/vendor/jquery_file_upload/js/demo.js +75 -0
  42. data/vendor/jquery_file_upload/js/jquery.fileupload-audio.js +82 -94
  43. data/vendor/jquery_file_upload/js/jquery.fileupload-image.js +321 -300
  44. data/vendor/jquery_file_upload/js/jquery.fileupload-process.js +138 -146
  45. data/vendor/jquery_file_upload/js/jquery.fileupload-ui.js +737 -692
  46. data/vendor/jquery_file_upload/js/jquery.fileupload-validate.js +91 -97
  47. data/vendor/jquery_file_upload/js/jquery.fileupload-video.js +82 -94
  48. data/vendor/jquery_file_upload/js/jquery.fileupload.js +1569 -1451
  49. data/vendor/jquery_file_upload/js/jquery.iframe-transport.js +208 -205
  50. data/vendor/jquery_file_upload/js/vendor/jquery.ui.widget.js +397 -340
  51. data/vendor/jquery_file_upload/package-lock.json +6853 -0
  52. data/vendor/jquery_file_upload/package.json +71 -10
  53. data/vendor/jquery_file_upload/server/gae-python/app.yaml +11 -10
  54. data/vendor/jquery_file_upload/server/php/Dockerfile +23 -17
  55. data/vendor/jquery_file_upload/server/php/UploadHandler.php +206 -137
  56. data/vendor/jquery_file_upload/server/php/php.ini +5 -0
  57. data/vendor/jquery_file_upload/test/index.html +36 -159
  58. data/vendor/jquery_file_upload/test/unit.js +989 -0
  59. data/vendor/jquery_file_upload/test/vendor/chai.js +10854 -0
  60. data/vendor/jquery_file_upload/test/vendor/mocha.css +325 -0
  61. data/vendor/jquery_file_upload/test/vendor/mocha.js +18178 -0
  62. data/vendor/jquery_file_upload/wdio/LICENSE.txt +20 -0
  63. data/vendor/jquery_file_upload/wdio/assets/black+white-3x2.jpg +0 -0
  64. data/vendor/jquery_file_upload/wdio/assets/black+white-60x40.gif +0 -0
  65. data/vendor/jquery_file_upload/wdio/conf/chrome.js +40 -0
  66. data/vendor/jquery_file_upload/wdio/conf/firefox.js +25 -0
  67. data/vendor/jquery_file_upload/wdio/hooks/index.js +36 -0
  68. data/vendor/jquery_file_upload/wdio/test/pages/file-upload.js +79 -0
  69. data/vendor/jquery_file_upload/wdio/test/specs/01-file-upload.js +25 -0
  70. data/vendor/jquery_file_upload/wdio/wdio.conf.js +4 -0
  71. metadata +36 -53
  72. data/assets/script/jquery-ui.js +0 -10
  73. data/file/mod_script_script_decko_machine_output/file.js +0 -2710
  74. data/file/mod_script_script_jquery_machine_output/file.js +0 -12924
  75. data/lib/javascript/script_html5shiv_printshiv.js +0 -1
  76. data/set/self/script_html5shiv_printshiv.rb +0 -11
  77. data/set/self/script_mods.rb +0 -1
  78. data/set/type/mod_script_assets.rb +0 -21
  79. data/vendor/jquery_file_upload/CONTRIBUTING.md +0 -15
  80. data/vendor/jquery_file_upload/angularjs.html +0 -211
  81. data/vendor/jquery_file_upload/basic-plus.html +0 -226
  82. data/vendor/jquery_file_upload/basic.html +0 -136
  83. data/vendor/jquery_file_upload/bower-version-update.js +0 -16
  84. data/vendor/jquery_file_upload/bower.json +0 -64
  85. data/vendor/jquery_file_upload/css/jquery-ui-demo-ie8.css +0 -21
  86. data/vendor/jquery_file_upload/css/jquery-ui-demo.css +0 -67
  87. data/vendor/jquery_file_upload/css/style.css +0 -15
  88. data/vendor/jquery_file_upload/jquery-ui.html +0 -252
  89. data/vendor/jquery_file_upload/js/app.js +0 -101
  90. data/vendor/jquery_file_upload/js/jquery.fileupload-angular.js +0 -437
  91. data/vendor/jquery_file_upload/js/jquery.fileupload-jquery-ui.js +0 -161
  92. data/vendor/jquery_file_upload/js/main.js +0 -75
  93. data/vendor/jquery_file_upload/server/gae-go/app/main.go +0 -361
  94. data/vendor/jquery_file_upload/server/gae-go/app.yaml +0 -12
  95. data/vendor/jquery_file_upload/server/gae-go/static/favicon.ico +0 -0
  96. data/vendor/jquery_file_upload/server/gae-go/static/robots.txt +0 -2
  97. data/vendor/jquery_file_upload/server/php/docker-compose.yml +0 -9
  98. data/vendor/jquery_file_upload/test/test.js +0 -1292
@@ -16,7 +16,7 @@ class UploadHandler
16
16
  protected $options;
17
17
 
18
18
  // PHP File Upload error message codes:
19
- // http://php.net/manual/en/features.file-upload.errors.php
19
+ // https://php.net/manual/en/features.file-upload.errors.php
20
20
  protected $error_messages = array(
21
21
  1 => 'The uploaded file exceeds the upload_max_filesize directive in php.ini',
22
22
  2 => 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form',
@@ -30,6 +30,7 @@ class UploadHandler
30
30
  'min_file_size' => 'File is too small',
31
31
  'accept_file_types' => 'Filetype not allowed',
32
32
  'max_number_of_files' => 'Maximum number of files exceeded',
33
+ 'invalid_file_type' => 'Invalid file type',
33
34
  'max_width' => 'Image exceeds maximum width',
34
35
  'min_width' => 'Image requires a minimum width',
35
36
  'max_height' => 'Image exceeds maximum height',
@@ -38,10 +39,14 @@ class UploadHandler
38
39
  'image_resize' => 'Failed to resize image'
39
40
  );
40
41
 
42
+ const IMAGETYPE_GIF = 'image/gif';
43
+ const IMAGETYPE_JPEG = 'image/jpeg';
44
+ const IMAGETYPE_PNG = 'image/png';
45
+
41
46
  protected $image_objects = array();
47
+ protected $response = array();
42
48
 
43
49
  public function __construct($options = null, $initialize = true, $error_messages = null) {
44
- $this->response = array();
45
50
  $this->options = array(
46
51
  'script_url' => $this->get_full_url().'/'.$this->basename($this->get_server_var('SCRIPT_NAME')),
47
52
  'upload_dir' => dirname($this->get_server_var('SCRIPT_FILENAME')).'/files/',
@@ -71,12 +76,12 @@ class UploadHandler
71
76
  ),
72
77
  // By default, allow redirects to the referer protocol+host:
73
78
  'redirect_allow_target' => '/^'.preg_quote(
74
- parse_url($this->get_server_var('HTTP_REFERER'), PHP_URL_SCHEME)
75
- .'://'
76
- .parse_url($this->get_server_var('HTTP_REFERER'), PHP_URL_HOST)
77
- .'/', // Trailing slash to not match subdomains by mistake
78
- '/' // preg_quote delimiter param
79
- ).'/',
79
+ parse_url($this->get_server_var('HTTP_REFERER'), PHP_URL_SCHEME)
80
+ .'://'
81
+ .parse_url($this->get_server_var('HTTP_REFERER'), PHP_URL_HOST)
82
+ .'/', // Trailing slash to not match subdomains by mistake
83
+ '/' // preg_quote delimiter param
84
+ ).'/',
80
85
  // Enable to provide file downloads via GET requests to the PHP script:
81
86
  // 1. Set to 1 to download files via readfile method through PHP
82
87
  // 2. Set to 2 to send a X-Sendfile header for lighttpd/Apache
@@ -89,17 +94,32 @@ class UploadHandler
89
94
  'readfile_chunk_size' => 10 * 1024 * 1024, // 10 MiB
90
95
  // Defines which files can be displayed inline when downloaded:
91
96
  'inline_file_types' => '/\.(gif|jpe?g|png)$/i',
92
- // Defines which files (based on their names) are accepted for upload:
93
- 'accept_file_types' => '/.+$/i',
97
+ // Defines which files (based on their names) are accepted for upload.
98
+ // By default, only allows file uploads with image file extensions.
99
+ // Only change this setting after making sure that any allowed file
100
+ // types cannot be executed by the webserver in the files directory,
101
+ // e.g. PHP scripts, nor executed by the browser when downloaded,
102
+ // e.g. HTML files with embedded JavaScript code.
103
+ // Please also read the SECURITY.md document in this repository.
104
+ 'accept_file_types' => '/\.(gif|jpe?g|png)$/i',
105
+ // Replaces dots in filenames with the given string.
106
+ // Can be disabled by setting it to false or an empty string.
107
+ // Note that this is a security feature for servers that support
108
+ // multiple file extensions, e.g. the Apache AddHandler Directive:
109
+ // https://httpd.apache.org/docs/current/mod/mod_mime.html#addhandler
110
+ // Before disabling it, make sure that files uploaded with multiple
111
+ // extensions cannot be executed by the webserver, e.g.
112
+ // "example.php.png" with embedded PHP code, nor executed by the
113
+ // browser when downloaded, e.g. "example.html.gif" with embedded
114
+ // JavaScript code.
115
+ 'replace_dots_in_filenames' => '-',
94
116
  // The php.ini settings upload_max_filesize and post_max_size
95
117
  // take precedence over the following max_file_size setting:
96
118
  'max_file_size' => null,
97
119
  'min_file_size' => 1,
98
120
  // The maximum number of files for the upload directory:
99
121
  'max_number_of_files' => null,
100
- // Defines which files are handled as image files:
101
- 'image_file_types' => '/\.(gif|jpe?g|png)$/i',
102
- // Use exif_imagetype on all files to correct file extensions:
122
+ // Reads first file bytes to identify and correct file extensions:
103
123
  'correct_image_extensions' => false,
104
124
  // Image resolution restrictions:
105
125
  'max_width' => null,
@@ -132,21 +152,21 @@ class UploadHandler
132
152
  'identify_bin' => 'identify',
133
153
  'image_versions' => array(
134
154
  // The empty image version key defines options for the original image.
135
- // Keep in mind: these image manipulations are inherited by all other image versions from this point onwards.
155
+ // Keep in mind: these image manipulations are inherited by all other image versions from this point onwards.
136
156
  // Also note that the property 'no_cache' is not inherited, since it's not a manipulation.
137
157
  '' => array(
138
158
  // Automatically rotate images based on EXIF meta data:
139
159
  'auto_orient' => true
140
160
  ),
141
161
  // You can add arrays to generate different versions.
142
- // The name of the key is the name of the version (example: 'medium').
162
+ // The name of the key is the name of the version (example: 'medium').
143
163
  // the array contains the options to apply.
144
164
  /*
145
165
  'medium' => array(
146
166
  'max_width' => 800,
147
167
  'max_height' => 600
148
168
  ),
149
- */
169
+ */
150
170
  'thumbnail' => array(
151
171
  // Uncomment the following to use a defined directory for the thumbnails
152
172
  // instead of a subdirectory based on the version identifier.
@@ -204,13 +224,13 @@ class UploadHandler
204
224
  protected function get_full_url() {
205
225
  $https = !empty($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'], 'on') === 0 ||
206
226
  !empty($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
207
- strcasecmp($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') === 0;
227
+ strcasecmp($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') === 0;
208
228
  return
209
229
  ($https ? 'https://' : 'http://').
210
230
  (!empty($_SERVER['REMOTE_USER']) ? $_SERVER['REMOTE_USER'].'@' : '').
211
231
  (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : ($_SERVER['SERVER_NAME'].
212
- ($https && $_SERVER['SERVER_PORT'] === 443 ||
213
- $_SERVER['SERVER_PORT'] === 80 ? '' : ':'.$_SERVER['SERVER_PORT']))).
232
+ ($https && $_SERVER['SERVER_PORT'] === 443 ||
233
+ $_SERVER['SERVER_PORT'] === 80 ? '' : ':'.$_SERVER['SERVER_PORT']))).
214
234
  substr($_SERVER['SCRIPT_NAME'],0, strrpos($_SERVER['SCRIPT_NAME'], '/'));
215
235
  }
216
236
 
@@ -305,7 +325,7 @@ class UploadHandler
305
325
 
306
326
  protected function is_valid_file_object($file_name) {
307
327
  $file_path = $this->get_upload_path($file_name);
308
- if (is_file($file_path) && $file_name[0] !== '.') {
328
+ if (strlen($file_name) > 0 && $file_name[0] !== '.' && is_file($file_path)) {
309
329
  return true;
310
330
  }
311
331
  return false;
@@ -358,7 +378,11 @@ class UploadHandler
358
378
  public function get_config_bytes($val) {
359
379
  $val = trim($val);
360
380
  $last = strtolower($val[strlen($val)-1]);
361
- $val = (int)$val;
381
+ if (is_numeric($val)) {
382
+ $val = (int)$val;
383
+ } else {
384
+ $val = (int)substr($val, 0, -1);
385
+ }
362
386
  switch ($last) {
363
387
  case 'g':
364
388
  $val *= 1024;
@@ -370,7 +394,53 @@ class UploadHandler
370
394
  return $this->fix_integer_overflow($val);
371
395
  }
372
396
 
373
- protected function validate($uploaded_file, $file, $error, $index) {
397
+ protected function validate_image_file($uploaded_file, $file, $error, $index) {
398
+ if ($this->imagetype($uploaded_file) !== $this->get_file_type($file->name)) {
399
+ $file->error = $this->get_error_message('invalid_file_type');
400
+ return false;
401
+ }
402
+ $max_width = @$this->options['max_width'];
403
+ $max_height = @$this->options['max_height'];
404
+ $min_width = @$this->options['min_width'];
405
+ $min_height = @$this->options['min_height'];
406
+ if ($max_width || $max_height || $min_width || $min_height) {
407
+ list($img_width, $img_height) = $this->get_image_size($uploaded_file);
408
+ // If we are auto rotating the image by default, do the checks on
409
+ // the correct orientation
410
+ if (
411
+ @$this->options['image_versions']['']['auto_orient'] &&
412
+ function_exists('exif_read_data') &&
413
+ ($exif = @exif_read_data($uploaded_file)) &&
414
+ (((int) @$exif['Orientation']) >= 5)
415
+ ) {
416
+ $tmp = $img_width;
417
+ $img_width = $img_height;
418
+ $img_height = $tmp;
419
+ unset($tmp);
420
+ }
421
+ if (!empty($img_width) && !empty($img_height)) {
422
+ if ($max_width && $img_width > $max_width) {
423
+ $file->error = $this->get_error_message('max_width');
424
+ return false;
425
+ }
426
+ if ($max_height && $img_height > $max_height) {
427
+ $file->error = $this->get_error_message('max_height');
428
+ return false;
429
+ }
430
+ if ($min_width && $img_width < $min_width) {
431
+ $file->error = $this->get_error_message('min_width');
432
+ return false;
433
+ }
434
+ if ($min_height && $img_height < $min_height) {
435
+ $file->error = $this->get_error_message('min_height');
436
+ return false;
437
+ }
438
+ }
439
+ }
440
+ return true;
441
+ }
442
+
443
+ protected function validate($uploaded_file, $file, $error, $index, $content_range) {
374
444
  if ($error) {
375
445
  $file->error = $this->get_error_message($error);
376
446
  return false;
@@ -395,7 +465,7 @@ class UploadHandler
395
465
  if ($this->options['max_file_size'] && (
396
466
  $file_size > $this->options['max_file_size'] ||
397
467
  $file->size > $this->options['max_file_size'])
398
- ) {
468
+ ) {
399
469
  $file->error = $this->get_error_message('max_file_size');
400
470
  return false;
401
471
  }
@@ -405,52 +475,14 @@ class UploadHandler
405
475
  return false;
406
476
  }
407
477
  if (is_int($this->options['max_number_of_files']) &&
408
- ($this->count_file_objects() >= $this->options['max_number_of_files']) &&
409
- // Ignore additional chunks of existing files:
410
- !is_file($this->get_upload_path($file->name))) {
478
+ ($this->count_file_objects() >= $this->options['max_number_of_files']) &&
479
+ // Ignore additional chunks of existing files:
480
+ !is_file($this->get_upload_path($file->name))) {
411
481
  $file->error = $this->get_error_message('max_number_of_files');
412
482
  return false;
413
483
  }
414
- $max_width = @$this->options['max_width'];
415
- $max_height = @$this->options['max_height'];
416
- $min_width = @$this->options['min_width'];
417
- $min_height = @$this->options['min_height'];
418
- if (($max_width || $max_height || $min_width || $min_height)
419
- && preg_match($this->options['image_file_types'], $file->name)) {
420
- list($img_width, $img_height) = $this->get_image_size($uploaded_file);
421
-
422
- // If we are auto rotating the image by default, do the checks on
423
- // the correct orientation
424
- if (
425
- @$this->options['image_versions']['']['auto_orient'] &&
426
- function_exists('exif_read_data') &&
427
- ($exif = @exif_read_data($uploaded_file)) &&
428
- (((int) @$exif['Orientation']) >= 5)
429
- ) {
430
- $tmp = $img_width;
431
- $img_width = $img_height;
432
- $img_height = $tmp;
433
- unset($tmp);
434
- }
435
-
436
- }
437
- if (!empty($img_width)) {
438
- if ($max_width && $img_width > $max_width) {
439
- $file->error = $this->get_error_message('max_width');
440
- return false;
441
- }
442
- if ($max_height && $img_height > $max_height) {
443
- $file->error = $this->get_error_message('max_height');
444
- return false;
445
- }
446
- if ($min_width && $img_width < $min_width) {
447
- $file->error = $this->get_error_message('min_width');
448
- return false;
449
- }
450
- if ($min_height && $img_height < $min_height) {
451
- $file->error = $this->get_error_message('min_height');
452
- return false;
453
- }
484
+ if (!$content_range && $this->has_image_file_extension($file->name)) {
485
+ return $this->validate_image_file($uploaded_file, $file, $error, $index);
454
486
  }
455
487
  return true;
456
488
  }
@@ -471,12 +503,12 @@ class UploadHandler
471
503
  }
472
504
 
473
505
  protected function get_unique_filename($file_path, $name, $size, $type, $error,
474
- $index, $content_range) {
506
+ $index, $content_range) {
475
507
  while(is_dir($this->get_upload_path($name))) {
476
508
  $name = $this->upcount_name($name);
477
509
  }
478
510
  // Keep an existing filename if this is part of a chunked upload:
479
- $uploaded_bytes = $this->fix_integer_overflow((int)$content_range[1]);
511
+ $uploaded_bytes = $this->fix_integer_overflow((int)@$content_range[1]);
480
512
  while (is_file($this->get_upload_path($name))) {
481
513
  if ($uploaded_bytes === $this->get_file_size(
482
514
  $this->get_upload_path($name))) {
@@ -487,26 +519,26 @@ class UploadHandler
487
519
  return $name;
488
520
  }
489
521
 
522
+ protected function get_valid_image_extensions($file_path) {
523
+ switch ($this->imagetype($file_path)) {
524
+ case self::IMAGETYPE_JPEG:
525
+ return array('jpg', 'jpeg');
526
+ case self::IMAGETYPE_PNG:
527
+ return array('png');
528
+ case self::IMAGETYPE_GIF:
529
+ return array('gif');
530
+ }
531
+ }
532
+
490
533
  protected function fix_file_extension($file_path, $name, $size, $type, $error,
491
- $index, $content_range) {
534
+ $index, $content_range) {
492
535
  // Add missing file extension for known image types:
493
536
  if (strpos($name, '.') === false &&
494
- preg_match('/^image\/(gif|jpe?g|png)/', $type, $matches)) {
537
+ preg_match('/^image\/(gif|jpe?g|png)/', $type, $matches)) {
495
538
  $name .= '.'.$matches[1];
496
539
  }
497
- if ($this->options['correct_image_extensions'] &&
498
- function_exists('exif_imagetype')) {
499
- switch (@exif_imagetype($file_path)){
500
- case IMAGETYPE_JPEG:
501
- $extensions = array('jpg', 'jpeg');
502
- break;
503
- case IMAGETYPE_PNG:
504
- $extensions = array('png');
505
- break;
506
- case IMAGETYPE_GIF:
507
- $extensions = array('gif');
508
- break;
509
- }
540
+ if ($this->options['correct_image_extensions']) {
541
+ $extensions = $this->get_valid_image_extensions($file_path);
510
542
  // Adjust incorrect image file extensions:
511
543
  if (!empty($extensions)) {
512
544
  $parts = explode('.', $name);
@@ -522,11 +554,21 @@ class UploadHandler
522
554
  }
523
555
 
524
556
  protected function trim_file_name($file_path, $name, $size, $type, $error,
525
- $index, $content_range) {
557
+ $index, $content_range) {
526
558
  // Remove path information and dots around the filename, to prevent uploading
527
559
  // into different directories or replacing hidden system files.
528
560
  // Also remove control characters and spaces (\x00..\x20) around the filename:
529
561
  $name = trim($this->basename(stripslashes($name)), ".\x00..\x20");
562
+ // Replace dots in filenames to avoid security issues with servers
563
+ // that interpret multiple file extensions, e.g. "example.php.png":
564
+ $replacement = $this->options['replace_dots_in_filenames'];
565
+ if (!empty($replacement)) {
566
+ $parts = explode('.', $name);
567
+ if (count($parts) > 2) {
568
+ $ext = array_pop($parts);
569
+ $name = implode($replacement, $parts).'.'.$ext;
570
+ }
571
+ }
530
572
  // Use a timestamp for empty filenames:
531
573
  if (!$name) {
532
574
  $name = str_replace('.', '-', microtime(true));
@@ -535,7 +577,7 @@ class UploadHandler
535
577
  }
536
578
 
537
579
  protected function get_file_name($file_path, $name, $size, $type, $error,
538
- $index, $content_range) {
580
+ $index, $content_range) {
539
581
  $name = $this->trim_file_name($file_path, $name, $size, $type, $error,
540
582
  $index, $content_range);
541
583
  return $this->get_unique_filename(
@@ -769,25 +811,26 @@ class UploadHandler
769
811
  // Handle transparency in GIF and PNG images:
770
812
  switch ($type) {
771
813
  case 'gif':
772
- case 'png':
773
814
  imagecolortransparent($new_img, imagecolorallocate($new_img, 0, 0, 0));
815
+ break;
774
816
  case 'png':
817
+ imagecolortransparent($new_img, imagecolorallocate($new_img, 0, 0, 0));
775
818
  imagealphablending($new_img, false);
776
819
  imagesavealpha($new_img, true);
777
820
  break;
778
821
  }
779
822
  $success = imagecopyresampled(
780
- $new_img,
781
- $src_img,
782
- $dst_x,
783
- $dst_y,
784
- 0,
785
- 0,
786
- $new_width,
787
- $new_height,
788
- $img_width,
789
- $img_height
790
- ) && $write_func($new_img, $new_file_path, $image_quality);
823
+ $new_img,
824
+ $src_img,
825
+ $dst_x,
826
+ $dst_y,
827
+ 0,
828
+ 0,
829
+ $new_width,
830
+ $new_height,
831
+ $img_width,
832
+ $img_height
833
+ ) && $write_func($new_img, $new_file_path, $image_quality);
791
834
  $this->gd_set_image_object($file_path, $new_img);
792
835
  return $success;
793
836
  }
@@ -801,7 +844,12 @@ class UploadHandler
801
844
  $image->setResourceLimit($type, $limit);
802
845
  }
803
846
  }
804
- $image->readImage($file_path);
847
+ try {
848
+ $image->readImage($file_path);
849
+ } catch (ImagickException $e) {
850
+ error_log($e->getMessage());
851
+ return null;
852
+ }
805
853
  $this->image_objects[$file_path] = $image;
806
854
  }
807
855
  return $this->image_objects[$file_path];
@@ -858,6 +906,7 @@ class UploadHandler
858
906
  $file_path,
859
907
  !empty($options['crop']) || !empty($options['no_cache'])
860
908
  );
909
+ if (is_null($image)) return false;
861
910
  if ($image->getImageFormat() === 'GIF') {
862
911
  // Handle animated GIFs:
863
912
  $images = $image->coalesceImages();
@@ -870,32 +919,28 @@ class UploadHandler
870
919
  $image_oriented = false;
871
920
  if (!empty($options['auto_orient'])) {
872
921
  $image_oriented = $this->imagick_orient_image($image);
873
- }
874
-
875
- $image_resize = false;
922
+ }
923
+ $image_resize = false;
876
924
  $new_width = $max_width = $img_width = $image->getImageWidth();
877
- $new_height = $max_height = $img_height = $image->getImageHeight();
878
-
925
+ $new_height = $max_height = $img_height = $image->getImageHeight();
879
926
  // use isset(). User might be setting max_width = 0 (auto in regular resizing). Value 0 would be considered empty when you use empty()
880
927
  if (isset($options['max_width'])) {
881
- $image_resize = true;
882
- $new_width = $max_width = $options['max_width'];
928
+ $image_resize = true;
929
+ $new_width = $max_width = $options['max_width'];
883
930
  }
884
931
  if (isset($options['max_height'])) {
885
932
  $image_resize = true;
886
933
  $new_height = $max_height = $options['max_height'];
887
934
  }
888
-
889
935
  $image_strip = (isset($options['strip']) ? $options['strip'] : false);
890
-
891
- if ( !$image_oriented && ($max_width >= $img_width) && ($max_height >= $img_height) && !$image_strip && empty($options["jpeg_quality"]) ) {
936
+ if ( !$image_oriented && ($max_width >= $img_width) && ($max_height >= $img_height) && !$image_strip && empty($options["jpeg_quality"]) ) {
892
937
  if ($file_path !== $new_file_path) {
893
938
  return copy($file_path, $new_file_path);
894
939
  }
895
940
  return true;
896
941
  }
897
942
  $crop = (isset($options['crop']) ? $options['crop'] : false);
898
-
943
+
899
944
  if ($crop) {
900
945
  $x = 0;
901
946
  $y = 0;
@@ -1021,13 +1066,18 @@ class UploadHandler
1021
1066
  }
1022
1067
 
1023
1068
  protected function create_scaled_image($file_name, $version, $options) {
1024
- if ($this->options['image_library'] === 2) {
1025
- return $this->imagemagick_create_scaled_image($file_name, $version, $options);
1026
- }
1027
- if ($this->options['image_library'] && extension_loaded('imagick')) {
1028
- return $this->imagick_create_scaled_image($file_name, $version, $options);
1069
+ try {
1070
+ if ($this->options['image_library'] === 2) {
1071
+ return $this->imagemagick_create_scaled_image($file_name, $version, $options);
1072
+ }
1073
+ if ($this->options['image_library'] && extension_loaded('imagick')) {
1074
+ return $this->imagick_create_scaled_image($file_name, $version, $options);
1075
+ }
1076
+ return $this->gd_create_scaled_image($file_name, $version, $options);
1077
+ } catch (\Exception $e) {
1078
+ error_log($e->getMessage());
1079
+ return false;
1029
1080
  }
1030
- return $this->gd_create_scaled_image($file_name, $version, $options);
1031
1081
  }
1032
1082
 
1033
1083
  protected function destroy_image_object($file_path) {
@@ -1036,15 +1086,31 @@ class UploadHandler
1036
1086
  }
1037
1087
  }
1038
1088
 
1039
- protected function is_valid_image_file($file_path) {
1040
- if (!preg_match($this->options['image_file_types'], $file_path)) {
1041
- return false;
1089
+ protected function imagetype($file_path) {
1090
+ $fp = fopen($file_path, 'r');
1091
+ $data = fread($fp, 4);
1092
+ fclose($fp);
1093
+ // GIF: 47 49 46 38
1094
+ if ($data === 'GIF8') {
1095
+ return self::IMAGETYPE_GIF;
1096
+ }
1097
+ // JPG: FF D8 FF
1098
+ if (bin2hex(substr($data, 0, 3)) === 'ffd8ff') {
1099
+ return self::IMAGETYPE_JPEG;
1042
1100
  }
1043
- if (function_exists('exif_imagetype')) {
1044
- return @exif_imagetype($file_path);
1101
+ // PNG: 89 50 4E 47
1102
+ if (bin2hex(@$data[0]).substr($data, 1, 4) === '89PNG') {
1103
+ return self::IMAGETYPE_PNG;
1045
1104
  }
1046
- $image_info = $this->get_image_size($file_path);
1047
- return $image_info && $image_info[0] && $image_info[1];
1105
+ return false;
1106
+ }
1107
+
1108
+ protected function is_valid_image_file($file_path) {
1109
+ return !!$this->imagetype($file_path);
1110
+ }
1111
+
1112
+ protected function has_image_file_extension($file_path) {
1113
+ return !!preg_match('/\.(gif|jpe?g|png)$/i', $file_path);
1048
1114
  }
1049
1115
 
1050
1116
  protected function handle_image_file($file_path, $file) {
@@ -1065,20 +1131,20 @@ class UploadHandler
1065
1131
  }
1066
1132
  if (count($failed_versions)) {
1067
1133
  $file->error = $this->get_error_message('image_resize')
1068
- .' ('.implode($failed_versions, ', ').')';
1134
+ .' ('.implode(', ', $failed_versions).')';
1069
1135
  }
1070
1136
  // Free memory:
1071
1137
  $this->destroy_image_object($file_path);
1072
1138
  }
1073
1139
 
1074
1140
  protected function handle_file_upload($uploaded_file, $name, $size, $type, $error,
1075
- $index = null, $content_range = null) {
1141
+ $index = null, $content_range = null) {
1076
1142
  $file = new \stdClass();
1077
1143
  $file->name = $this->get_file_name($uploaded_file, $name, $size, $type, $error,
1078
1144
  $index, $content_range);
1079
1145
  $file->size = $this->fix_integer_overflow((int)$size);
1080
1146
  $file->type = $type;
1081
- if ($this->validate($uploaded_file, $file, $error, $index)) {
1147
+ if ($this->validate($uploaded_file, $file, $error, $index, $content_range)) {
1082
1148
  $this->handle_form_data($file, $index);
1083
1149
  $upload_dir = $this->get_upload_path();
1084
1150
  if (!is_dir($upload_dir)) {
@@ -1109,8 +1175,12 @@ class UploadHandler
1109
1175
  $file_size = $this->get_file_size($file_path, $append_file);
1110
1176
  if ($file_size === $file->size) {
1111
1177
  $file->url = $this->get_download_url($file->name);
1112
- if ($this->is_valid_image_file($file_path)) {
1113
- $this->handle_image_file($file_path, $file);
1178
+ if ($this->has_image_file_extension($file->name)) {
1179
+ if ($content_range && !$this->validate_image_file($file_path, $file, $error, $index)) {
1180
+ unlink($file_path);
1181
+ } else {
1182
+ $this->handle_image_file($file_path, $file);
1183
+ }
1114
1184
  }
1115
1185
  } else {
1116
1186
  $file->size = $file_size;
@@ -1196,11 +1266,11 @@ class UploadHandler
1196
1266
  switch (strtolower(pathinfo($file_path, PATHINFO_EXTENSION))) {
1197
1267
  case 'jpeg':
1198
1268
  case 'jpg':
1199
- return 'image/jpeg';
1269
+ return self::IMAGETYPE_JPEG;
1200
1270
  case 'png':
1201
- return 'image/png';
1271
+ return self::IMAGETYPE_PNG;
1202
1272
  case 'gif':
1203
- return 'image/gif';
1273
+ return self::IMAGETYPE_GIF;
1204
1274
  default:
1205
1275
  return '';
1206
1276
  }
@@ -1273,8 +1343,7 @@ class UploadHandler
1273
1343
  $json = json_encode($content);
1274
1344
  $redirect = stripslashes($this->get_post_param('redirect'));
1275
1345
  if ($redirect && preg_match($this->options['redirect_allow_target'], $redirect)) {
1276
- $this->header('Location: '.sprintf($redirect, rawurlencode($json)));
1277
- return;
1346
+ return $this->header('Location: '.sprintf($redirect, rawurlencode($json)));
1278
1347
  }
1279
1348
  $this->head();
1280
1349
  if ($this->get_server_var('HTTP_CONTENT_RANGE')) {
@@ -1342,7 +1411,7 @@ class UploadHandler
1342
1411
  $content_range_header = $this->get_server_var('HTTP_CONTENT_RANGE');
1343
1412
  $content_range = $content_range_header ?
1344
1413
  preg_split('/[^0-9]+/', $content_range_header) : null;
1345
- $size = $content_range ? $content_range[3] : null;
1414
+ $size = @$content_range[3];
1346
1415
  $files = array();
1347
1416
  if ($upload) {
1348
1417
  if (is_array($upload['tmp_name'])) {
@@ -1365,11 +1434,11 @@ class UploadHandler
1365
1434
  $files[] = $this->handle_file_upload(
1366
1435
  isset($upload['tmp_name']) ? $upload['tmp_name'] : null,
1367
1436
  $file_name ? $file_name : (isset($upload['name']) ?
1368
- $upload['name'] : null),
1437
+ $upload['name'] : null),
1369
1438
  $size ? $size : (isset($upload['size']) ?
1370
- $upload['size'] : $this->get_server_var('CONTENT_LENGTH')),
1439
+ $upload['size'] : $this->get_server_var('CONTENT_LENGTH')),
1371
1440
  isset($upload['type']) ?
1372
- $upload['type'] : $this->get_server_var('CONTENT_TYPE'),
1441
+ $upload['type'] : $this->get_server_var('CONTENT_TYPE'),
1373
1442
  isset($upload['error']) ? $upload['error'] : null,
1374
1443
  null,
1375
1444
  $content_range
@@ -1388,7 +1457,7 @@ class UploadHandler
1388
1457
  $response = array();
1389
1458
  foreach ($file_names as $file_name) {
1390
1459
  $file_path = $this->get_upload_path($file_name);
1391
- $success = is_file($file_path) && $file_name[0] !== '.' && unlink($file_path);
1460
+ $success = strlen($file_name) > 0 && $file_name[0] !== '.' && is_file($file_path) && unlink($file_path);
1392
1461
  if ($success) {
1393
1462
  foreach ($this->options['image_versions'] as $version => $options) {
1394
1463
  if (!empty($version)) {
@@ -0,0 +1,5 @@
1
+ max_execution_time = 300
2
+ memory_limit = 500M
3
+ post_max_size = 4G
4
+ upload_max_filesize = 4G
5
+ max_file_uploads = 50