card-mod-script 0.11.0

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