diff options
Diffstat (limited to 'library/blueimp_upload/server')
-rw-r--r-- | library/blueimp_upload/server/gae-go/app.yaml | 12 | ||||
-rw-r--r-- | library/blueimp_upload/server/gae-go/app/main.go | 361 | ||||
-rw-r--r-- | library/blueimp_upload/server/gae-go/static/robots.txt | 2 | ||||
-rw-r--r-- | library/blueimp_upload/server/gae-python/app.yaml | 17 | ||||
-rw-r--r-- | library/blueimp_upload/server/gae-python/main.py | 204 | ||||
-rw-r--r-- | library/blueimp_upload/server/gae-python/static/robots.txt | 2 | ||||
-rw-r--r-- | library/blueimp_upload/server/php/Dockerfile | 38 | ||||
-rwxr-xr-x | library/blueimp_upload/server/php/UploadHandler.php | 1411 | ||||
-rw-r--r-- | library/blueimp_upload/server/php/docker-compose.yml | 9 | ||||
-rw-r--r-- | library/blueimp_upload/server/php/files/.gitignore | 3 | ||||
-rw-r--r-- | library/blueimp_upload/server/php/files/.htaccess | 26 |
11 files changed, 0 insertions, 2085 deletions
diff --git a/library/blueimp_upload/server/gae-go/app.yaml b/library/blueimp_upload/server/gae-go/app.yaml deleted file mode 100644 index 2d09daa56..000000000 --- a/library/blueimp_upload/server/gae-go/app.yaml +++ /dev/null @@ -1,12 +0,0 @@ -application: jquery-file-upload -version: 2 -runtime: go -api_version: go1 - -handlers: -- url: /(favicon\.ico|robots\.txt) - static_files: static/\1 - upload: static/(.*) - expiration: '1d' -- url: /.* - script: _go_app diff --git a/library/blueimp_upload/server/gae-go/app/main.go b/library/blueimp_upload/server/gae-go/app/main.go deleted file mode 100644 index a92d128c0..000000000 --- a/library/blueimp_upload/server/gae-go/app/main.go +++ /dev/null @@ -1,361 +0,0 @@ -/* - * jQuery File Upload Plugin GAE Go Example - * https://github.com/blueimp/jQuery-File-Upload - * - * Copyright 2011, Sebastian Tschan - * https://blueimp.net - * - * Licensed under the MIT license: - * https://opensource.org/licenses/MIT - */ - -package app - -import ( - "bufio" - "bytes" - "encoding/json" - "fmt" - "github.com/disintegration/gift" - "golang.org/x/net/context" - "google.golang.org/appengine" - "google.golang.org/appengine/memcache" - "hash/crc32" - "image" - "image/gif" - "image/jpeg" - "image/png" - "io" - "log" - "mime/multipart" - "net/http" - "net/url" - "path/filepath" - "regexp" - "strings" -) - -const ( - WEBSITE = "https://blueimp.github.io/jQuery-File-Upload/" - MIN_FILE_SIZE = 1 // bytes - // Max file size is memcache limit (1MB) minus key size minus overhead: - MAX_FILE_SIZE = 999000 // bytes - IMAGE_TYPES = "image/(gif|p?jpeg|(x-)?png)" - ACCEPT_FILE_TYPES = IMAGE_TYPES - THUMB_MAX_WIDTH = 80 - THUMB_MAX_HEIGHT = 80 - EXPIRATION_TIME = 300 // seconds - // If empty, only allow redirects to the referer protocol+host. - // Set to a regexp string for custom pattern matching: - REDIRECT_ALLOW_TARGET = "" -) - -var ( - imageTypes = regexp.MustCompile(IMAGE_TYPES) - acceptFileTypes = regexp.MustCompile(ACCEPT_FILE_TYPES) - thumbSuffix = "." + fmt.Sprint(THUMB_MAX_WIDTH) + "x" + - fmt.Sprint(THUMB_MAX_HEIGHT) -) - -func escape(s string) string { - return strings.Replace(url.QueryEscape(s), "+", "%20", -1) -} - -func extractKey(r *http.Request) string { - // Use RequestURI instead of r.URL.Path, as we need the encoded form: - path := strings.Split(r.RequestURI, "?")[0] - // Also adjust double encoded slashes: - return strings.Replace(path[1:], "%252F", "%2F", -1) -} - -func check(err error) { - if err != nil { - panic(err) - } -} - -type FileInfo struct { - Key string `json:"-"` - ThumbnailKey string `json:"-"` - Url string `json:"url,omitempty"` - ThumbnailUrl string `json:"thumbnailUrl,omitempty"` - Name string `json:"name"` - Type string `json:"type"` - Size int64 `json:"size"` - Error string `json:"error,omitempty"` - DeleteUrl string `json:"deleteUrl,omitempty"` - DeleteType string `json:"deleteType,omitempty"` -} - -func (fi *FileInfo) ValidateType() (valid bool) { - if acceptFileTypes.MatchString(fi.Type) { - return true - } - fi.Error = "Filetype not allowed" - return false -} - -func (fi *FileInfo) ValidateSize() (valid bool) { - if fi.Size < MIN_FILE_SIZE { - fi.Error = "File is too small" - } else if fi.Size > MAX_FILE_SIZE { - fi.Error = "File is too big" - } else { - return true - } - return false -} - -func (fi *FileInfo) CreateUrls(r *http.Request, c context.Context) { - u := &url.URL{ - Scheme: r.URL.Scheme, - Host: appengine.DefaultVersionHostname(c), - Path: "/", - } - uString := u.String() - fi.Url = uString + fi.Key - fi.DeleteUrl = fi.Url - fi.DeleteType = "DELETE" - if fi.ThumbnailKey != "" { - fi.ThumbnailUrl = uString + fi.ThumbnailKey - } -} - -func (fi *FileInfo) SetKey(checksum uint32) { - fi.Key = escape(string(fi.Type)) + "/" + - escape(fmt.Sprint(checksum)) + "/" + - escape(string(fi.Name)) -} - -func (fi *FileInfo) createThumb(buffer *bytes.Buffer, c context.Context) { - if imageTypes.MatchString(fi.Type) { - src, _, err := image.Decode(bytes.NewReader(buffer.Bytes())) - check(err) - filter := gift.New(gift.ResizeToFit( - THUMB_MAX_WIDTH, - THUMB_MAX_HEIGHT, - gift.LanczosResampling, - )) - dst := image.NewNRGBA(filter.Bounds(src.Bounds())) - filter.Draw(dst, src) - buffer.Reset() - bWriter := bufio.NewWriter(buffer) - switch fi.Type { - case "image/jpeg", "image/pjpeg": - err = jpeg.Encode(bWriter, dst, nil) - case "image/gif": - err = gif.Encode(bWriter, dst, nil) - default: - err = png.Encode(bWriter, dst) - } - check(err) - bWriter.Flush() - thumbnailKey := fi.Key + thumbSuffix + filepath.Ext(fi.Name) - item := &memcache.Item{ - Key: thumbnailKey, - Value: buffer.Bytes(), - } - err = memcache.Set(c, item) - check(err) - fi.ThumbnailKey = thumbnailKey - } -} - -func handleUpload(r *http.Request, p *multipart.Part) (fi *FileInfo) { - fi = &FileInfo{ - Name: p.FileName(), - Type: p.Header.Get("Content-Type"), - } - if !fi.ValidateType() { - return - } - defer func() { - if rec := recover(); rec != nil { - log.Println(rec) - fi.Error = rec.(error).Error() - } - }() - var buffer bytes.Buffer - hash := crc32.NewIEEE() - mw := io.MultiWriter(&buffer, hash) - lr := &io.LimitedReader{R: p, N: MAX_FILE_SIZE + 1} - _, err := io.Copy(mw, lr) - check(err) - fi.Size = MAX_FILE_SIZE + 1 - lr.N - if !fi.ValidateSize() { - return - } - fi.SetKey(hash.Sum32()) - item := &memcache.Item{ - Key: fi.Key, - Value: buffer.Bytes(), - } - context := appengine.NewContext(r) - err = memcache.Set(context, item) - check(err) - fi.createThumb(&buffer, context) - fi.CreateUrls(r, context) - return -} - -func getFormValue(p *multipart.Part) string { - var b bytes.Buffer - io.CopyN(&b, p, int64(1<<20)) // Copy max: 1 MiB - return b.String() -} - -func handleUploads(r *http.Request) (fileInfos []*FileInfo) { - fileInfos = make([]*FileInfo, 0) - mr, err := r.MultipartReader() - check(err) - r.Form, err = url.ParseQuery(r.URL.RawQuery) - check(err) - part, err := mr.NextPart() - for err == nil { - if name := part.FormName(); name != "" { - if part.FileName() != "" { - fileInfos = append(fileInfos, handleUpload(r, part)) - } else { - r.Form[name] = append(r.Form[name], getFormValue(part)) - } - } - part, err = mr.NextPart() - } - return -} - -func validateRedirect(r *http.Request, redirect string) bool { - if redirect != "" { - var redirectAllowTarget *regexp.Regexp - if REDIRECT_ALLOW_TARGET != "" { - redirectAllowTarget = regexp.MustCompile(REDIRECT_ALLOW_TARGET) - } else { - referer := r.Referer() - if referer == "" { - return false - } - refererUrl, err := url.Parse(referer) - if err != nil { - return false - } - redirectAllowTarget = regexp.MustCompile("^" + regexp.QuoteMeta( - refererUrl.Scheme+"://"+refererUrl.Host+"/", - )) - } - return redirectAllowTarget.MatchString(redirect) - } - return false -} - -func get(w http.ResponseWriter, r *http.Request) { - if r.URL.Path == "/" { - http.Redirect(w, r, WEBSITE, http.StatusFound) - return - } - // Use RequestURI instead of r.URL.Path, as we need the encoded form: - key := extractKey(r) - parts := strings.Split(key, "/") - if len(parts) == 3 { - context := appengine.NewContext(r) - item, err := memcache.Get(context, key) - if err == nil { - w.Header().Add("X-Content-Type-Options", "nosniff") - contentType, _ := url.QueryUnescape(parts[0]) - if !imageTypes.MatchString(contentType) { - contentType = "application/octet-stream" - } - w.Header().Add("Content-Type", contentType) - w.Header().Add( - "Cache-Control", - fmt.Sprintf("public,max-age=%d", EXPIRATION_TIME), - ) - w.Write(item.Value) - return - } - } - http.Error(w, "404 Not Found", http.StatusNotFound) -} - -func post(w http.ResponseWriter, r *http.Request) { - result := make(map[string][]*FileInfo, 1) - result["files"] = handleUploads(r) - b, err := json.Marshal(result) - check(err) - if redirect := r.FormValue("redirect"); validateRedirect(r, redirect) { - if strings.Contains(redirect, "%s") { - redirect = fmt.Sprintf( - redirect, - escape(string(b)), - ) - } - http.Redirect(w, r, redirect, http.StatusFound) - return - } - w.Header().Set("Cache-Control", "no-cache") - jsonType := "application/json" - if strings.Index(r.Header.Get("Accept"), jsonType) != -1 { - w.Header().Set("Content-Type", jsonType) - } - fmt.Fprintln(w, string(b)) -} - -func delete(w http.ResponseWriter, r *http.Request) { - key := extractKey(r) - parts := strings.Split(key, "/") - if len(parts) == 3 { - result := make(map[string]bool, 1) - context := appengine.NewContext(r) - err := memcache.Delete(context, key) - if err == nil { - result[key] = true - contentType, _ := url.QueryUnescape(parts[0]) - if imageTypes.MatchString(contentType) { - thumbnailKey := key + thumbSuffix + filepath.Ext(parts[2]) - err := memcache.Delete(context, thumbnailKey) - if err == nil { - result[thumbnailKey] = true - } - } - } - w.Header().Set("Content-Type", "application/json") - b, err := json.Marshal(result) - check(err) - fmt.Fprintln(w, string(b)) - } else { - http.Error(w, "405 Method not allowed", http.StatusMethodNotAllowed) - } -} - -func handle(w http.ResponseWriter, r *http.Request) { - params, err := url.ParseQuery(r.URL.RawQuery) - check(err) - w.Header().Add("Access-Control-Allow-Origin", "*") - w.Header().Add( - "Access-Control-Allow-Methods", - "OPTIONS, HEAD, GET, POST, DELETE", - ) - w.Header().Add( - "Access-Control-Allow-Headers", - "Content-Type, Content-Range, Content-Disposition", - ) - switch r.Method { - case "OPTIONS", "HEAD": - return - case "GET": - get(w, r) - case "POST": - if len(params["_method"]) > 0 && params["_method"][0] == "DELETE" { - delete(w, r) - } else { - post(w, r) - } - case "DELETE": - delete(w, r) - default: - http.Error(w, "501 Not Implemented", http.StatusNotImplemented) - } -} - -func init() { - http.HandleFunc("/", handle) -} diff --git a/library/blueimp_upload/server/gae-go/static/robots.txt b/library/blueimp_upload/server/gae-go/static/robots.txt deleted file mode 100644 index eb0536286..000000000 --- a/library/blueimp_upload/server/gae-go/static/robots.txt +++ /dev/null @@ -1,2 +0,0 @@ -User-agent: * -Disallow: diff --git a/library/blueimp_upload/server/gae-python/app.yaml b/library/blueimp_upload/server/gae-python/app.yaml deleted file mode 100644 index 764449b74..000000000 --- a/library/blueimp_upload/server/gae-python/app.yaml +++ /dev/null @@ -1,17 +0,0 @@ -application: jquery-file-upload -version: 1 -runtime: python27 -api_version: 1 -threadsafe: true - -libraries: -- name: PIL - version: latest - -handlers: -- url: /(favicon\.ico|robots\.txt) - static_files: static/\1 - upload: static/(.*) - expiration: '1d' -- url: /.* - script: main.app diff --git a/library/blueimp_upload/server/gae-python/main.py b/library/blueimp_upload/server/gae-python/main.py deleted file mode 100644 index 1955ac00a..000000000 --- a/library/blueimp_upload/server/gae-python/main.py +++ /dev/null @@ -1,204 +0,0 @@ -# -*- coding: utf-8 -*- -# -# jQuery File Upload Plugin GAE Python Example -# https://github.com/blueimp/jQuery-File-Upload -# -# Copyright 2011, Sebastian Tschan -# https://blueimp.net -# -# Licensed under the MIT license: -# https://opensource.org/licenses/MIT -# - -from google.appengine.api import memcache, images -import json -import os -import re -import urllib -import webapp2 - -DEBUG=os.environ.get('SERVER_SOFTWARE', '').startswith('Dev') -WEBSITE = 'https://blueimp.github.io/jQuery-File-Upload/' -MIN_FILE_SIZE = 1 # bytes -# Max file size is memcache limit (1MB) minus key size minus overhead: -MAX_FILE_SIZE = 999000 # bytes -IMAGE_TYPES = re.compile('image/(gif|p?jpeg|(x-)?png)') -ACCEPT_FILE_TYPES = IMAGE_TYPES -THUMB_MAX_WIDTH = 80 -THUMB_MAX_HEIGHT = 80 -THUMB_SUFFIX = '.'+str(THUMB_MAX_WIDTH)+'x'+str(THUMB_MAX_HEIGHT)+'.png' -EXPIRATION_TIME = 300 # seconds -# If set to None, only allow redirects to the referer protocol+host. -# Set to a regexp for custom pattern matching against the redirect value: -REDIRECT_ALLOW_TARGET = None - -class CORSHandler(webapp2.RequestHandler): - def cors(self): - headers = self.response.headers - headers['Access-Control-Allow-Origin'] = '*' - headers['Access-Control-Allow-Methods'] =\ - 'OPTIONS, HEAD, GET, POST, DELETE' - headers['Access-Control-Allow-Headers'] =\ - 'Content-Type, Content-Range, Content-Disposition' - - def initialize(self, request, response): - super(CORSHandler, self).initialize(request, response) - self.cors() - - def json_stringify(self, obj): - return json.dumps(obj, separators=(',', ':')) - - def options(self, *args, **kwargs): - pass - -class UploadHandler(CORSHandler): - def validate(self, file): - if file['size'] < MIN_FILE_SIZE: - file['error'] = 'File is too small' - elif file['size'] > MAX_FILE_SIZE: - file['error'] = 'File is too big' - elif not ACCEPT_FILE_TYPES.match(file['type']): - file['error'] = 'Filetype not allowed' - else: - return True - return False - - def validate_redirect(self, redirect): - if redirect: - if REDIRECT_ALLOW_TARGET: - return REDIRECT_ALLOW_TARGET.match(redirect) - referer = self.request.headers['referer'] - if referer: - from urlparse import urlparse - parts = urlparse(referer) - redirect_allow_target = '^' + re.escape( - parts.scheme + '://' + parts.netloc + '/' - ) - return re.match(redirect_allow_target, redirect) - return False - - def get_file_size(self, file): - file.seek(0, 2) # Seek to the end of the file - size = file.tell() # Get the position of EOF - file.seek(0) # Reset the file position to the beginning - return size - - def write_blob(self, data, info): - key = urllib.quote(info['type'].encode('utf-8'), '') +\ - '/' + str(hash(data)) +\ - '/' + urllib.quote(info['name'].encode('utf-8'), '') - try: - memcache.set(key, data, time=EXPIRATION_TIME) - except: #Failed to add to memcache - return (None, None) - thumbnail_key = None - if IMAGE_TYPES.match(info['type']): - try: - img = images.Image(image_data=data) - img.resize( - width=THUMB_MAX_WIDTH, - height=THUMB_MAX_HEIGHT - ) - thumbnail_data = img.execute_transforms() - thumbnail_key = key + THUMB_SUFFIX - memcache.set( - thumbnail_key, - thumbnail_data, - time=EXPIRATION_TIME - ) - except: #Failed to resize Image or add to memcache - thumbnail_key = None - return (key, thumbnail_key) - - def handle_upload(self): - results = [] - for name, fieldStorage in self.request.POST.items(): - if type(fieldStorage) is unicode: - continue - result = {} - result['name'] = urllib.unquote(fieldStorage.filename) - result['type'] = fieldStorage.type - result['size'] = self.get_file_size(fieldStorage.file) - if self.validate(result): - key, thumbnail_key = self.write_blob( - fieldStorage.value, - result - ) - if key is not None: - result['url'] = self.request.host_url + '/' + key - result['deleteUrl'] = result['url'] - result['deleteType'] = 'DELETE' - if thumbnail_key is not None: - result['thumbnailUrl'] = self.request.host_url +\ - '/' + thumbnail_key - else: - result['error'] = 'Failed to store uploaded file.' - results.append(result) - return results - - def head(self): - pass - - def get(self): - self.redirect(WEBSITE) - - def post(self): - if (self.request.get('_method') == 'DELETE'): - return self.delete() - result = {'files': self.handle_upload()} - s = self.json_stringify(result) - redirect = self.request.get('redirect') - if self.validate_redirect(redirect): - return self.redirect(str( - redirect.replace('%s', urllib.quote(s, ''), 1) - )) - if 'application/json' in self.request.headers.get('Accept'): - self.response.headers['Content-Type'] = 'application/json' - self.response.write(s) - -class FileHandler(CORSHandler): - def normalize(self, str): - return urllib.quote(urllib.unquote(str), '') - - def get(self, content_type, data_hash, file_name): - content_type = self.normalize(content_type) - file_name = self.normalize(file_name) - key = content_type + '/' + data_hash + '/' + file_name - data = memcache.get(key) - if data is None: - return self.error(404) - # Prevent browsers from MIME-sniffing the content-type: - self.response.headers['X-Content-Type-Options'] = 'nosniff' - content_type = urllib.unquote(content_type) - if not IMAGE_TYPES.match(content_type): - # Force a download dialog for non-image types: - content_type = 'application/octet-stream' - elif file_name.endswith(THUMB_SUFFIX): - content_type = 'image/png' - self.response.headers['Content-Type'] = content_type - # Cache for the expiration time: - self.response.headers['Cache-Control'] = 'public,max-age=%d' \ - % EXPIRATION_TIME - self.response.write(data) - - def delete(self, content_type, data_hash, file_name): - content_type = self.normalize(content_type) - file_name = self.normalize(file_name) - key = content_type + '/' + data_hash + '/' + file_name - result = {key: memcache.delete(key)} - content_type = urllib.unquote(content_type) - if IMAGE_TYPES.match(content_type): - thumbnail_key = key + THUMB_SUFFIX - result[thumbnail_key] = memcache.delete(thumbnail_key) - if 'application/json' in self.request.headers.get('Accept'): - self.response.headers['Content-Type'] = 'application/json' - s = self.json_stringify(result) - self.response.write(s) - -app = webapp2.WSGIApplication( - [ - ('/', UploadHandler), - ('/(.+)/([^/]+)/([^/]+)', FileHandler) - ], - debug=DEBUG -) diff --git a/library/blueimp_upload/server/gae-python/static/robots.txt b/library/blueimp_upload/server/gae-python/static/robots.txt deleted file mode 100644 index eb0536286..000000000 --- a/library/blueimp_upload/server/gae-python/static/robots.txt +++ /dev/null @@ -1,2 +0,0 @@ -User-agent: * -Disallow: diff --git a/library/blueimp_upload/server/php/Dockerfile b/library/blueimp_upload/server/php/Dockerfile deleted file mode 100644 index 8633fee74..000000000 --- a/library/blueimp_upload/server/php/Dockerfile +++ /dev/null @@ -1,38 +0,0 @@ -FROM php:7-apache - -# Enable the Apache Headers module: -RUN ln -s /etc/apache2/mods-available/headers.load \ - /etc/apache2/mods-enabled/headers.load - -# Enable the Apache Rewrite module: -RUN ln -s /etc/apache2/mods-available/rewrite.load \ - /etc/apache2/mods-enabled/rewrite.load - -# Install GD, Imagick and ImageMagick as image conversion options: -RUN DEBIAN_FRONTEND=noninteractive \ - apt-get update && apt-get install -y --no-install-recommends \ - libpng-dev \ - libjpeg-dev \ - libmagickwand-dev \ - imagemagick \ - && pecl install \ - imagick \ - && docker-php-ext-enable \ - imagick \ - && docker-php-ext-configure \ - gd --with-jpeg-dir=/usr/include/ \ - && docker-php-ext-install \ - gd \ - # Uninstall obsolete packages: - && apt-get autoremove -y \ - libpng-dev \ - libjpeg-dev \ - libmagickwand-dev \ - # Remove obsolete files: - && apt-get clean \ - && rm -rf \ - /tmp/* \ - /usr/share/doc/* \ - /var/cache/* \ - /var/lib/apt/lists/* \ - /var/tmp/* diff --git a/library/blueimp_upload/server/php/UploadHandler.php b/library/blueimp_upload/server/php/UploadHandler.php deleted file mode 100755 index 285d046aa..000000000 --- a/library/blueimp_upload/server/php/UploadHandler.php +++ /dev/null @@ -1,1411 +0,0 @@ -<?php -/* - * jQuery File Upload Plugin PHP Class - * https://github.com/blueimp/jQuery-File-Upload - * - * Copyright 2010, Sebastian Tschan - * https://blueimp.net - * - * Licensed under the MIT license: - * https://opensource.org/licenses/MIT - */ - -class UploadHandler -{ - - protected $options; - - // PHP File Upload error message codes: - // http://php.net/manual/en/features.file-upload.errors.php - protected $error_messages = array( - 1 => 'The uploaded file exceeds the upload_max_filesize directive in php.ini', - 2 => 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form', - 3 => 'The uploaded file was only partially uploaded', - 4 => 'No file was uploaded', - 6 => 'Missing a temporary folder', - 7 => 'Failed to write file to disk', - 8 => 'A PHP extension stopped the file upload', - 'post_max_size' => 'The uploaded file exceeds the post_max_size directive in php.ini', - 'max_file_size' => 'File is too big', - 'min_file_size' => 'File is too small', - 'accept_file_types' => 'Filetype not allowed', - 'max_number_of_files' => 'Maximum number of files exceeded', - 'max_width' => 'Image exceeds maximum width', - 'min_width' => 'Image requires a minimum width', - 'max_height' => 'Image exceeds maximum height', - 'min_height' => 'Image requires a minimum height', - 'abort' => 'File upload aborted', - 'image_resize' => 'Failed to resize image' - ); - - protected $image_objects = array(); - - public function __construct($options = null, $initialize = true, $error_messages = null) { - $this->response = array(); - $this->options = array( - 'script_url' => $this->get_full_url().'/'.$this->basename($this->get_server_var('SCRIPT_NAME')), - 'upload_dir' => dirname($this->get_server_var('SCRIPT_FILENAME')).'/files/', - 'upload_url' => $this->get_full_url().'/files/', - 'input_stream' => 'php://input', - 'user_dirs' => false, - 'mkdir_mode' => 0755, - 'param_name' => 'files', - // Set the following option to 'POST', if your server does not support - // DELETE requests. This is a parameter sent to the client: - 'delete_type' => 'DELETE', - 'access_control_allow_origin' => '*', - 'access_control_allow_credentials' => false, - 'access_control_allow_methods' => array( - 'OPTIONS', - 'HEAD', - 'GET', - 'POST', - 'PUT', - 'PATCH', - 'DELETE' - ), - 'access_control_allow_headers' => array( - 'Content-Type', - 'Content-Range', - 'Content-Disposition' - ), - // By default, allow redirects to the referer protocol+host: - 'redirect_allow_target' => '/^'.preg_quote( - parse_url($this->get_server_var('HTTP_REFERER'), PHP_URL_SCHEME) - .'://' - .parse_url($this->get_server_var('HTTP_REFERER'), PHP_URL_HOST) - .'/', // Trailing slash to not match subdomains by mistake - '/' // preg_quote delimiter param - ).'/', - // Enable to provide file downloads via GET requests to the PHP script: - // 1. Set to 1 to download files via readfile method through PHP - // 2. Set to 2 to send a X-Sendfile header for lighttpd/Apache - // 3. Set to 3 to send a X-Accel-Redirect header for nginx - // If set to 2 or 3, adjust the upload_url option to the base path of - // the redirect parameter, e.g. '/files/'. - 'download_via_php' => false, - // Read files in chunks to avoid memory limits when download_via_php - // is enabled, set to 0 to disable chunked reading of files: - 'readfile_chunk_size' => 10 * 1024 * 1024, // 10 MiB - // Defines which files can be displayed inline when downloaded: - 'inline_file_types' => '/\.(gif|jpe?g|png)$/i', - // Defines which files (based on their names) are accepted for upload: - 'accept_file_types' => '/.+$/i', - // The php.ini settings upload_max_filesize and post_max_size - // take precedence over the following max_file_size setting: - 'max_file_size' => null, - 'min_file_size' => 1, - // The maximum number of files for the upload directory: - 'max_number_of_files' => null, - // Defines which files are handled as image files: - 'image_file_types' => '/\.(gif|jpe?g|png)$/i', - // Use exif_imagetype on all files to correct file extensions: - 'correct_image_extensions' => false, - // Image resolution restrictions: - 'max_width' => null, - 'max_height' => null, - 'min_width' => 1, - 'min_height' => 1, - // Set the following option to false to enable resumable uploads: - 'discard_aborted_uploads' => true, - // Set to 0 to use the GD library to scale and orient images, - // set to 1 to use imagick (if installed, falls back to GD), - // set to 2 to use the ImageMagick convert binary directly: - 'image_library' => 1, - // Uncomment the following to define an array of resource limits - // for imagick: - /* - 'imagick_resource_limits' => array( - imagick::RESOURCETYPE_MAP => 32, - imagick::RESOURCETYPE_MEMORY => 32 - ), - */ - // Command or path for to the ImageMagick convert binary: - 'convert_bin' => 'convert', - // Uncomment the following to add parameters in front of each - // ImageMagick convert call (the limit constraints seem only - // to have an effect if put in front): - /* - 'convert_params' => '-limit memory 32MiB -limit map 32MiB', - */ - // Command or path for to the ImageMagick identify binary: - 'identify_bin' => 'identify', - 'image_versions' => array( - // The empty image version key defines options for the original image. - // Keep in mind: these image manipulations are inherited by all other image versions from this point onwards. - // Also note that the property 'no_cache' is not inherited, since it's not a manipulation. - '' => array( - // Automatically rotate images based on EXIF meta data: - 'auto_orient' => true - ), - // You can add arrays to generate different versions. - // The name of the key is the name of the version (example: 'medium'). - // the array contains the options to apply. - /* - 'medium' => array( - 'max_width' => 800, - 'max_height' => 600 - ), - */ - 'thumbnail' => array( - // Uncomment the following to use a defined directory for the thumbnails - // instead of a subdirectory based on the version identifier. - // Make sure that this directory doesn't allow execution of files if you - // don't pose any restrictions on the type of uploaded files, e.g. by - // copying the .htaccess file from the files directory for Apache: - //'upload_dir' => dirname($this->get_server_var('SCRIPT_FILENAME')).'/thumb/', - //'upload_url' => $this->get_full_url().'/thumb/', - // Uncomment the following to force the max - // dimensions and e.g. create square thumbnails: - // 'auto_orient' => true, - // 'crop' => true, - // 'jpeg_quality' => 70, - // 'no_cache' => true, (there's a caching option, but this remembers thumbnail sizes from a previous action!) - // 'strip' => true, (this strips EXIF tags, such as geolocation) - 'max_width' => 80, // either specify width, or set to 0. Then width is automatically adjusted - keeping aspect ratio to a specified max_height. - 'max_height' => 80 // either specify height, or set to 0. Then height is automatically adjusted - keeping aspect ratio to a specified max_width. - ) - ), - 'print_response' => true - ); - if ($options) { - $this->options = $options + $this->options; - } - if ($error_messages) { - $this->error_messages = $error_messages + $this->error_messages; - } - if ($initialize) { - $this->initialize(); - } - } - - protected function initialize() { - switch ($this->get_server_var('REQUEST_METHOD')) { - case 'OPTIONS': - case 'HEAD': - $this->head(); - break; - case 'GET': - $this->get($this->options['print_response']); - break; - case 'PATCH': - case 'PUT': - case 'POST': - $this->post($this->options['print_response']); - break; - case 'DELETE': - $this->delete($this->options['print_response']); - break; - default: - $this->header('HTTP/1.1 405 Method Not Allowed'); - } - } - - protected function get_full_url() { - $https = !empty($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'], 'on') === 0 || - !empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && - strcasecmp($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') === 0; - return - ($https ? 'https://' : 'http://'). - (!empty($_SERVER['REMOTE_USER']) ? $_SERVER['REMOTE_USER'].'@' : ''). - (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : ($_SERVER['SERVER_NAME']. - ($https && $_SERVER['SERVER_PORT'] === 443 || - $_SERVER['SERVER_PORT'] === 80 ? '' : ':'.$_SERVER['SERVER_PORT']))). - substr($_SERVER['SCRIPT_NAME'],0, strrpos($_SERVER['SCRIPT_NAME'], '/')); - } - - protected function get_user_id() { - @session_start(); - return session_id(); - } - - protected function get_user_path() { - if ($this->options['user_dirs']) { - return $this->get_user_id().'/'; - } - return ''; - } - - protected function get_upload_path($file_name = null, $version = null) { - $file_name = $file_name ? $file_name : ''; - if (empty($version)) { - $version_path = ''; - } else { - $version_dir = @$this->options['image_versions'][$version]['upload_dir']; - if ($version_dir) { - return $version_dir.$this->get_user_path().$file_name; - } - $version_path = $version.'/'; - } - return $this->options['upload_dir'].$this->get_user_path() - .$version_path.$file_name; - } - - protected function get_query_separator($url) { - return strpos($url, '?') === false ? '?' : '&'; - } - - protected function get_download_url($file_name, $version = null, $direct = false) { - if (!$direct && $this->options['download_via_php']) { - $url = $this->options['script_url'] - .$this->get_query_separator($this->options['script_url']) - .$this->get_singular_param_name() - .'='.rawurlencode($file_name); - if ($version) { - $url .= '&version='.rawurlencode($version); - } - return $url.'&download=1'; - } - if (empty($version)) { - $version_path = ''; - } else { - $version_url = @$this->options['image_versions'][$version]['upload_url']; - if ($version_url) { - return $version_url.$this->get_user_path().rawurlencode($file_name); - } - $version_path = rawurlencode($version).'/'; - } - return $this->options['upload_url'].$this->get_user_path() - .$version_path.rawurlencode($file_name); - } - - protected function set_additional_file_properties($file) { - $file->deleteUrl = $this->options['script_url'] - .$this->get_query_separator($this->options['script_url']) - .$this->get_singular_param_name() - .'='.rawurlencode($file->name); - $file->deleteType = $this->options['delete_type']; - if ($file->deleteType !== 'DELETE') { - $file->deleteUrl .= '&_method=DELETE'; - } - if ($this->options['access_control_allow_credentials']) { - $file->deleteWithCredentials = true; - } - } - - // Fix for overflowing signed 32 bit integers, - // works for sizes up to 2^32-1 bytes (4 GiB - 1): - protected function fix_integer_overflow($size) { - if ($size < 0) { - $size += 2.0 * (PHP_INT_MAX + 1); - } - return $size; - } - - protected function get_file_size($file_path, $clear_stat_cache = false) { - if ($clear_stat_cache) { - if (version_compare(PHP_VERSION, '5.3.0') >= 0) { - clearstatcache(true, $file_path); - } else { - clearstatcache(); - } - } - return $this->fix_integer_overflow(filesize($file_path)); - } - - protected function is_valid_file_object($file_name) { - $file_path = $this->get_upload_path($file_name); - if (is_file($file_path) && $file_name[0] !== '.') { - return true; - } - return false; - } - - protected function get_file_object($file_name) { - if ($this->is_valid_file_object($file_name)) { - $file = new \stdClass(); - $file->name = $file_name; - $file->size = $this->get_file_size( - $this->get_upload_path($file_name) - ); - $file->url = $this->get_download_url($file->name); - foreach ($this->options['image_versions'] as $version => $options) { - if (!empty($version)) { - if (is_file($this->get_upload_path($file_name, $version))) { - $file->{$version.'Url'} = $this->get_download_url( - $file->name, - $version - ); - } - } - } - $this->set_additional_file_properties($file); - return $file; - } - return null; - } - - protected function get_file_objects($iteration_method = 'get_file_object') { - $upload_dir = $this->get_upload_path(); - if (!is_dir($upload_dir)) { - return array(); - } - return array_values(array_filter(array_map( - array($this, $iteration_method), - scandir($upload_dir) - ))); - } - - protected function count_file_objects() { - return count($this->get_file_objects('is_valid_file_object')); - } - - protected function get_error_message($error) { - return isset($this->error_messages[$error]) ? - $this->error_messages[$error] : $error; - } - - public function get_config_bytes($val) { - $val = trim($val); - $last = strtolower($val[strlen($val)-1]); - $val = (int)$val; - switch ($last) { - case 'g': - $val *= 1024; - case 'm': - $val *= 1024; - case 'k': - $val *= 1024; - } - return $this->fix_integer_overflow($val); - } - - protected function validate($uploaded_file, $file, $error, $index) { - if ($error) { - $file->error = $this->get_error_message($error); - return false; - } - $content_length = $this->fix_integer_overflow( - (int)$this->get_server_var('CONTENT_LENGTH') - ); - $post_max_size = $this->get_config_bytes(ini_get('post_max_size')); - if ($post_max_size && ($content_length > $post_max_size)) { - $file->error = $this->get_error_message('post_max_size'); - return false; - } - if (!preg_match($this->options['accept_file_types'], $file->name)) { - $file->error = $this->get_error_message('accept_file_types'); - return false; - } - if ($uploaded_file && is_uploaded_file($uploaded_file)) { - $file_size = $this->get_file_size($uploaded_file); - } else { - $file_size = $content_length; - } - if ($this->options['max_file_size'] && ( - $file_size > $this->options['max_file_size'] || - $file->size > $this->options['max_file_size']) - ) { - $file->error = $this->get_error_message('max_file_size'); - return false; - } - if ($this->options['min_file_size'] && - $file_size < $this->options['min_file_size']) { - $file->error = $this->get_error_message('min_file_size'); - return false; - } - if (is_int($this->options['max_number_of_files']) && - ($this->count_file_objects() >= $this->options['max_number_of_files']) && - // Ignore additional chunks of existing files: - !is_file($this->get_upload_path($file->name))) { - $file->error = $this->get_error_message('max_number_of_files'); - return false; - } - $max_width = @$this->options['max_width']; - $max_height = @$this->options['max_height']; - $min_width = @$this->options['min_width']; - $min_height = @$this->options['min_height']; - if (($max_width || $max_height || $min_width || $min_height) - && preg_match($this->options['image_file_types'], $file->name)) { - list($img_width, $img_height) = $this->get_image_size($uploaded_file); - - // If we are auto rotating the image by default, do the checks on - // the correct orientation - if ( - @$this->options['image_versions']['']['auto_orient'] && - function_exists('exif_read_data') && - ($exif = @exif_read_data($uploaded_file)) && - (((int) @$exif['Orientation']) >= 5) - ) { - $tmp = $img_width; - $img_width = $img_height; - $img_height = $tmp; - unset($tmp); - } - - } - if (!empty($img_width)) { - if ($max_width && $img_width > $max_width) { - $file->error = $this->get_error_message('max_width'); - return false; - } - if ($max_height && $img_height > $max_height) { - $file->error = $this->get_error_message('max_height'); - return false; - } - if ($min_width && $img_width < $min_width) { - $file->error = $this->get_error_message('min_width'); - return false; - } - if ($min_height && $img_height < $min_height) { - $file->error = $this->get_error_message('min_height'); - return false; - } - } - return true; - } - - protected function upcount_name_callback($matches) { - $index = isset($matches[1]) ? ((int)$matches[1]) + 1 : 1; - $ext = isset($matches[2]) ? $matches[2] : ''; - return ' ('.$index.')'.$ext; - } - - protected function upcount_name($name) { - return preg_replace_callback( - '/(?:(?: \(([\d]+)\))?(\.[^.]+))?$/', - array($this, 'upcount_name_callback'), - $name, - 1 - ); - } - - protected function get_unique_filename($file_path, $name, $size, $type, $error, - $index, $content_range) { - while(is_dir($this->get_upload_path($name))) { - $name = $this->upcount_name($name); - } - // Keep an existing filename if this is part of a chunked upload: - $uploaded_bytes = $this->fix_integer_overflow((int)$content_range[1]); - while (is_file($this->get_upload_path($name))) { - if ($uploaded_bytes === $this->get_file_size( - $this->get_upload_path($name))) { - break; - } - $name = $this->upcount_name($name); - } - return $name; - } - - protected function fix_file_extension($file_path, $name, $size, $type, $error, - $index, $content_range) { - // Add missing file extension for known image types: - if (strpos($name, '.') === false && - preg_match('/^image\/(gif|jpe?g|png)/', $type, $matches)) { - $name .= '.'.$matches[1]; - } - if ($this->options['correct_image_extensions'] && - function_exists('exif_imagetype')) { - switch (@exif_imagetype($file_path)){ - case IMAGETYPE_JPEG: - $extensions = array('jpg', 'jpeg'); - break; - case IMAGETYPE_PNG: - $extensions = array('png'); - break; - case IMAGETYPE_GIF: - $extensions = array('gif'); - break; - } - // Adjust incorrect image file extensions: - if (!empty($extensions)) { - $parts = explode('.', $name); - $extIndex = count($parts) - 1; - $ext = strtolower(@$parts[$extIndex]); - if (!in_array($ext, $extensions)) { - $parts[$extIndex] = $extensions[0]; - $name = implode('.', $parts); - } - } - } - return $name; - } - - protected function trim_file_name($file_path, $name, $size, $type, $error, - $index, $content_range) { - // Remove path information and dots around the filename, to prevent uploading - // into different directories or replacing hidden system files. - // Also remove control characters and spaces (\x00..\x20) around the filename: - $name = trim($this->basename(stripslashes($name)), ".\x00..\x20"); - // Use a timestamp for empty filenames: - if (!$name) { - $name = str_replace('.', '-', microtime(true)); - } - return $name; - } - - protected function get_file_name($file_path, $name, $size, $type, $error, - $index, $content_range) { - $name = $this->trim_file_name($file_path, $name, $size, $type, $error, - $index, $content_range); - return $this->get_unique_filename( - $file_path, - $this->fix_file_extension($file_path, $name, $size, $type, $error, - $index, $content_range), - $size, - $type, - $error, - $index, - $content_range - ); - } - - protected function get_scaled_image_file_paths($file_name, $version) { - $file_path = $this->get_upload_path($file_name); - if (!empty($version)) { - $version_dir = $this->get_upload_path(null, $version); - if (!is_dir($version_dir)) { - mkdir($version_dir, $this->options['mkdir_mode'], true); - } - $new_file_path = $version_dir.'/'.$file_name; - } else { - $new_file_path = $file_path; - } - return array($file_path, $new_file_path); - } - - protected function gd_get_image_object($file_path, $func, $no_cache = false) { - if (empty($this->image_objects[$file_path]) || $no_cache) { - $this->gd_destroy_image_object($file_path); - $this->image_objects[$file_path] = $func($file_path); - } - return $this->image_objects[$file_path]; - } - - protected function gd_set_image_object($file_path, $image) { - $this->gd_destroy_image_object($file_path); - $this->image_objects[$file_path] = $image; - } - - protected function gd_destroy_image_object($file_path) { - $image = (isset($this->image_objects[$file_path])) ? $this->image_objects[$file_path] : null ; - return $image && imagedestroy($image); - } - - protected function gd_imageflip($image, $mode) { - if (function_exists('imageflip')) { - return imageflip($image, $mode); - } - $new_width = $src_width = imagesx($image); - $new_height = $src_height = imagesy($image); - $new_img = imagecreatetruecolor($new_width, $new_height); - $src_x = 0; - $src_y = 0; - switch ($mode) { - case '1': // flip on the horizontal axis - $src_y = $new_height - 1; - $src_height = -$new_height; - break; - case '2': // flip on the vertical axis - $src_x = $new_width - 1; - $src_width = -$new_width; - break; - case '3': // flip on both axes - $src_y = $new_height - 1; - $src_height = -$new_height; - $src_x = $new_width - 1; - $src_width = -$new_width; - break; - default: - return $image; - } - imagecopyresampled( - $new_img, - $image, - 0, - 0, - $src_x, - $src_y, - $new_width, - $new_height, - $src_width, - $src_height - ); - return $new_img; - } - - protected function gd_orient_image($file_path, $src_img) { - if (!function_exists('exif_read_data')) { - return false; - } - $exif = @exif_read_data($file_path); - if ($exif === false) { - return false; - } - $orientation = (int)@$exif['Orientation']; - if ($orientation < 2 || $orientation > 8) { - return false; - } - switch ($orientation) { - case 2: - $new_img = $this->gd_imageflip( - $src_img, - defined('IMG_FLIP_VERTICAL') ? IMG_FLIP_VERTICAL : 2 - ); - break; - case 3: - $new_img = imagerotate($src_img, 180, 0); - break; - case 4: - $new_img = $this->gd_imageflip( - $src_img, - defined('IMG_FLIP_HORIZONTAL') ? IMG_FLIP_HORIZONTAL : 1 - ); - break; - case 5: - $tmp_img = $this->gd_imageflip( - $src_img, - defined('IMG_FLIP_HORIZONTAL') ? IMG_FLIP_HORIZONTAL : 1 - ); - $new_img = imagerotate($tmp_img, 270, 0); - imagedestroy($tmp_img); - break; - case 6: - $new_img = imagerotate($src_img, 270, 0); - break; - case 7: - $tmp_img = $this->gd_imageflip( - $src_img, - defined('IMG_FLIP_VERTICAL') ? IMG_FLIP_VERTICAL : 2 - ); - $new_img = imagerotate($tmp_img, 270, 0); - imagedestroy($tmp_img); - break; - case 8: - $new_img = imagerotate($src_img, 90, 0); - break; - default: - return false; - } - $this->gd_set_image_object($file_path, $new_img); - return true; - } - - protected function gd_create_scaled_image($file_name, $version, $options) { - if (!function_exists('imagecreatetruecolor')) { - error_log('Function not found: imagecreatetruecolor'); - return false; - } - list($file_path, $new_file_path) = - $this->get_scaled_image_file_paths($file_name, $version); - $type = strtolower(substr(strrchr($file_name, '.'), 1)); - switch ($type) { - case 'jpg': - case 'jpeg': - $src_func = 'imagecreatefromjpeg'; - $write_func = 'imagejpeg'; - $image_quality = isset($options['jpeg_quality']) ? - $options['jpeg_quality'] : 75; - break; - case 'gif': - $src_func = 'imagecreatefromgif'; - $write_func = 'imagegif'; - $image_quality = null; - break; - case 'png': - $src_func = 'imagecreatefrompng'; - $write_func = 'imagepng'; - $image_quality = isset($options['png_quality']) ? - $options['png_quality'] : 9; - break; - default: - return false; - } - $src_img = $this->gd_get_image_object( - $file_path, - $src_func, - !empty($options['no_cache']) - ); - $image_oriented = false; - if (!empty($options['auto_orient']) && $this->gd_orient_image( - $file_path, - $src_img - )) { - $image_oriented = true; - $src_img = $this->gd_get_image_object( - $file_path, - $src_func - ); - } - $max_width = $img_width = imagesx($src_img); - $max_height = $img_height = imagesy($src_img); - if (!empty($options['max_width'])) { - $max_width = $options['max_width']; - } - if (!empty($options['max_height'])) { - $max_height = $options['max_height']; - } - $scale = min( - $max_width / $img_width, - $max_height / $img_height - ); - if ($scale >= 1) { - if ($image_oriented) { - return $write_func($src_img, $new_file_path, $image_quality); - } - if ($file_path !== $new_file_path) { - return copy($file_path, $new_file_path); - } - return true; - } - if (empty($options['crop'])) { - $new_width = $img_width * $scale; - $new_height = $img_height * $scale; - $dst_x = 0; - $dst_y = 0; - $new_img = imagecreatetruecolor($new_width, $new_height); - } else { - if (($img_width / $img_height) >= ($max_width / $max_height)) { - $new_width = $img_width / ($img_height / $max_height); - $new_height = $max_height; - } else { - $new_width = $max_width; - $new_height = $img_height / ($img_width / $max_width); - } - $dst_x = 0 - ($new_width - $max_width) / 2; - $dst_y = 0 - ($new_height - $max_height) / 2; - $new_img = imagecreatetruecolor($max_width, $max_height); - } - // Handle transparency in GIF and PNG images: - switch ($type) { - case 'gif': - case 'png': - imagecolortransparent($new_img, imagecolorallocate($new_img, 0, 0, 0)); - case 'png': - imagealphablending($new_img, false); - imagesavealpha($new_img, true); - break; - } - $success = imagecopyresampled( - $new_img, - $src_img, - $dst_x, - $dst_y, - 0, - 0, - $new_width, - $new_height, - $img_width, - $img_height - ) && $write_func($new_img, $new_file_path, $image_quality); - $this->gd_set_image_object($file_path, $new_img); - return $success; - } - - protected function imagick_get_image_object($file_path, $no_cache = false) { - if (empty($this->image_objects[$file_path]) || $no_cache) { - $this->imagick_destroy_image_object($file_path); - $image = new \Imagick(); - if (!empty($this->options['imagick_resource_limits'])) { - foreach ($this->options['imagick_resource_limits'] as $type => $limit) { - $image->setResourceLimit($type, $limit); - } - } - $image->readImage($file_path); - $this->image_objects[$file_path] = $image; - } - return $this->image_objects[$file_path]; - } - - protected function imagick_set_image_object($file_path, $image) { - $this->imagick_destroy_image_object($file_path); - $this->image_objects[$file_path] = $image; - } - - protected function imagick_destroy_image_object($file_path) { - $image = (isset($this->image_objects[$file_path])) ? $this->image_objects[$file_path] : null ; - return $image && $image->destroy(); - } - - protected function imagick_orient_image($image) { - $orientation = $image->getImageOrientation(); - $background = new \ImagickPixel('none'); - switch ($orientation) { - case \imagick::ORIENTATION_TOPRIGHT: // 2 - $image->flopImage(); // horizontal flop around y-axis - break; - case \imagick::ORIENTATION_BOTTOMRIGHT: // 3 - $image->rotateImage($background, 180); - break; - case \imagick::ORIENTATION_BOTTOMLEFT: // 4 - $image->flipImage(); // vertical flip around x-axis - break; - case \imagick::ORIENTATION_LEFTTOP: // 5 - $image->flopImage(); // horizontal flop around y-axis - $image->rotateImage($background, 270); - break; - case \imagick::ORIENTATION_RIGHTTOP: // 6 - $image->rotateImage($background, 90); - break; - case \imagick::ORIENTATION_RIGHTBOTTOM: // 7 - $image->flipImage(); // vertical flip around x-axis - $image->rotateImage($background, 270); - break; - case \imagick::ORIENTATION_LEFTBOTTOM: // 8 - $image->rotateImage($background, 270); - break; - default: - return false; - } - $image->setImageOrientation(\imagick::ORIENTATION_TOPLEFT); // 1 - return true; - } - - protected function imagick_create_scaled_image($file_name, $version, $options) { - list($file_path, $new_file_path) = - $this->get_scaled_image_file_paths($file_name, $version); - $image = $this->imagick_get_image_object( - $file_path, - !empty($options['crop']) || !empty($options['no_cache']) - ); - if ($image->getImageFormat() === 'GIF') { - // Handle animated GIFs: - $images = $image->coalesceImages(); - foreach ($images as $frame) { - $image = $frame; - $this->imagick_set_image_object($file_name, $image); - break; - } - } - $image_oriented = false; - if (!empty($options['auto_orient'])) { - $image_oriented = $this->imagick_orient_image($image); - } - - $image_resize = false; - $new_width = $max_width = $img_width = $image->getImageWidth(); - $new_height = $max_height = $img_height = $image->getImageHeight(); - - // use isset(). User might be setting max_width = 0 (auto in regular resizing). Value 0 would be considered empty when you use empty() - if (isset($options['max_width'])) { - $image_resize = true; - $new_width = $max_width = $options['max_width']; - } - if (isset($options['max_height'])) { - $image_resize = true; - $new_height = $max_height = $options['max_height']; - } - - $image_strip = (isset($options['strip']) ? $options['strip'] : false); - - if ( !$image_oriented && ($max_width >= $img_width) && ($max_height >= $img_height) && !$image_strip && empty($options["jpeg_quality"]) ) { - if ($file_path !== $new_file_path) { - return copy($file_path, $new_file_path); - } - return true; - } - $crop = (isset($options['crop']) ? $options['crop'] : false); - - if ($crop) { - $x = 0; - $y = 0; - if (($img_width / $img_height) >= ($max_width / $max_height)) { - $new_width = 0; // Enables proportional scaling based on max_height - $x = ($img_width / ($img_height / $max_height) - $max_width) / 2; - } else { - $new_height = 0; // Enables proportional scaling based on max_width - $y = ($img_height / ($img_width / $max_width) - $max_height) / 2; - } - } - $success = $image->resizeImage( - $new_width, - $new_height, - isset($options['filter']) ? $options['filter'] : \imagick::FILTER_LANCZOS, - isset($options['blur']) ? $options['blur'] : 1, - $new_width && $new_height // fit image into constraints if not to be cropped - ); - if ($success && $crop) { - $success = $image->cropImage( - $max_width, - $max_height, - $x, - $y - ); - if ($success) { - $success = $image->setImagePage($max_width, $max_height, 0, 0); - } - } - $type = strtolower(substr(strrchr($file_name, '.'), 1)); - switch ($type) { - case 'jpg': - case 'jpeg': - if (!empty($options['jpeg_quality'])) { - $image->setImageCompression(\imagick::COMPRESSION_JPEG); - $image->setImageCompressionQuality($options['jpeg_quality']); - } - break; - } - if ( $image_strip ) { - $image->stripImage(); - } - return $success && $image->writeImage($new_file_path); - } - - protected function imagemagick_create_scaled_image($file_name, $version, $options) { - list($file_path, $new_file_path) = - $this->get_scaled_image_file_paths($file_name, $version); - $resize = @$options['max_width'] - .(empty($options['max_height']) ? '' : 'X'.$options['max_height']); - if (!$resize && empty($options['auto_orient'])) { - if ($file_path !== $new_file_path) { - return copy($file_path, $new_file_path); - } - return true; - } - $cmd = $this->options['convert_bin']; - if (!empty($this->options['convert_params'])) { - $cmd .= ' '.$this->options['convert_params']; - } - $cmd .= ' '.escapeshellarg($file_path); - if (!empty($options['auto_orient'])) { - $cmd .= ' -auto-orient'; - } - if ($resize) { - // Handle animated GIFs: - $cmd .= ' -coalesce'; - if (empty($options['crop'])) { - $cmd .= ' -resize '.escapeshellarg($resize.'>'); - } else { - $cmd .= ' -resize '.escapeshellarg($resize.'^'); - $cmd .= ' -gravity center'; - $cmd .= ' -crop '.escapeshellarg($resize.'+0+0'); - } - // Make sure the page dimensions are correct (fixes offsets of animated GIFs): - $cmd .= ' +repage'; - } - if (!empty($options['convert_params'])) { - $cmd .= ' '.$options['convert_params']; - } - $cmd .= ' '.escapeshellarg($new_file_path); - exec($cmd, $output, $error); - if ($error) { - error_log(implode('\n', $output)); - return false; - } - return true; - } - - protected function get_image_size($file_path) { - if ($this->options['image_library']) { - if (extension_loaded('imagick')) { - $image = new \Imagick(); - try { - if (@$image->pingImage($file_path)) { - $dimensions = array($image->getImageWidth(), $image->getImageHeight()); - $image->destroy(); - return $dimensions; - } - return false; - } catch (\Exception $e) { - error_log($e->getMessage()); - } - } - if ($this->options['image_library'] === 2) { - $cmd = $this->options['identify_bin']; - $cmd .= ' -ping '.escapeshellarg($file_path); - exec($cmd, $output, $error); - if (!$error && !empty($output)) { - // image.jpg JPEG 1920x1080 1920x1080+0+0 8-bit sRGB 465KB 0.000u 0:00.000 - $infos = preg_split('/\s+/', substr($output[0], strlen($file_path))); - $dimensions = preg_split('/x/', $infos[2]); - return $dimensions; - } - return false; - } - } - if (!function_exists('getimagesize')) { - error_log('Function not found: getimagesize'); - return false; - } - return @getimagesize($file_path); - } - - protected function create_scaled_image($file_name, $version, $options) { - if ($this->options['image_library'] === 2) { - return $this->imagemagick_create_scaled_image($file_name, $version, $options); - } - if ($this->options['image_library'] && extension_loaded('imagick')) { - return $this->imagick_create_scaled_image($file_name, $version, $options); - } - return $this->gd_create_scaled_image($file_name, $version, $options); - } - - protected function destroy_image_object($file_path) { - if ($this->options['image_library'] && extension_loaded('imagick')) { - return $this->imagick_destroy_image_object($file_path); - } - } - - protected function is_valid_image_file($file_path) { - if (!preg_match($this->options['image_file_types'], $file_path)) { - return false; - } - if (function_exists('exif_imagetype')) { - return @exif_imagetype($file_path); - } - $image_info = $this->get_image_size($file_path); - return $image_info && $image_info[0] && $image_info[1]; - } - - protected function handle_image_file($file_path, $file) { - $failed_versions = array(); - foreach ($this->options['image_versions'] as $version => $options) { - if ($this->create_scaled_image($file->name, $version, $options)) { - if (!empty($version)) { - $file->{$version.'Url'} = $this->get_download_url( - $file->name, - $version - ); - } else { - $file->size = $this->get_file_size($file_path, true); - } - } else { - $failed_versions[] = $version ? $version : 'original'; - } - } - if (count($failed_versions)) { - $file->error = $this->get_error_message('image_resize') - .' ('.implode($failed_versions, ', ').')'; - } - // Free memory: - $this->destroy_image_object($file_path); - } - - protected function handle_file_upload($uploaded_file, $name, $size, $type, $error, - $index = null, $content_range = null) { - $file = new \stdClass(); - $file->name = $this->get_file_name($uploaded_file, $name, $size, $type, $error, - $index, $content_range); - $file->size = $this->fix_integer_overflow((int)$size); - $file->type = $type; - if ($this->validate($uploaded_file, $file, $error, $index)) { - $this->handle_form_data($file, $index); - $upload_dir = $this->get_upload_path(); - if (!is_dir($upload_dir)) { - mkdir($upload_dir, $this->options['mkdir_mode'], true); - } - $file_path = $this->get_upload_path($file->name); - $append_file = $content_range && is_file($file_path) && - $file->size > $this->get_file_size($file_path); - if ($uploaded_file && is_uploaded_file($uploaded_file)) { - // multipart/formdata uploads (POST method uploads) - if ($append_file) { - file_put_contents( - $file_path, - fopen($uploaded_file, 'r'), - FILE_APPEND - ); - } else { - move_uploaded_file($uploaded_file, $file_path); - } - } else { - // Non-multipart uploads (PUT method support) - file_put_contents( - $file_path, - fopen($this->options['input_stream'], 'r'), - $append_file ? FILE_APPEND : 0 - ); - } - $file_size = $this->get_file_size($file_path, $append_file); - if ($file_size === $file->size) { - $file->url = $this->get_download_url($file->name); - if ($this->is_valid_image_file($file_path)) { - $this->handle_image_file($file_path, $file); - } - } else { - $file->size = $file_size; - if (!$content_range && $this->options['discard_aborted_uploads']) { - unlink($file_path); - $file->error = $this->get_error_message('abort'); - } - } - $this->set_additional_file_properties($file); - } - return $file; - } - - protected function readfile($file_path) { - $file_size = $this->get_file_size($file_path); - $chunk_size = $this->options['readfile_chunk_size']; - if ($chunk_size && $file_size > $chunk_size) { - $handle = fopen($file_path, 'rb'); - while (!feof($handle)) { - echo fread($handle, $chunk_size); - @ob_flush(); - @flush(); - } - fclose($handle); - return $file_size; - } - return readfile($file_path); - } - - protected function body($str) { - echo $str; - } - - protected function header($str) { - header($str); - } - - protected function get_upload_data($id) { - return @$_FILES[$id]; - } - - protected function get_post_param($id) { - return @$_POST[$id]; - } - - protected function get_query_param($id) { - return @$_GET[$id]; - } - - protected function get_server_var($id) { - return @$_SERVER[$id]; - } - - protected function handle_form_data($file, $index) { - // Handle form data, e.g. $_POST['description'][$index] - } - - protected function get_version_param() { - return $this->basename(stripslashes($this->get_query_param('version'))); - } - - protected function get_singular_param_name() { - return substr($this->options['param_name'], 0, -1); - } - - protected function get_file_name_param() { - $name = $this->get_singular_param_name(); - return $this->basename(stripslashes($this->get_query_param($name))); - } - - protected function get_file_names_params() { - $params = $this->get_query_param($this->options['param_name']); - if (!$params) { - return null; - } - foreach ($params as $key => $value) { - $params[$key] = $this->basename(stripslashes($value)); - } - return $params; - } - - protected function get_file_type($file_path) { - switch (strtolower(pathinfo($file_path, PATHINFO_EXTENSION))) { - case 'jpeg': - case 'jpg': - return 'image/jpeg'; - case 'png': - return 'image/png'; - case 'gif': - return 'image/gif'; - default: - return ''; - } - } - - protected function download() { - switch ($this->options['download_via_php']) { - case 1: - $redirect_header = null; - break; - case 2: - $redirect_header = 'X-Sendfile'; - break; - case 3: - $redirect_header = 'X-Accel-Redirect'; - break; - default: - return $this->header('HTTP/1.1 403 Forbidden'); - } - $file_name = $this->get_file_name_param(); - if (!$this->is_valid_file_object($file_name)) { - return $this->header('HTTP/1.1 404 Not Found'); - } - if ($redirect_header) { - return $this->header( - $redirect_header.': '.$this->get_download_url( - $file_name, - $this->get_version_param(), - true - ) - ); - } - $file_path = $this->get_upload_path($file_name, $this->get_version_param()); - // Prevent browsers from MIME-sniffing the content-type: - $this->header('X-Content-Type-Options: nosniff'); - if (!preg_match($this->options['inline_file_types'], $file_name)) { - $this->header('Content-Type: application/octet-stream'); - $this->header('Content-Disposition: attachment; filename="'.$file_name.'"'); - } else { - $this->header('Content-Type: '.$this->get_file_type($file_path)); - $this->header('Content-Disposition: inline; filename="'.$file_name.'"'); - } - $this->header('Content-Length: '.$this->get_file_size($file_path)); - $this->header('Last-Modified: '.gmdate('D, d M Y H:i:s T', filemtime($file_path))); - $this->readfile($file_path); - } - - protected function send_content_type_header() { - $this->header('Vary: Accept'); - if (strpos($this->get_server_var('HTTP_ACCEPT'), 'application/json') !== false) { - $this->header('Content-type: application/json'); - } else { - $this->header('Content-type: text/plain'); - } - } - - protected function send_access_control_headers() { - $this->header('Access-Control-Allow-Origin: '.$this->options['access_control_allow_origin']); - $this->header('Access-Control-Allow-Credentials: ' - .($this->options['access_control_allow_credentials'] ? 'true' : 'false')); - $this->header('Access-Control-Allow-Methods: ' - .implode(', ', $this->options['access_control_allow_methods'])); - $this->header('Access-Control-Allow-Headers: ' - .implode(', ', $this->options['access_control_allow_headers'])); - } - - public function generate_response($content, $print_response = true) { - $this->response = $content; - if ($print_response) { - $json = json_encode($content); - $redirect = stripslashes($this->get_post_param('redirect')); - if ($redirect && preg_match($this->options['redirect_allow_target'], $redirect)) { - $this->header('Location: '.sprintf($redirect, rawurlencode($json))); - return; - } - $this->head(); - if ($this->get_server_var('HTTP_CONTENT_RANGE')) { - $files = isset($content[$this->options['param_name']]) ? - $content[$this->options['param_name']] : null; - if ($files && is_array($files) && is_object($files[0]) && $files[0]->size) { - $this->header('Range: 0-'.( - $this->fix_integer_overflow((int)$files[0]->size) - 1 - )); - } - } - $this->body($json); - } - return $content; - } - - public function get_response () { - return $this->response; - } - - public function head() { - $this->header('Pragma: no-cache'); - $this->header('Cache-Control: no-store, no-cache, must-revalidate'); - $this->header('Content-Disposition: inline; filename="files.json"'); - // Prevent Internet Explorer from MIME-sniffing the content-type: - $this->header('X-Content-Type-Options: nosniff'); - if ($this->options['access_control_allow_origin']) { - $this->send_access_control_headers(); - } - $this->send_content_type_header(); - } - - public function get($print_response = true) { - if ($print_response && $this->get_query_param('download')) { - return $this->download(); - } - $file_name = $this->get_file_name_param(); - if ($file_name) { - $response = array( - $this->get_singular_param_name() => $this->get_file_object($file_name) - ); - } else { - $response = array( - $this->options['param_name'] => $this->get_file_objects() - ); - } - return $this->generate_response($response, $print_response); - } - - public function post($print_response = true) { - if ($this->get_query_param('_method') === 'DELETE') { - return $this->delete($print_response); - } - $upload = $this->get_upload_data($this->options['param_name']); - // Parse the Content-Disposition header, if available: - $content_disposition_header = $this->get_server_var('HTTP_CONTENT_DISPOSITION'); - $file_name = $content_disposition_header ? - rawurldecode(preg_replace( - '/(^[^"]+")|("$)/', - '', - $content_disposition_header - )) : null; - // Parse the Content-Range header, which has the following form: - // Content-Range: bytes 0-524287/2000000 - $content_range_header = $this->get_server_var('HTTP_CONTENT_RANGE'); - $content_range = $content_range_header ? - preg_split('/[^0-9]+/', $content_range_header) : null; - $size = $content_range ? $content_range[3] : null; - $files = array(); - if ($upload) { - if (is_array($upload['tmp_name'])) { - // param_name is an array identifier like "files[]", - // $upload is a multi-dimensional array: - foreach ($upload['tmp_name'] as $index => $value) { - $files[] = $this->handle_file_upload( - $upload['tmp_name'][$index], - $file_name ? $file_name : $upload['name'][$index], - $size ? $size : $upload['size'][$index], - $upload['type'][$index], - $upload['error'][$index], - $index, - $content_range - ); - } - } else { - // param_name is a single object identifier like "file", - // $upload is a one-dimensional array: - $files[] = $this->handle_file_upload( - isset($upload['tmp_name']) ? $upload['tmp_name'] : null, - $file_name ? $file_name : (isset($upload['name']) ? - $upload['name'] : null), - $size ? $size : (isset($upload['size']) ? - $upload['size'] : $this->get_server_var('CONTENT_LENGTH')), - isset($upload['type']) ? - $upload['type'] : $this->get_server_var('CONTENT_TYPE'), - isset($upload['error']) ? $upload['error'] : null, - null, - $content_range - ); - } - } - $response = array($this->options['param_name'] => $files); - return $this->generate_response($response, $print_response); - } - - public function delete($print_response = true) { - $file_names = $this->get_file_names_params(); - if (empty($file_names)) { - $file_names = array($this->get_file_name_param()); - } - $response = array(); - foreach ($file_names as $file_name) { - $file_path = $this->get_upload_path($file_name); - $success = is_file($file_path) && $file_name[0] !== '.' && unlink($file_path); - if ($success) { - foreach ($this->options['image_versions'] as $version => $options) { - if (!empty($version)) { - $file = $this->get_upload_path($file_name, $version); - if (is_file($file)) { - unlink($file); - } - } - } - } - $response[$file_name] = $success; - } - return $this->generate_response($response, $print_response); - } - - protected function basename($filepath, $suffix = null) { - $splited = preg_split('/\//', rtrim ($filepath, '/ ')); - return substr(basename('X'.$splited[count($splited)-1], $suffix), 1); - } -} diff --git a/library/blueimp_upload/server/php/docker-compose.yml b/library/blueimp_upload/server/php/docker-compose.yml deleted file mode 100644 index 74eabf7dc..000000000 --- a/library/blueimp_upload/server/php/docker-compose.yml +++ /dev/null @@ -1,9 +0,0 @@ -version: '2.3' -services: - apache: - build: ./ - network_mode: bridge - ports: - - "80:80" - volumes: - - "../../:/var/www/html" diff --git a/library/blueimp_upload/server/php/files/.gitignore b/library/blueimp_upload/server/php/files/.gitignore deleted file mode 100644 index e24a60fae..000000000 --- a/library/blueimp_upload/server/php/files/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -* -!.gitignore -!.htaccess diff --git a/library/blueimp_upload/server/php/files/.htaccess b/library/blueimp_upload/server/php/files/.htaccess deleted file mode 100644 index 6f454afb9..000000000 --- a/library/blueimp_upload/server/php/files/.htaccess +++ /dev/null @@ -1,26 +0,0 @@ -# To enable the Headers module, execute the following command and reload Apache: -# sudo a2enmod headers - -# The following directives prevent the execution of script files -# in the context of the website. -# They also force the content-type application/octet-stream and -# force browsers to display a download dialog for non-image files. -SetHandler default-handler -ForceType application/octet-stream -Header set Content-Disposition attachment - -# The following unsets the forced type and Content-Disposition headers -# for known image files: -<FilesMatch "(?i)\.(gif|jpe?g|png)$"> - ForceType none - Header unset Content-Disposition -</FilesMatch> - -# The following directive prevents browsers from MIME-sniffing the content-type. -# This is an important complement to the ForceType directive above: -Header set X-Content-Type-Options nosniff - -# Uncomment the following lines to prevent unauthorized download of files: -#AuthName "Authorization required" -#AuthType Basic -#require valid-user |