Fine-uploader PHP Слияние на стороне сервера

Я экспериментировал с Fine Uploader. Меня действительно интересуют функции фрагментации и возобновления, но я испытываю трудности с объединением файлов на стороне сервера;

Я обнаружил, что мне нужно разрешить пустое расширение файла на стороне сервера, чтобы разрешить загрузку фрагментов, иначе загрузка завершится ошибкой с неизвестным типом файла. Он отлично загружает фрагменты с именами файлов, такими как «blob» и «blob63» (без расширения файла), однако не объединяет их обратно по завершении загрузки.

Любая помощь или указатели будут оценены.

$('#edit-file-uploader').fineUploader({
            request: {
                endpoint: 'upload.php'
            },
            multiple: false,
            validation:{
                allowedExtentions: ['stl', 'obj', '3ds', 'zpr', 'zip'],
                sizeLimit: 104857600  // 100mb * 1024 (kb) * 1024 (bytes)
            },
            text: {
                uploadButton: 'Select File'
            },
            autoUpload: false, 
            chunking: {
              enabled: true
            },
            callbacks: {
                 onComplete: function(id, fileName, responseJSON) {
                  if (responseJSON.success) {
                     /** some code here **??
                  }
           }

    });

А это скрипт на стороне сервера (PHP):

// list of valid extensions, ex. array("stl", "xml", "bmp")
$allowedExtensions = array("stl", "");
// max file size in bytes
$sizeLimit = null;

$uploader = new qqFileUploader($allowedExtensions, $sizeLimit);

// Call handleUpload() with the name of the folder, relative to PHP's getcwd()
$result = $uploader->handleUpload('uploads/');

// to pass data through iframe you will need to encode all html tags
echo htmlspecialchars(json_encode($result), ENT_NOQUOTES);

/******************************************/



/**
 * Handle file uploads via XMLHttpRequest
 */
class qqUploadedFileXhr {
    /**
     * Save the file to the specified path
     * @return boolean TRUE on success
     */
    public function save($path) {    
        $input = fopen("php://input", "r");
        $temp = tmpfile();
        $realSize = stream_copy_to_stream($input, $temp);
        fclose($input);

        if ($realSize != $this->getSize()){            
            return false;
        }

        $target = fopen($path, "w");        
        fseek($temp, 0, SEEK_SET);
        stream_copy_to_stream($temp, $target);
        fclose($target);

        return true;
    }

    /**
     * Get the original filename
     * @return string filename
     */
    public function getName() {
        return $_GET['qqfile'];
    }

    /**
     * Get the file size
     * @return integer file-size in byte
     */
    public function getSize() {
        if (isset($_SERVER["CONTENT_LENGTH"])){
            return (int)$_SERVER["CONTENT_LENGTH"];            
        } else {
            throw new Exception('Getting content length is not supported.');
        }      
    }   
}

/**
 * Handle file uploads via regular form post (uses the $_FILES array)
 */
class qqUploadedFileForm {

    /**
     * Save the file to the specified path
     * @return boolean TRUE on success
     */
    public function save($path) {
        return move_uploaded_file($_FILES['qqfile']['tmp_name'], $path);
    }

    /**
     * Get the original filename
     * @return string filename
     */
    public function getName() {
        return $_FILES['qqfile']['name'];
    }

    /**
     * Get the file size
     * @return integer file-size in byte
     */
    public function getSize() {
        return $_FILES['qqfile']['size'];
    }
}

/**
 * Class that encapsulates the file-upload internals
 */
class qqFileUploader {
    private $allowedExtensions;
    private $sizeLimit;
    private $file;
    private $uploadName;

    /**
     * @param array $allowedExtensions; defaults to an empty array
     * @param int $sizeLimit; defaults to the server's upload_max_filesize setting
     */
    function __construct(array $allowedExtensions = null, $sizeLimit = null){
        if($allowedExtensions===null) {
            $allowedExtensions = array();
        }
        if($sizeLimit===null) {
            $sizeLimit = $this->toBytes(ini_get('upload_max_filesize'));
        }

        $allowedExtensions = array_map("strtolower", $allowedExtensions);

        $this->allowedExtensions = $allowedExtensions;        
        $this->sizeLimit = $sizeLimit;

        $this->checkServerSettings();       

        if(!isset($_SERVER['CONTENT_TYPE'])) {
            $this->file = false;    
        } else if (strpos(strtolower($_SERVER['CONTENT_TYPE']), 'multipart/') === 0) {
            $this->file = new qqUploadedFileForm();
        } else {
            $this->file = new qqUploadedFileXhr();
        }
    }

    /**
     * Get the name of the uploaded file
     * @return string
     */
    public function getUploadName(){
        if( isset( $this->uploadName ) )
            return $this->uploadName;
    }

    /**
     * Get the original filename
     * @return string filename
     */
    public function getName(){
        if ($this->file)
            return $this->file->getName();
    }

    /**
     * Internal function that checks if server's may sizes match the
     * object's maximum size for uploads
     */
    private function checkServerSettings(){        
        $postSize = $this->toBytes(ini_get('post_max_size'));
        $uploadSize = $this->toBytes(ini_get('upload_max_filesize'));        

        if ($postSize < $this->sizeLimit || $uploadSize < $this->sizeLimit){
            $size = max(1, $this->sizeLimit / 1024 / 1024) . 'M';             
            die(json_encode(array('error'=>'increase post_max_size and upload_max_filesize to ' . $size)));    
        }        
    }

    /**
     * Convert a given size with units to bytes
     * @param string $str
     */
    private function toBytes($str){
        $val = trim($str);
        $last = strtolower($str[strlen($str)-1]);
        switch($last) {
            case 'g': $val *= 1024;
            case 'm': $val *= 1024;
            case 'k': $val *= 1024;        
        }
        return $val;
    }

    /**
     * Handle the uploaded file
     * @param string $uploadDirectory
     * @param string $replaceOldFile=true
     * @returns array('success'=>true) or array('error'=>'error message')
     */
    function handleUpload($uploadDirectory, $replaceOldFile = FALSE){
        if (!is_writable($uploadDirectory)){
            return array('error' => "Server error. Upload directory isn't writable.");
        }

        if (!$this->file){
            return array('error' => 'No files were uploaded.');
        }

        $size = $this->file->getSize();

        if ($size == 0) {
            return array('error' => 'File is empty');
        }

        if ($size > $this->sizeLimit) {
            return array('error' => 'File is too large');
        }

        $pathinfo = pathinfo($this->file->getName());
        $filename = $pathinfo['filename'];
        //$filename = md5(uniqid());
        $ext = @$pathinfo['extension'];        // hide notices if extension is empty

        if($this->allowedExtensions && !in_array(strtolower($ext), $this->allowedExtensions)){
            $these = implode(', ', $this->allowedExtensions);
            return array('error' => 'File has an invalid extension, it should be one of '. $these . '.');
        }

        $ext = ($ext == '') ? $ext : '.' . $ext;

        if(!$replaceOldFile){
            /// don't overwrite previous files that were uploaded
            while (file_exists($uploadDirectory . DIRECTORY_SEPARATOR . $filename . $ext)) {
                $filename .= rand(10, 99);
            }
        }

        $this->uploadName = $filename . $ext;

        if ($this->file->save($uploadDirectory . DIRECTORY_SEPARATOR . $filename . $ext)){
            return array('success'=>true);
        } else {
            return array('error'=> 'Could not save uploaded file.' .
                'The upload was cancelled, or server error encountered');
        }

    }    
}

person Jason Mitchell    schedule 16.08.2013    source источник


Ответы (1)


Чтобы обрабатывать запросы, разделенные на фрагменты, вы ДОЛЖНЫ хранить каждый фрагмент отдельно в своей файловой системе.
Как вы называете эти фрагменты или где вы их храните, зависит от вас, но я предлагаю вам назвать их, используя UUID, предоставленный Fine Uploader, и добавить параметр номера детали, включенный в каждый запрос на фрагментацию. После отправки последнего фрагмента объедините все фрагменты в один файл с правильным именем и верните стандартный ответ об успешном завершении, как описано в документации Fine Uploader. Исходное имя файла по умолчанию передается в параметре qqfilename при каждом запросе. Это также обсуждается в документах и блог.

Не похоже, что вы пытались обрабатывать фрагменты на стороне сервера. Существует пример PHP в Widen/fine-uploader- серверный репозиторий, который вы можете использовать. Кроме того, в документации есть раздел «на стороне сервера», в котором подробно объясняется, как обрабатывать фрагменты. Я предполагаю, что вы не читали это. Посмотрите.) в репозитории Widen/fine-uploader-server, который вы можете использовать. Кроме того, в документации есть раздел «на стороне сервера», в котором подробно объясняется, как обрабатывать фрагменты. Я предполагаю, что вы не читали это. Посмотри.

Обратите внимание, что, начиная с Fine Uploader 3.8 (который будет выпущен ОЧЕНЬ скоро), вы сможете делегировать всю обработку загрузки на стороне сервера Amazon S3, поскольку Fine Uploader обеспечит тесную интеграцию с S3, которая отправляет все ваши файлы прямо в вашу корзину. из браузера, и вам не нужно беспокоиться о создании документа политики, выполнении вызовов REST API, обработке ответов от S3 и т. д. Я упоминаю об этом, поскольку использование S3 означает, что вам больше не придется беспокоиться об обработке таких вещей, как сегментированные запросы на вашем сервере.

person Ray Nicholus    schedule 16.08.2013