Advertisement
Guest User

get chunk file blueimp

a guest
Nov 27th, 2017
379
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 55.77 KB | None | 0 0
  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 that these options are inherited by all other image versions!
  136.                 '' => array(
  137.                     // Automatically rotate images based on EXIF meta data:
  138.                     'auto_orient' => true
  139.                 ),
  140.                 // Uncomment the following to create medium sized images:
  141.                 /*
  142.                 'medium' => array(
  143.                     'max_width' => 800,
  144.                     'max_height' => 600
  145.                 ),
  146.                 */
  147.                 'thumbnail' => array(
  148.                     // Uncomment the following to use a defined directory for the thumbnails
  149.                     // instead of a subdirectory based on the version identifier.
  150.                     // Make sure that this directory doesn't allow execution of files if you
  151.                     // don't pose any restrictions on the type of uploaded files, e.g. by
  152.                     // copying the .htaccess file from the files directory for Apache:
  153.                     //'upload_dir' => dirname($this->get_server_var('SCRIPT_FILENAME')).'/thumb/',
  154.                     //'upload_url' => $this->get_full_url().'/thumb/',
  155.                     // Uncomment the following to force the max
  156.                     // dimensions and e.g. create square thumbnails:
  157.                     //'crop' => true,
  158.                     'max_width' => 80,
  159.                     'max_height' => 80
  160.                 )
  161.             ),
  162.             'print_response' => true
  163.         );
  164.         if ($options) {
  165.             $this->options = $options + $this->options;
  166.         }
  167.         if ($error_messages) {
  168.             $this->error_messages = $error_messages + $this->error_messages;
  169.         }
  170.         if ($initialize) {
  171.             $this->initialize();
  172.         }
  173.     }
  174.  
  175.     protected function initialize() {
  176.         switch ($this->get_server_var('REQUEST_METHOD')) {
  177.             case 'OPTIONS':
  178.             case 'HEAD':
  179.                 $this->head();
  180.                 break;
  181.             case 'GET':
  182.                 $this->get($this->options['print_response']);
  183.                 break;
  184.             case 'PATCH':
  185.             case 'PUT':
  186.             case 'POST':
  187.                 $this->post($this->options['print_response']);
  188.                 break;
  189.             case 'DELETE':
  190.                 $this->delete($this->options['print_response']);
  191.                 break;
  192.             default:
  193.                 $this->header('HTTP/1.1 405 Method Not Allowed');
  194.         }
  195.     }
  196.  
  197.     protected function get_full_url() {
  198.         $https = !empty($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'], 'on') === 0 ||
  199.             !empty($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
  200.                 strcasecmp($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') === 0;
  201.         return
  202.             ($https ? 'https://' : 'http://').
  203.             (!empty($_SERVER['REMOTE_USER']) ? $_SERVER['REMOTE_USER'].'@' : '').
  204.             (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : ($_SERVER['SERVER_NAME'].
  205.             ($https && $_SERVER['SERVER_PORT'] === 443 ||
  206.             $_SERVER['SERVER_PORT'] === 80 ? '' : ':'.$_SERVER['SERVER_PORT']))).
  207.             substr($_SERVER['SCRIPT_NAME'],0, strrpos($_SERVER['SCRIPT_NAME'], '/'));
  208.     }
  209.  
  210.     protected function get_user_id() {
  211.         @session_start();
  212.         return session_id();
  213.     }
  214.  
  215.     protected function get_user_path() {
  216.         if ($this->options['user_dirs']) {
  217.             return $this->get_user_id().'/';
  218.         }
  219.         return '';
  220.     }
  221.  
  222.     protected function get_upload_path($file_name = null, $version = null) {
  223.         $file_name = $file_name ? $file_name : '';
  224.         if (empty($version)) {
  225.             $version_path = '';
  226.         } else {
  227.             $version_dir = @$this->options['image_versions'][$version]['upload_dir'];
  228.             if ($version_dir) {
  229.                 return $version_dir.$this->get_user_path().$file_name;
  230.             }
  231.             $version_path = $version.'/';
  232.         }
  233.         return $this->options['upload_dir'].$this->get_user_path()
  234.             .$version_path.$file_name;
  235.     }
  236.  
  237.     protected function get_query_separator($url) {
  238.         return strpos($url, '?') === false ? '?' : '&';
  239.     }
  240.  
  241.     protected function get_download_url($file_name, $version = null, $direct = false) {
  242.         if (!$direct && $this->options['download_via_php']) {
  243.             $url = $this->options['script_url']
  244.                 .$this->get_query_separator($this->options['script_url'])
  245.                 .$this->get_singular_param_name()
  246.                 .'='.rawurlencode($file_name);
  247.             if ($version) {
  248.                 $url .= '&version='.rawurlencode($version);
  249.             }
  250.             return $url.'&download=1';
  251.         }
  252.         if (empty($version)) {
  253.             $version_path = '';
  254.         } else {
  255.             $version_url = @$this->options['image_versions'][$version]['upload_url'];
  256.             if ($version_url) {
  257.                 return $version_url.$this->get_user_path().rawurlencode($file_name);
  258.             }
  259.             $version_path = rawurlencode($version).'/';
  260.         }
  261.         return $this->options['upload_url'].$this->get_user_path()
  262.             .$version_path.rawurlencode($file_name);
  263.     }
  264.  
  265.     protected function set_additional_file_properties($file) {
  266.         $file->deleteUrl = $this->options['script_url']
  267.             .$this->get_query_separator($this->options['script_url'])
  268.             .$this->get_singular_param_name()
  269.             .'='.rawurlencode($file->name);
  270.         $file->deleteType = $this->options['delete_type'];
  271.         if ($file->deleteType !== 'DELETE') {
  272.             $file->deleteUrl .= '&_method=DELETE';
  273.         }
  274.         if ($this->options['access_control_allow_credentials']) {
  275.             $file->deleteWithCredentials = true;
  276.         }
  277.     }
  278.  
  279.     // Fix for overflowing signed 32 bit integers,
  280.     // works for sizes up to 2^32-1 bytes (4 GiB - 1):
  281.     protected function fix_integer_overflow($size) {
  282.         if ($size < 0) {
  283.             $size += 2.0 * (PHP_INT_MAX + 1);
  284.         }
  285.         return $size;
  286.     }
  287.  
  288.     protected function get_file_size($file_path, $clear_stat_cache = false) {
  289.         if ($clear_stat_cache) {
  290.             if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
  291.                 clearstatcache(true, $file_path);
  292.             } else {
  293.                 clearstatcache();
  294.             }
  295.         }
  296.         return $this->fix_integer_overflow(filesize($file_path));
  297.     }
  298.  
  299.     protected function is_valid_file_object($file_name) {
  300.         $file_path = $this->get_upload_path($file_name);
  301.         if (is_file($file_path) && $file_name[0] !== '.') {
  302.             return true;
  303.         }
  304.         return false;
  305.     }
  306.  
  307.     protected function get_file_object($file_name) {
  308.         if ($this->is_valid_file_object($file_name)) {
  309.             $file = new \stdClass();
  310.             $file->name = $file_name;
  311.             $file->size = $this->get_file_size(
  312.                 $this->get_upload_path($file_name)
  313.             );
  314.             $file->url = $this->get_download_url($file->name);
  315.             foreach ($this->options['image_versions'] as $version => $options) {
  316.                 if (!empty($version)) {
  317.                     if (is_file($this->get_upload_path($file_name, $version))) {
  318.                         $file->{$version.'Url'} = $this->get_download_url(
  319.                             $file->name,
  320.                             $version
  321.                         );
  322.                     }
  323.                 }
  324.             }
  325.             $this->set_additional_file_properties($file);
  326.             return $file;
  327.         }
  328.         return null;
  329.     }
  330.  
  331.     protected function get_file_objects($iteration_method = 'get_file_object') {
  332.         $upload_dir = $this->get_upload_path();
  333.         if (!is_dir($upload_dir)) {
  334.             return array();
  335.         }
  336.         return array_values(array_filter(array_map(
  337.             array($this, $iteration_method),
  338.             scandir($upload_dir)
  339.         )));
  340.     }
  341.  
  342.     protected function count_file_objects() {
  343.         return count($this->get_file_objects('is_valid_file_object'));
  344.     }
  345.  
  346.     protected function get_error_message($error) {
  347.         return isset($this->error_messages[$error]) ?
  348.             $this->error_messages[$error] : $error;
  349.     }
  350.  
  351.     public function get_config_bytes($val) {
  352.         $val = trim($val);
  353.         $last = strtolower($val[strlen($val)-1]);
  354.         $val = (int)$val;
  355.         switch ($last) {
  356.             case 'g':
  357.                 $val *= 1024;
  358.             case 'm':
  359.                 $val *= 1024;
  360.             case 'k':
  361.                 $val *= 1024;
  362.         }
  363.         return $this->fix_integer_overflow($val);
  364.     }
  365.  
  366.     protected function validate($uploaded_file, $file, $error, $index) {
  367.         if ($error) {
  368.             $file->error = $this->get_error_message($error);
  369.             return false;
  370.         }
  371.         $content_length = $this->fix_integer_overflow(
  372.             (int)$this->get_server_var('CONTENT_LENGTH')
  373.         );
  374.         $post_max_size = $this->get_config_bytes(ini_get('post_max_size'));
  375.         if ($post_max_size && ($content_length > $post_max_size)) {
  376.             $file->error = $this->get_error_message('post_max_size');
  377.             return false;
  378.         }
  379.         if (!preg_match($this->options['accept_file_types'], $file->name)) {
  380.             $file->error = $this->get_error_message('accept_file_types');
  381.             return false;
  382.         }
  383.         if ($uploaded_file && is_uploaded_file($uploaded_file)) {
  384.             $file_size = $this->get_file_size($uploaded_file);
  385.         } else {
  386.             $file_size = $content_length;
  387.         }
  388.         if ($this->options['max_file_size'] && (
  389.                 $file_size > $this->options['max_file_size'] ||
  390.                 $file->size > $this->options['max_file_size'])
  391.             ) {
  392.             $file->error = $this->get_error_message('max_file_size');
  393.             return false;
  394.         }
  395.         if ($this->options['min_file_size'] &&
  396.             $file_size < $this->options['min_file_size']) {
  397.             $file->error = $this->get_error_message('min_file_size');
  398.             return false;
  399.         }
  400.         if (is_int($this->options['max_number_of_files']) &&
  401.                 ($this->count_file_objects() >= $this->options['max_number_of_files']) &&
  402.                 // Ignore additional chunks of existing files:
  403.                 !is_file($this->get_upload_path($file->name))) {
  404.             $file->error = $this->get_error_message('max_number_of_files');
  405.             return false;
  406.         }
  407.         $max_width = @$this->options['max_width'];
  408.         $max_height = @$this->options['max_height'];
  409.         $min_width = @$this->options['min_width'];
  410.         $min_height = @$this->options['min_height'];
  411.         if (($max_width || $max_height || $min_width || $min_height)
  412.            && preg_match($this->options['image_file_types'], $file->name)) {
  413.             list($img_width, $img_height) = $this->get_image_size($uploaded_file);
  414.  
  415.             // If we are auto rotating the image by default, do the checks on
  416.             // the correct orientation
  417.             if (
  418.                 @$this->options['image_versions']['']['auto_orient'] &&
  419.                 function_exists('exif_read_data') &&
  420.                 ($exif = @exif_read_data($uploaded_file)) &&
  421.                 (((int) @$exif['Orientation']) >= 5)
  422.             ) {
  423.                 $tmp = $img_width;
  424.                 $img_width = $img_height;
  425.                 $img_height = $tmp;
  426.                 unset($tmp);
  427.             }
  428.  
  429.         }
  430.         if (!empty($img_width)) {
  431.             if ($max_width && $img_width > $max_width) {
  432.                 $file->error = $this->get_error_message('max_width');
  433.                 return false;
  434.             }
  435.             if ($max_height && $img_height > $max_height) {
  436.                 $file->error = $this->get_error_message('max_height');
  437.                 return false;
  438.             }
  439.             if ($min_width && $img_width < $min_width) {
  440.                 $file->error = $this->get_error_message('min_width');
  441.                 return false;
  442.             }
  443.             if ($min_height && $img_height < $min_height) {
  444.                 $file->error = $this->get_error_message('min_height');
  445.                 return false;
  446.             }
  447.         }
  448.         return true;
  449.     }
  450.  
  451.     protected function upcount_name_callback($matches) {
  452.         $index = isset($matches[1]) ? ((int)$matches[1]) + 1 : 1;
  453.         $ext = isset($matches[2]) ? $matches[2] : '';
  454.         return ' ('.$index.')'.$ext;
  455.     }
  456.  
  457.     protected function upcount_name($name) {
  458.         return preg_replace_callback(
  459.             '/(?:(?: \(([\d]+)\))?(\.[^.]+))?$/',
  460.             array($this, 'upcount_name_callback'),
  461.             $name,
  462.             1
  463.         );
  464.     }
  465.  
  466.     protected function get_unique_filename($file_path, $name, $size, $type, $error,
  467.             $index, $content_range) {
  468.         while(is_dir($this->get_upload_path($name))) {
  469.             $name = $this->upcount_name($name);
  470.         }
  471.         // Keep an existing filename if this is part of a chunked upload:
  472.         $uploaded_bytes = $this->fix_integer_overflow((int)$content_range[1]);
  473.         while (is_file($this->get_upload_path($name))) {
  474.             if ($uploaded_bytes === $this->get_file_size(
  475.                     $this->get_upload_path($name))) {
  476.                 break;
  477.             }
  478.             $name = $this->upcount_name($name);
  479.         }
  480.         return $name;
  481.     }
  482.  
  483.     protected function fix_file_extension($file_path, $name, $size, $type, $error,
  484.             $index, $content_range) {
  485.         // Add missing file extension for known image types:
  486.         if (strpos($name, '.') === false &&
  487.                 preg_match('/^image\/(gif|jpe?g|png)/', $type, $matches)) {
  488.             $name .= '.'.$matches[1];
  489.         }
  490.         if ($this->options['correct_image_extensions'] &&
  491.                 function_exists('exif_imagetype')) {
  492.             switch (@exif_imagetype($file_path)){
  493.                 case IMAGETYPE_JPEG:
  494.                     $extensions = array('jpg', 'jpeg');
  495.                     break;
  496.                 case IMAGETYPE_PNG:
  497.                     $extensions = array('png');
  498.                     break;
  499.                 case IMAGETYPE_GIF:
  500.                     $extensions = array('gif');
  501.                     break;
  502.             }
  503.             // Adjust incorrect image file extensions:
  504.             if (!empty($extensions)) {
  505.                 $parts = explode('.', $name);
  506.                 $extIndex = count($parts) - 1;
  507.                 $ext = strtolower(@$parts[$extIndex]);
  508.                 if (!in_array($ext, $extensions)) {
  509.                     $parts[$extIndex] = $extensions[0];
  510.                     $name = implode('.', $parts);
  511.                 }
  512.             }
  513.         }
  514.         return $name;
  515.     }
  516.  
  517.     protected function trim_file_name($file_path, $name, $size, $type, $error,
  518.             $index, $content_range) {
  519.         // Remove path information and dots around the filename, to prevent uploading
  520.         // into different directories or replacing hidden system files.
  521.         // Also remove control characters and spaces (\x00..\x20) around the filename:
  522.         $name = trim($this->basename(stripslashes($name)), ".\x00..\x20");
  523.         // Use a timestamp for empty filenames:
  524.         if (!$name) {
  525.             $name = str_replace('.', '-', microtime(true));
  526.         }
  527.         return $name;
  528.     }
  529.  
  530.     protected function get_file_name($file_path, $name, $size, $type, $error,
  531.             $index, $content_range) {
  532.         $name = $this->trim_file_name($file_path, $name, $size, $type, $error,
  533.             $index, $content_range);
  534.         return $this->get_unique_filename(
  535.             $file_path,
  536.             $this->fix_file_extension($file_path, $name, $size, $type, $error,
  537.                 $index, $content_range),
  538.             $size,
  539.             $type,
  540.             $error,
  541.             $index,
  542.             $content_range
  543.         );
  544.     }
  545.  
  546.     protected function get_scaled_image_file_paths($file_name, $version) {
  547.         $file_path = $this->get_upload_path($file_name);
  548.         if (!empty($version)) {
  549.             $version_dir = $this->get_upload_path(null, $version);
  550.             if (!is_dir($version_dir)) {
  551.                 mkdir($version_dir, $this->options['mkdir_mode'], true);
  552.             }
  553.             $new_file_path = $version_dir.'/'.$file_name;
  554.         } else {
  555.             $new_file_path = $file_path;
  556.         }
  557.         return array($file_path, $new_file_path);
  558.     }
  559.  
  560.     protected function gd_get_image_object($file_path, $func, $no_cache = false) {
  561.         if (empty($this->image_objects[$file_path]) || $no_cache) {
  562.             $this->gd_destroy_image_object($file_path);
  563.             $this->image_objects[$file_path] = $func($file_path);
  564.         }
  565.         return $this->image_objects[$file_path];
  566.     }
  567.  
  568.     protected function gd_set_image_object($file_path, $image) {
  569.         $this->gd_destroy_image_object($file_path);
  570.         $this->image_objects[$file_path] = $image;
  571.     }
  572.  
  573.     protected function gd_destroy_image_object($file_path) {
  574.         $image = (isset($this->image_objects[$file_path])) ? $this->image_objects[$file_path] : null ;
  575.         return $image && imagedestroy($image);
  576.     }
  577.  
  578.     protected function gd_imageflip($image, $mode) {
  579.         if (function_exists('imageflip')) {
  580.             return imageflip($image, $mode);
  581.         }
  582.         $new_width = $src_width = imagesx($image);
  583.         $new_height = $src_height = imagesy($image);
  584.         $new_img = imagecreatetruecolor($new_width, $new_height);
  585.         $src_x = 0;
  586.         $src_y = 0;
  587.         switch ($mode) {
  588.             case '1': // flip on the horizontal axis
  589.                 $src_y = $new_height - 1;
  590.                 $src_height = -$new_height;
  591.                 break;
  592.             case '2': // flip on the vertical axis
  593.                 $src_x  = $new_width - 1;
  594.                 $src_width = -$new_width;
  595.                 break;
  596.             case '3': // flip on both axes
  597.                 $src_y = $new_height - 1;
  598.                 $src_height = -$new_height;
  599.                 $src_x  = $new_width - 1;
  600.                 $src_width = -$new_width;
  601.                 break;
  602.             default:
  603.                 return $image;
  604.         }
  605.         imagecopyresampled(
  606.             $new_img,
  607.             $image,
  608.             0,
  609.             0,
  610.             $src_x,
  611.             $src_y,
  612.             $new_width,
  613.             $new_height,
  614.             $src_width,
  615.             $src_height
  616.         );
  617.         return $new_img;
  618.     }
  619.  
  620.     protected function gd_orient_image($file_path, $src_img) {
  621.         if (!function_exists('exif_read_data')) {
  622.             return false;
  623.         }
  624.         $exif = @exif_read_data($file_path);
  625.         if ($exif === false) {
  626.             return false;
  627.         }
  628.         $orientation = (int)@$exif['Orientation'];
  629.         if ($orientation < 2 || $orientation > 8) {
  630.             return false;
  631.         }
  632.         switch ($orientation) {
  633.             case 2:
  634.                 $new_img = $this->gd_imageflip(
  635.                     $src_img,
  636.                     defined('IMG_FLIP_VERTICAL') ? IMG_FLIP_VERTICAL : 2
  637.                 );
  638.                 break;
  639.             case 3:
  640.                 $new_img = imagerotate($src_img, 180, 0);
  641.                 break;
  642.             case 4:
  643.                 $new_img = $this->gd_imageflip(
  644.                     $src_img,
  645.                     defined('IMG_FLIP_HORIZONTAL') ? IMG_FLIP_HORIZONTAL : 1
  646.                 );
  647.                 break;
  648.             case 5:
  649.                 $tmp_img = $this->gd_imageflip(
  650.                     $src_img,
  651.                     defined('IMG_FLIP_HORIZONTAL') ? IMG_FLIP_HORIZONTAL : 1
  652.                 );
  653.                 $new_img = imagerotate($tmp_img, 270, 0);
  654.                 imagedestroy($tmp_img);
  655.                 break;
  656.             case 6:
  657.                 $new_img = imagerotate($src_img, 270, 0);
  658.                 break;
  659.             case 7:
  660.                 $tmp_img = $this->gd_imageflip(
  661.                     $src_img,
  662.                     defined('IMG_FLIP_VERTICAL') ? IMG_FLIP_VERTICAL : 2
  663.                 );
  664.                 $new_img = imagerotate($tmp_img, 270, 0);
  665.                 imagedestroy($tmp_img);
  666.                 break;
  667.             case 8:
  668.                 $new_img = imagerotate($src_img, 90, 0);
  669.                 break;
  670.             default:
  671.                 return false;
  672.         }
  673.         $this->gd_set_image_object($file_path, $new_img);
  674.         return true;
  675.     }
  676.  
  677.     protected function gd_create_scaled_image($file_name, $version, $options) {
  678.         if (!function_exists('imagecreatetruecolor')) {
  679.             error_log('Function not found: imagecreatetruecolor');
  680.             return false;
  681.         }
  682.         list($file_path, $new_file_path) =
  683.             $this->get_scaled_image_file_paths($file_name, $version);
  684.         $type = strtolower(substr(strrchr($file_name, '.'), 1));
  685.         switch ($type) {
  686.             case 'jpg':
  687.             case 'jpeg':
  688.                 $src_func = 'imagecreatefromjpeg';
  689.                 $write_func = 'imagejpeg';
  690.                 $image_quality = isset($options['jpeg_quality']) ?
  691.                     $options['jpeg_quality'] : 75;
  692.                 break;
  693.             case 'gif':
  694.                 $src_func = 'imagecreatefromgif';
  695.                 $write_func = 'imagegif';
  696.                 $image_quality = null;
  697.                 break;
  698.             case 'png':
  699.                 $src_func = 'imagecreatefrompng';
  700.                 $write_func = 'imagepng';
  701.                 $image_quality = isset($options['png_quality']) ?
  702.                     $options['png_quality'] : 9;
  703.                 break;
  704.             default:
  705.                 return false;
  706.         }
  707.         $src_img = $this->gd_get_image_object(
  708.             $file_path,
  709.             $src_func,
  710.             !empty($options['no_cache'])
  711.         );
  712.         $image_oriented = false;
  713.         if (!empty($options['auto_orient']) && $this->gd_orient_image(
  714.                 $file_path,
  715.                 $src_img
  716.             )) {
  717.             $image_oriented = true;
  718.             $src_img = $this->gd_get_image_object(
  719.                 $file_path,
  720.                 $src_func
  721.             );
  722.         }
  723.         $max_width = $img_width = imagesx($src_img);
  724.         $max_height = $img_height = imagesy($src_img);
  725.         if (!empty($options['max_width'])) {
  726.             $max_width = $options['max_width'];
  727.         }
  728.         if (!empty($options['max_height'])) {
  729.             $max_height = $options['max_height'];
  730.         }
  731.         $scale = min(
  732.             $max_width / $img_width,
  733.             $max_height / $img_height
  734.         );
  735.         if ($scale >= 1) {
  736.             if ($image_oriented) {
  737.                 return $write_func($src_img, $new_file_path, $image_quality);
  738.             }
  739.             if ($file_path !== $new_file_path) {
  740.                 return copy($file_path, $new_file_path);
  741.             }
  742.             return true;
  743.         }
  744.         if (empty($options['crop'])) {
  745.             $new_width = $img_width * $scale;
  746.             $new_height = $img_height * $scale;
  747.             $dst_x = 0;
  748.             $dst_y = 0;
  749.             $new_img = imagecreatetruecolor($new_width, $new_height);
  750.         } else {
  751.             if (($img_width / $img_height) >= ($max_width / $max_height)) {
  752.                 $new_width = $img_width / ($img_height / $max_height);
  753.                 $new_height = $max_height;
  754.             } else {
  755.                 $new_width = $max_width;
  756.                 $new_height = $img_height / ($img_width / $max_width);
  757.             }
  758.             $dst_x = 0 - ($new_width - $max_width) / 2;
  759.             $dst_y = 0 - ($new_height - $max_height) / 2;
  760.             $new_img = imagecreatetruecolor($max_width, $max_height);
  761.         }
  762.         // Handle transparency in GIF and PNG images:
  763.         switch ($type) {
  764.             case 'gif':
  765.             case 'png':
  766.                 imagecolortransparent($new_img, imagecolorallocate($new_img, 0, 0, 0));
  767.             case 'png':
  768.                 imagealphablending($new_img, false);
  769.                 imagesavealpha($new_img, true);
  770.                 break;
  771.         }
  772.         $success = imagecopyresampled(
  773.             $new_img,
  774.             $src_img,
  775.             $dst_x,
  776.             $dst_y,
  777.             0,
  778.             0,
  779.             $new_width,
  780.             $new_height,
  781.             $img_width,
  782.             $img_height
  783.         ) && $write_func($new_img, $new_file_path, $image_quality);
  784.         $this->gd_set_image_object($file_path, $new_img);
  785.         return $success;
  786.     }
  787.  
  788.     protected function imagick_get_image_object($file_path, $no_cache = false) {
  789.         if (empty($this->image_objects[$file_path]) || $no_cache) {
  790.             $this->imagick_destroy_image_object($file_path);
  791.             $image = new \Imagick();
  792.             if (!empty($this->options['imagick_resource_limits'])) {
  793.                 foreach ($this->options['imagick_resource_limits'] as $type => $limit) {
  794.                     $image->setResourceLimit($type, $limit);
  795.                 }
  796.             }
  797.             $image->readImage($file_path);
  798.             $this->image_objects[$file_path] = $image;
  799.         }
  800.         return $this->image_objects[$file_path];
  801.     }
  802.  
  803.     protected function imagick_set_image_object($file_path, $image) {
  804.         $this->imagick_destroy_image_object($file_path);
  805.         $this->image_objects[$file_path] = $image;
  806.     }
  807.  
  808.     protected function imagick_destroy_image_object($file_path) {
  809.         $image = (isset($this->image_objects[$file_path])) ? $this->image_objects[$file_path] : null ;
  810.         return $image && $image->destroy();
  811.     }
  812.  
  813.     protected function imagick_orient_image($image) {
  814.         $orientation = $image->getImageOrientation();
  815.         $background = new \ImagickPixel('none');
  816.         switch ($orientation) {
  817.             case \imagick::ORIENTATION_TOPRIGHT: // 2
  818.                 $image->flopImage(); // horizontal flop around y-axis
  819.                 break;
  820.             case \imagick::ORIENTATION_BOTTOMRIGHT: // 3
  821.                 $image->rotateImage($background, 180);
  822.                 break;
  823.             case \imagick::ORIENTATION_BOTTOMLEFT: // 4
  824.                 $image->flipImage(); // vertical flip around x-axis
  825.                 break;
  826.             case \imagick::ORIENTATION_LEFTTOP: // 5
  827.                 $image->flopImage(); // horizontal flop around y-axis
  828.                 $image->rotateImage($background, 270);
  829.                 break;
  830.             case \imagick::ORIENTATION_RIGHTTOP: // 6
  831.                 $image->rotateImage($background, 90);
  832.                 break;
  833.             case \imagick::ORIENTATION_RIGHTBOTTOM: // 7
  834.                 $image->flipImage(); // vertical flip around x-axis
  835.                 $image->rotateImage($background, 270);
  836.                 break;
  837.             case \imagick::ORIENTATION_LEFTBOTTOM: // 8
  838.                 $image->rotateImage($background, 270);
  839.                 break;
  840.             default:
  841.                 return false;
  842.         }
  843.         $image->setImageOrientation(\imagick::ORIENTATION_TOPLEFT); // 1
  844.         return true;
  845.     }
  846.  
  847.     protected function imagick_create_scaled_image($file_name, $version, $options) {
  848.         list($file_path, $new_file_path) =
  849.             $this->get_scaled_image_file_paths($file_name, $version);
  850.         $image = $this->imagick_get_image_object(
  851.             $file_path,
  852.             !empty($options['crop']) || !empty($options['no_cache'])
  853.         );
  854.         if ($image->getImageFormat() === 'GIF') {
  855.             // Handle animated GIFs:
  856.             $images = $image->coalesceImages();
  857.             foreach ($images as $frame) {
  858.                 $image = $frame;
  859.                 $this->imagick_set_image_object($file_name, $image);
  860.                 break;
  861.             }
  862.         }
  863.         $image_oriented = false;
  864.         if (!empty($options['auto_orient'])) {
  865.             $image_oriented = $this->imagick_orient_image($image);
  866.         }
  867.         $new_width = $max_width = $img_width = $image->getImageWidth();
  868.         $new_height = $max_height = $img_height = $image->getImageHeight();
  869.         if (!empty($options['max_width'])) {
  870.             $new_width = $max_width = $options['max_width'];
  871.         }
  872.         if (!empty($options['max_height'])) {
  873.             $new_height = $max_height = $options['max_height'];
  874.         }
  875.         $image_strip = false;
  876.         if( !empty($options["strip"]) ) {
  877.             $image_strip = $options["strip"];
  878.         }
  879.         if ( !$image_oriented && ($max_width >= $img_width) && ($max_height >= $img_height) && !$image_strip && empty($options["jpeg_quality"]) ) {        
  880.             if ($file_path !== $new_file_path) {
  881.                 return copy($file_path, $new_file_path);
  882.             }
  883.             return true;
  884.         }
  885.         $crop = !empty($options['crop']);
  886.         if ($crop) {
  887.             $x = 0;
  888.             $y = 0;
  889.             if (($img_width / $img_height) >= ($max_width / $max_height)) {
  890.                 $new_width = 0; // Enables proportional scaling based on max_height
  891.                 $x = ($img_width / ($img_height / $max_height) - $max_width) / 2;
  892.             } else {
  893.                 $new_height = 0; // Enables proportional scaling based on max_width
  894.                 $y = ($img_height / ($img_width / $max_width) - $max_height) / 2;
  895.             }
  896.         }
  897.         $success = $image->resizeImage(
  898.             $new_width,
  899.             $new_height,
  900.             isset($options['filter']) ? $options['filter'] : \imagick::FILTER_LANCZOS,
  901.             isset($options['blur']) ? $options['blur'] : 1,
  902.             $new_width && $new_height // fit image into constraints if not to be cropped
  903.         );
  904.         if ($success && $crop) {
  905.             $success = $image->cropImage(
  906.                 $max_width,
  907.                 $max_height,
  908.                 $x,
  909.                 $y
  910.             );
  911.             if ($success) {
  912.                 $success = $image->setImagePage($max_width, $max_height, 0, 0);
  913.             }
  914.         }
  915.         $type = strtolower(substr(strrchr($file_name, '.'), 1));
  916.         switch ($type) {
  917.             case 'jpg':
  918.             case 'jpeg':
  919.                 if (!empty($options['jpeg_quality'])) {
  920.                     $image->setImageCompression(\imagick::COMPRESSION_JPEG);
  921.                     $image->setImageCompressionQuality($options['jpeg_quality']);
  922.                 }
  923.                 break;
  924.         }
  925.         if ( $image_strip ) {
  926.             $image->stripImage();
  927.         }
  928.         return $success && $image->writeImage($new_file_path);
  929.     }
  930.  
  931.     protected function imagemagick_create_scaled_image($file_name, $version, $options) {
  932.         list($file_path, $new_file_path) =
  933.             $this->get_scaled_image_file_paths($file_name, $version);
  934.         $resize = @$options['max_width']
  935.             .(empty($options['max_height']) ? '' : 'X'.$options['max_height']);
  936.         if (!$resize && empty($options['auto_orient'])) {
  937.             if ($file_path !== $new_file_path) {
  938.                 return copy($file_path, $new_file_path);
  939.             }
  940.             return true;
  941.         }
  942.         $cmd = $this->options['convert_bin'];
  943.         if (!empty($this->options['convert_params'])) {
  944.             $cmd .= ' '.$this->options['convert_params'];
  945.         }
  946.         $cmd .= ' '.escapeshellarg($file_path);
  947.         if (!empty($options['auto_orient'])) {
  948.             $cmd .= ' -auto-orient';
  949.         }
  950.         if ($resize) {
  951.             // Handle animated GIFs:
  952.             $cmd .= ' -coalesce';
  953.             if (empty($options['crop'])) {
  954.                 $cmd .= ' -resize '.escapeshellarg($resize.'>');
  955.             } else {
  956.                 $cmd .= ' -resize '.escapeshellarg($resize.'^');
  957.                 $cmd .= ' -gravity center';
  958.                 $cmd .= ' -crop '.escapeshellarg($resize.'+0+0');
  959.             }
  960.             // Make sure the page dimensions are correct (fixes offsets of animated GIFs):
  961.             $cmd .= ' +repage';
  962.         }
  963.         if (!empty($options['convert_params'])) {
  964.             $cmd .= ' '.$options['convert_params'];
  965.         }
  966.         $cmd .= ' '.escapeshellarg($new_file_path);
  967.         exec($cmd, $output, $error);
  968.         if ($error) {
  969.             error_log(implode('\n', $output));
  970.             return false;
  971.         }
  972.         return true;
  973.     }
  974.  
  975.     protected function get_image_size($file_path) {
  976.         if ($this->options['image_library']) {
  977.             if (extension_loaded('imagick')) {
  978.                 $image = new \Imagick();
  979.                 try {
  980.                     if (@$image->pingImage($file_path)) {
  981.                         $dimensions = array($image->getImageWidth(), $image->getImageHeight());
  982.                         $image->destroy();
  983.                         return $dimensions;
  984.                     }
  985.                     return false;
  986.                 } catch (\Exception $e) {
  987.                     error_log($e->getMessage());
  988.                 }
  989.             }
  990.             if ($this->options['image_library'] === 2) {
  991.                 $cmd = $this->options['identify_bin'];
  992.                 $cmd .= ' -ping '.escapeshellarg($file_path);
  993.                 exec($cmd, $output, $error);
  994.                 if (!$error && !empty($output)) {
  995.                     // image.jpg JPEG 1920x1080 1920x1080+0+0 8-bit sRGB 465KB 0.000u 0:00.000
  996.                     $infos = preg_split('/\s+/', substr($output[0], strlen($file_path)));
  997.                     $dimensions = preg_split('/x/', $infos[2]);
  998.                     return $dimensions;
  999.                 }
  1000.                 return false;
  1001.             }
  1002.         }
  1003.         if (!function_exists('getimagesize')) {
  1004.             error_log('Function not found: getimagesize');
  1005.             return false;
  1006.         }
  1007.         return @getimagesize($file_path);
  1008.     }
  1009.  
  1010.     protected function create_scaled_image($file_name, $version, $options) {
  1011.         if ($this->options['image_library'] === 2) {
  1012.             return $this->imagemagick_create_scaled_image($file_name, $version, $options);
  1013.         }
  1014.         if ($this->options['image_library'] && extension_loaded('imagick')) {
  1015.             return $this->imagick_create_scaled_image($file_name, $version, $options);
  1016.         }
  1017.         return $this->gd_create_scaled_image($file_name, $version, $options);
  1018.     }
  1019.  
  1020.     protected function destroy_image_object($file_path) {
  1021.         if ($this->options['image_library'] && extension_loaded('imagick')) {
  1022.             return $this->imagick_destroy_image_object($file_path);
  1023.         }
  1024.     }
  1025.  
  1026.     protected function is_valid_image_file($file_path) {
  1027.         if (!preg_match($this->options['image_file_types'], $file_path)) {
  1028.             return false;
  1029.         }
  1030.         if (function_exists('exif_imagetype')) {
  1031.             return @exif_imagetype($file_path);
  1032.         }
  1033.         $image_info = $this->get_image_size($file_path);
  1034.         return $image_info && $image_info[0] && $image_info[1];
  1035.     }
  1036.  
  1037.     protected function handle_image_file($file_path, $file) {
  1038.         $failed_versions = array();
  1039.         foreach ($this->options['image_versions'] as $version => $options) {
  1040.             if ($this->create_scaled_image($file->name, $version, $options)) {
  1041.                 if (!empty($version)) {
  1042.                     $file->{$version.'Url'} = $this->get_download_url(
  1043.                         $file->name,
  1044.                         $version
  1045.                     );
  1046.                 } else {
  1047.                     $file->size = $this->get_file_size($file_path, true);
  1048.                 }
  1049.             } else {
  1050.                 $failed_versions[] = $version ? $version : 'original';
  1051.             }
  1052.         }
  1053.         if (count($failed_versions)) {
  1054.             $file->error = $this->get_error_message('image_resize')
  1055.                     .' ('.implode($failed_versions, ', ').')';
  1056.         }
  1057.         // Free memory:
  1058.         $this->destroy_image_object($file_path);
  1059.     }
  1060.  
  1061.     protected function handle_file_upload($uploaded_file, $name, $size, $type, $error,
  1062.             $index = null, $content_range = null) {
  1063.         $file = new \stdClass();
  1064.         $file->name = $this->get_file_name($uploaded_file, $name, $size, $type, $error,
  1065.             $index, $content_range);
  1066.         $file->size = $this->fix_integer_overflow((int)$size);
  1067.         $file->type = $type;
  1068.         if ($this->validate($uploaded_file, $file, $error, $index)) {
  1069.             $this->handle_form_data($file, $index);
  1070.             $upload_dir = $this->get_upload_path();
  1071.             if (!is_dir($upload_dir)) {
  1072.                 mkdir($upload_dir, $this->options['mkdir_mode'], true);
  1073.             }
  1074.             $file_path = $this->get_upload_path($file->name);
  1075.             $append_file = $content_range && is_file($file_path) &&
  1076.                 $file->size > $this->get_file_size($file_path);
  1077.             if ($uploaded_file && is_uploaded_file($uploaded_file)) {
  1078.                 // multipart/formdata uploads (POST method uploads)
  1079.                 $path_parts = pathinfo($file_path);
  1080.                 $chunkFileName = $path_parts['dirname'].'/'.$path_parts['filename'].'_'. $content_range[1]."_". $content_range[2].".".$path_parts['extension'];//echo $chunkFileName;
  1081.                 if ($append_file) {
  1082.                     file_put_contents($chunkFileName,  file_get_contents($uploaded_file));
  1083.                     file_put_contents(
  1084.                         $file_path,
  1085.                         fopen($uploaded_file, 'r'),
  1086.                         FILE_APPEND
  1087.                     );
  1088.                 } else {
  1089.                     file_put_contents($chunkFileName,  file_get_contents($uploaded_file));
  1090.                     move_uploaded_file($uploaded_file, $file_path);
  1091.                 }
  1092.             } else {
  1093.                 // Non-multipart uploads (PUT method support)
  1094.                 file_put_contents(
  1095.                     $file_path,
  1096.                     fopen($this->options['input_stream'], 'r'),
  1097.                     $append_file ? FILE_APPEND : 0
  1098.                 );
  1099.             }
  1100.             $file_size = $this->get_file_size($file_path, $append_file);
  1101.             if ($file_size === $file->size) {
  1102.                 $file->url = $this->get_download_url($file->name);
  1103.                 if ($this->is_valid_image_file($file_path)) {
  1104.                     $this->handle_image_file($file_path, $file);
  1105.                 }
  1106.             } else {
  1107.                 $file->size = $file_size;
  1108.                 if (!$content_range && $this->options['discard_aborted_uploads']) {
  1109.                     unlink($file_path);
  1110.                     $file->error = $this->get_error_message('abort');
  1111.                 }
  1112.             }
  1113.             $this->set_additional_file_properties($file);
  1114.         }
  1115.         return $file;
  1116.     }
  1117.  
  1118.     protected function readfile($file_path) {
  1119.         $file_size = $this->get_file_size($file_path);
  1120.         $chunk_size = $this->options['readfile_chunk_size'];
  1121.         if ($chunk_size && $file_size > $chunk_size) {
  1122.             $handle = fopen($file_path, 'rb');
  1123.             while (!feof($handle)) {
  1124.                 echo fread($handle, $chunk_size);
  1125.                 @ob_flush();
  1126.                 @flush();
  1127.             }
  1128.             fclose($handle);
  1129.             return $file_size;
  1130.         }
  1131.         return readfile($file_path);
  1132.     }
  1133.  
  1134.     protected function body($str) {
  1135.         echo $str;
  1136.     }
  1137.  
  1138.     protected function header($str) {
  1139.         header($str);
  1140.     }
  1141.  
  1142.     protected function get_upload_data($id) {
  1143.         return @$_FILES[$id];
  1144.     }
  1145.  
  1146.     protected function get_post_param($id) {
  1147.         return @$_POST[$id];
  1148.     }
  1149.  
  1150.     protected function get_query_param($id) {
  1151.         return @$_GET[$id];
  1152.     }
  1153.  
  1154.     protected function get_server_var($id) {
  1155.         return @$_SERVER[$id];
  1156.     }
  1157.  
  1158.     protected function handle_form_data($file, $index) {
  1159.         // Handle form data, e.g. $_POST['description'][$index]
  1160.     }
  1161.  
  1162.     protected function get_version_param() {
  1163.         return $this->basename(stripslashes($this->get_query_param('version')));
  1164.     }
  1165.  
  1166.     protected function get_singular_param_name() {
  1167.         return substr($this->options['param_name'], 0, -1);
  1168.     }
  1169.  
  1170.     protected function get_file_name_param() {
  1171.         $name = $this->get_singular_param_name();
  1172.         return $this->basename(stripslashes($this->get_query_param($name)));
  1173.     }
  1174.  
  1175.     protected function get_file_names_params() {
  1176.         $params = $this->get_query_param($this->options['param_name']);
  1177.         if (!$params) {
  1178.             return null;
  1179.         }
  1180.         foreach ($params as $key => $value) {
  1181.             $params[$key] = $this->basename(stripslashes($value));
  1182.         }
  1183.         return $params;
  1184.     }
  1185.  
  1186.     protected function get_file_type($file_path) {
  1187.         switch (strtolower(pathinfo($file_path, PATHINFO_EXTENSION))) {
  1188.             case 'jpeg':
  1189.             case 'jpg':
  1190.                 return 'image/jpeg';
  1191.             case 'png':
  1192.                 return 'image/png';
  1193.             case 'gif':
  1194.                 return 'image/gif';
  1195.             default:
  1196.                 return '';
  1197.         }
  1198.     }
  1199.  
  1200.     protected function download() {
  1201.         switch ($this->options['download_via_php']) {
  1202.             case 1:
  1203.                 $redirect_header = null;
  1204.                 break;
  1205.             case 2:
  1206.                 $redirect_header = 'X-Sendfile';
  1207.                 break;
  1208.             case 3:
  1209.                 $redirect_header = 'X-Accel-Redirect';
  1210.                 break;
  1211.             default:
  1212.                 return $this->header('HTTP/1.1 403 Forbidden');
  1213.         }
  1214.         $file_name = $this->get_file_name_param();
  1215.         if (!$this->is_valid_file_object($file_name)) {
  1216.             return $this->header('HTTP/1.1 404 Not Found');
  1217.         }
  1218.         if ($redirect_header) {
  1219.             return $this->header(
  1220.                 $redirect_header.': '.$this->get_download_url(
  1221.                     $file_name,
  1222.                     $this->get_version_param(),
  1223.                     true
  1224.                 )
  1225.             );
  1226.         }
  1227.         $file_path = $this->get_upload_path($file_name, $this->get_version_param());
  1228.         // Prevent browsers from MIME-sniffing the content-type:
  1229.         $this->header('X-Content-Type-Options: nosniff');
  1230.         if (!preg_match($this->options['inline_file_types'], $file_name)) {
  1231.             $this->header('Content-Type: application/octet-stream');
  1232.             $this->header('Content-Disposition: attachment; filename="'.$file_name.'"');
  1233.         } else {
  1234.             $this->header('Content-Type: '.$this->get_file_type($file_path));
  1235.             $this->header('Content-Disposition: inline; filename="'.$file_name.'"');
  1236.         }
  1237.         $this->header('Content-Length: '.$this->get_file_size($file_path));
  1238.         $this->header('Last-Modified: '.gmdate('D, d M Y H:i:s T', filemtime($file_path)));
  1239.         $this->readfile($file_path);
  1240.     }
  1241.  
  1242.     protected function send_content_type_header() {
  1243.         $this->header('Vary: Accept');
  1244.         if (strpos($this->get_server_var('HTTP_ACCEPT'), 'application/json') !== false) {
  1245.             $this->header('Content-type: application/json');
  1246.         } else {
  1247.             $this->header('Content-type: text/plain');
  1248.         }
  1249.     }
  1250.  
  1251.     protected function send_access_control_headers() {
  1252.         $this->header('Access-Control-Allow-Origin: '.$this->options['access_control_allow_origin']);
  1253.         $this->header('Access-Control-Allow-Credentials: '
  1254.             .($this->options['access_control_allow_credentials'] ? 'true' : 'false'));
  1255.         $this->header('Access-Control-Allow-Methods: '
  1256.             .implode(', ', $this->options['access_control_allow_methods']));
  1257.         $this->header('Access-Control-Allow-Headers: '
  1258.             .implode(', ', $this->options['access_control_allow_headers']));
  1259.     }
  1260.  
  1261.     public function generate_response($content, $print_response = true) {
  1262.         $this->response = $content;
  1263.         if ($print_response) {
  1264.             $json = json_encode($content);
  1265.             $redirect = stripslashes($this->get_post_param('redirect'));
  1266.             if ($redirect && preg_match($this->options['redirect_allow_target'], $redirect)) {
  1267.                 $this->header('Location: '.sprintf($redirect, rawurlencode($json)));
  1268.                 return;
  1269.             }
  1270.             $this->head();
  1271.             if ($this->get_server_var('HTTP_CONTENT_RANGE')) {
  1272.                 $files = isset($content[$this->options['param_name']]) ?
  1273.                     $content[$this->options['param_name']] : null;
  1274.                 if ($files && is_array($files) && is_object($files[0]) && $files[0]->size) {
  1275.                     $this->header('Range: 0-'.(
  1276.                         $this->fix_integer_overflow((int)$files[0]->size) - 1
  1277.                     ));
  1278.                 }
  1279.             }
  1280.             $this->body($json);
  1281.         }
  1282.         return $content;
  1283.     }
  1284.  
  1285.     public function get_response () {
  1286.         return $this->response;
  1287.     }
  1288.  
  1289.     public function head() {
  1290.         $this->header('Pragma: no-cache');
  1291.         $this->header('Cache-Control: no-store, no-cache, must-revalidate');
  1292.         $this->header('Content-Disposition: inline; filename="files.json"');
  1293.         // Prevent Internet Explorer from MIME-sniffing the content-type:
  1294.         $this->header('X-Content-Type-Options: nosniff');
  1295.         if ($this->options['access_control_allow_origin']) {
  1296.             $this->send_access_control_headers();
  1297.         }
  1298.         $this->send_content_type_header();
  1299.     }
  1300.  
  1301.     public function get($print_response = true) {
  1302.         if ($print_response && $this->get_query_param('download')) {
  1303.             return $this->download();
  1304.         }
  1305.         $file_name = $this->get_file_name_param();
  1306.         if ($file_name) {
  1307.             $response = array(
  1308.                 $this->get_singular_param_name() => $this->get_file_object($file_name)
  1309.             );
  1310.         } else {
  1311.             $response = array(
  1312.                 $this->options['param_name'] => $this->get_file_objects()
  1313.             );
  1314.         }
  1315.         return $this->generate_response($response, $print_response);
  1316.     }
  1317.  
  1318.     public function post($print_response = true) {
  1319.         if ($this->get_query_param('_method') === 'DELETE') {
  1320.             return $this->delete($print_response);
  1321.         }
  1322.         $upload = $this->get_upload_data($this->options['param_name']);
  1323.         // Parse the Content-Disposition header, if available:
  1324.         $content_disposition_header = $this->get_server_var('HTTP_CONTENT_DISPOSITION');
  1325.         $file_name = $content_disposition_header ?
  1326.             rawurldecode(preg_replace(
  1327.                 '/(^[^"]+")|("$)/',
  1328.                 '',
  1329.                 $content_disposition_header
  1330.             )) : null;
  1331.         // Parse the Content-Range header, which has the following form:
  1332.         // Content-Range: bytes 0-524287/2000000
  1333.         $content_range_header = $this->get_server_var('HTTP_CONTENT_RANGE');
  1334.         $content_range = $content_range_header ?
  1335.             preg_split('/[^0-9]+/', $content_range_header) : null;
  1336.         $size =  $content_range ? $content_range[3] : null;
  1337.         $files = array();
  1338.         if ($upload) {
  1339.             if (is_array($upload['tmp_name'])) {
  1340.                 // param_name is an array identifier like "files[]",
  1341.                 // $upload is a multi-dimensional array:
  1342.                 foreach ($upload['tmp_name'] as $index => $value) {
  1343.                     $files[] = $this->handle_file_upload(
  1344.                         $upload['tmp_name'][$index],
  1345.                         $file_name ? $file_name : $upload['name'][$index],
  1346.                         $size ? $size : $upload['size'][$index],
  1347.                         $upload['type'][$index],
  1348.                         $upload['error'][$index],
  1349.                         $index,
  1350.                         $content_range
  1351.                     );
  1352.                 }
  1353.             } else {
  1354.                 // param_name is a single object identifier like "file",
  1355.                 // $upload is a one-dimensional array:
  1356.                 $files[] = $this->handle_file_upload(
  1357.                     isset($upload['tmp_name']) ? $upload['tmp_name'] : null,
  1358.                     $file_name ? $file_name : (isset($upload['name']) ?
  1359.                             $upload['name'] : null),
  1360.                     $size ? $size : (isset($upload['size']) ?
  1361.                             $upload['size'] : $this->get_server_var('CONTENT_LENGTH')),
  1362.                     isset($upload['type']) ?
  1363.                             $upload['type'] : $this->get_server_var('CONTENT_TYPE'),
  1364.                     isset($upload['error']) ? $upload['error'] : null,
  1365.                     null,
  1366.                     $content_range
  1367.                 );
  1368.             }
  1369.         }
  1370.         $response = array($this->options['param_name'] => $files);
  1371.         return $this->generate_response($response, $print_response);
  1372.     }
  1373.  
  1374.     public function delete($print_response = true) {
  1375.         $file_names = $this->get_file_names_params();
  1376.         if (empty($file_names)) {
  1377.             $file_names = array($this->get_file_name_param());
  1378.         }
  1379.         $response = array();
  1380.         foreach ($file_names as $file_name) {
  1381.             $file_path = $this->get_upload_path($file_name);
  1382.             $success = is_file($file_path) && $file_name[0] !== '.' && unlink($file_path);
  1383.             if ($success) {
  1384.                 foreach ($this->options['image_versions'] as $version => $options) {
  1385.                     if (!empty($version)) {
  1386.                         $file = $this->get_upload_path($file_name, $version);
  1387.                         if (is_file($file)) {
  1388.                             unlink($file);
  1389.                         }
  1390.                     }
  1391.                 }
  1392.             }
  1393.             $response[$file_name] = $success;
  1394.         }
  1395.         return $this->generate_response($response, $print_response);
  1396.     }
  1397.  
  1398.     protected function basename($filepath, $suffix = null) {
  1399.         $splited = preg_split('/\//', rtrim ($filepath, '/ '));
  1400.         return substr(basename('X'.$splited[count($splited)-1], $suffix), 1);
  1401.     }
  1402. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement