Ejemplo n.º 1
0
 /**
  * Process the 'upload' event
  *
  * Process and store the uploaded file in the designated location.
  * Images will be resized when possible and applicable. A thumbnail image will also
  * be preproduced when possible.
  * Return a JSON encoded status of success or failure.
  *
  * Expected parameters:
  *
  * $_POST['directory']    path relative to basedir a.k.a. options['URLpath4FileManagedDirTree'] root
  *
  * $_POST['resize']       nonzero value indicates any uploaded image should be resized to the configured
  *                        options['maxImageDimension'] width and height whenever possible
  *
  * $_POST['filter']       optional mimetype filter string, amy be the part up to and
  *                        including the slash '/' or the full mimetype. Only files
  *                        matching this (set of) mimetypes will be listed.
  *                        Examples: 'image/' or 'application/zip'
  *
  * $_FILES[]              the metadata for the uploaded file
  *
  * $_POST['reportContentType']
  *                        if you want a specific content type header set on our response, put it here.
  *                        This is needed for when we are posting an upload response to a hidden iframe, the
  *                        default application/json mimetype breaks down in that case at least for Firefox 3.X
  *                        as the browser will pop up a save/view dialog before JS can access the transmitted data.
  *
  * Errors will produce a JSON encoded error report, including at least two fields:
  *
  * status                 0 for error; nonzero for success
  *
  * error                  error message
  */
 protected function onUpload()
 {
     $emsg = null;
     $file_arg = null;
     $file = null;
     $legal_dir_url = null;
     $jserr = array('status' => 1);
     try {
         if (!$this->options['upload']) {
             throw new FileManagerException('disabled:upload');
         }
         // MAY upload zero length files!
         if (!isset($_FILES) || empty($_FILES['Filedata']) || empty($_FILES['Filedata']['name'])) {
             throw new FileManagerException('nofile');
         }
         $v_ex_code = 'nofile';
         $file_size = empty($_FILES['Filedata']['size']) ? 0 : $_FILES['Filedata']['size'];
         $file_arg = $_FILES['Filedata']['name'];
         $dir_arg = $this->getPOSTparam('directory');
         $legal_dir_url = $this->rel2abs_legal_url_path($dir_arg . '/');
         // must transform here so alias/etc. expansions inside legal_url_path2file_path() get a chance:
         $dir = $this->legal_url_path2file_path($legal_dir_url);
         $mime_filter = $this->getPOSTparam('filter', $this->options['filter']);
         $mime_filters = $this->getAllowedMimeTypes($mime_filter);
         $tmppath = $_FILES['Filedata']['tmp_name'];
         $resize_imgs = $this->getPOSTparam('resize', 0);
         $filename = null;
         $fi = array('filename' => null, 'extension' => null);
         $mime = null;
         $meta = null;
         if (!empty($file_arg)) {
             if (!$this->IsHiddenNameAllowed($file_arg)) {
                 $v_ex_code = 'fmt_not_allowed';
             } else {
                 $filename = $this->getUniqueName($file_arg, $dir);
                 if ($filename !== null) {
                     /*
                      * Security:
                      *
                      * Upload::move() processes the unfiltered version of $_FILES[]['name'], at least to get the extension,
                      * unless we ALWAYS override the filename and extension in the options array below. That's why we
                      * calculate the extension at all times here.
                      */
                     if ($this->options['safe']) {
                         $fi = pathinfo($filename);
                         $fi['extension'] = $this->getSafeExtension(isset($fi['extension']) ? $fi['extension'] : '');
                         $filename = $fi['filename'] . (isset($fi['extension']) && strlen($fi['extension']) > 0 ? '.' . $fi['extension'] : '');
                     }
                     $legal_url = $legal_dir_url . $filename;
                     // UPLOAD delivers files in temporary storage with extensions NOT matching the mime type, so we don't
                     // filter on extension; we just let getID3 go ahead and content-sniff the mime type.
                     // Since getID3::analyze() is a quite costly operation, we like to do it only ONCE per file,
                     // so we cache the last entries.
                     $meta = $this->getFileInfo($tmppath, $legal_url);
                     $mime = $meta->getMimeType();
                     if (!$this->IsAllowedMimeType($mime, $mime_filters)) {
                         $v_ex_code = 'extension';
                     } else {
                         $v_ex_code = null;
                     }
                 }
             }
         }
         $fileinfo = array('legal_dir_url' => $legal_dir_url, 'dir' => $dir, 'raw_filename' => $file_arg, 'filename' => $filename, 'meta_data' => $meta, 'mime' => $mime, 'mime_filter' => $mime_filter, 'mime_filters' => $mime_filters, 'tmp_filepath' => $tmppath, 'size' => $file_size, 'maxsize' => $this->options['maxUploadSize'], 'overwrite' => false, 'resize' => $resize_imgs, 'chmod' => $this->options['chmod'] & 0666, 'preliminary_json' => $jserr, 'validation_failure' => $v_ex_code);
         if (!empty($this->options['UploadIsAuthorized_cb']) && function_exists($this->options['UploadIsAuthorized_cb']) && !$this->options['UploadIsAuthorized_cb']($this, 'upload', $fileinfo)) {
             $v_ex_code = $fileinfo['validation_failure'];
             if (empty($v_ex_code)) {
                 $v_ex_code = 'authorized';
             }
         }
         if (!empty($v_ex_code)) {
             throw new FileManagerException($v_ex_code);
         }
         $legal_dir_url = $fileinfo['legal_dir_url'];
         $dir = $fileinfo['dir'];
         $file_arg = $fileinfo['raw_filename'];
         $filename = $fileinfo['filename'];
         $meta = $fileinfo['meta_data'];
         $mime = $fileinfo['mime'];
         $mime_filter = $fileinfo['mime_filter'];
         $mime_filters = $fileinfo['mime_filters'];
         //$tmppath = $fileinfo['tmp_filepath'];
         $resize_imgs = $fileinfo['resize'];
         $jserr = $fileinfo['preliminary_json'];
         if ($fileinfo['maxsize'] && $fileinfo['size'] > $fileinfo['maxsize']) {
             throw new FileManagerException('size');
         }
         //if (!isset($fileinfo['extension']))
         //  throw new FileManagerException('extension');
         // Creates safe file names
         if ($this->options['cleanFileName']) {
             $filename = FileManagerUtility::cleanUrl($filename, array(), '_');
         }
         // must transform here so alias/etc. expansions inside legal_url_path2file_path() get a chance:
         $legal_url = $legal_dir_url . $filename;
         $file = $this->legal_url_path2file_path($legal_url);
         if (!$fileinfo['overwrite'] && file_exists($file)) {
             throw new FileManagerException('exists');
         }
         if (!@move_uploaded_file($_FILES['Filedata']['tmp_name'], $file)) {
             $emsg = 'path';
             switch ($_FILES['Filedata']['error']) {
                 case 1:
                 case 2:
                     $emsg = 'size';
                     break;
                 case 3:
                     $emsg = 'partial';
                     break;
                 default:
                     $dir = $this->legal_url_path2file_path($legal_dir_url);
                     if (!is_dir($dir)) {
                         $emsg = 'path';
                     } else {
                         if (!is_writable($dir)) {
                             $emsg = 'path_not_writable';
                         } else {
                             $emsg = 'filename_maybe_too_large';
                         }
                     }
                     if (!empty($_FILES['Filedata']['error'])) {
                         $emsg .= ': error code = ' . strtolower($_FILES['Filedata']['error']) . ', ' . $emsg_add;
                     }
                     break;
             }
             throw new FileManagerException($emsg);
         }
         @chmod($file, $fileinfo['chmod']);
         /*
          * NOTE: you /can/ (and should be able to, IMHO) upload 'overly large' image files to your site, but the resizing process step
          *       happening here will fail; we have memory usage estimators in place to make the fatal crash a non-silent one, i,e, one
          *       where we still have a very high probability of NOT fatally crashing the PHP iunterpreter but catching a suitable exception
          *       instead.
          *       Having uploaded such huge images, a developer/somebody can always go in later and up the memory limit if the site admins
          *       feel it is deserved. Until then, no thumbnails of such images (though you /should/ be able to milkbox-view the real thing!)
          */
         $thumb250 = false;
         $thumb250_e = false;
         $thumb48 = false;
         $thumb48_e = false;
         if (FileManagerUtility::startsWith($mime, 'image/')) {
             if (!empty($resize_imgs)) {
                 $img = new Image($file);
                 $size = $img->getSize();
                 // Image::resize() takes care to maintain the proper aspect ratio, so this is easy
                 // (default quality is 100% for JPEG so we get the cleanest resized images here)
                 $img->resize($this->options['maxImageDimension']['width'], $this->options['maxImageDimension']['height'])->save();
                 unset($img);
                 // source image has changed: nuke the cached metadata and then refetch the metadata = forced refetch
                 $meta = $this->getFileInfo($file, $legal_url, true);
             }
         }
         /*
          * 'abuse' the info extraction process to generate the thumbnails. Besides, doing it this way will also prime the metadata cache for this item,
          * so we'll have a very fast performance viewing this file's details and thumbnails both from this point forward!
          */
         $jsbogus = array('status' => 1);
         $jsbogus = $this->extractDetailInfo($jsbogus, $legal_url, $meta, $mime_filter, $mime_filters, array('direct'));
         $this->sendHttpHeaders('Content-Type: ' . $this->getPOSTparam('reportContentType', 'application/json'));
         echo json_encode(array('status' => 1, 'name' => basename($file)));
         return;
     } catch (FileManagerException $e) {
         $emsg = $e->getMessage();
     } catch (Exception $e) {
         // catching other severe failures; since this can be anything and should only happen in the direst of circumstances, we don't bother translating
         $emsg = $e->getMessage();
     }
     $this->modify_json4exception($jserr, $emsg, 'file = ' . $this->mkSafe4Display($file_arg . ', destination path = ' . $file . ', target directory (URI path) = ' . $legal_dir_url));
     $this->sendHttpHeaders('Content-Type: ' . $this->getPOSTparam('reportContentType', 'application/json'));
     // when we fail here, it's pretty darn bad and nothing to it.
     // just push the error JSON and go.
     echo json_encode(array_merge($jserr, $_FILES));
 }