fine-uploader implementation
Asked Answered
M

1

1

I have my HTML file:

<html>
  <head>
    <meta charset="utf-8">
    <title>Fine Uploader Demo</title>
    <link href="fineuploader-3.4.1.css" rel="stylesheet">
  </head>
  <body>
    <div id="fine-uploader"></div>
   <script src="jquery-1.7.2.min.js"></script>
    <script src="jquery.fineuploader-3.4.1.js"></script>
    <script>

      function createUploader() {
       var uploader = new qq.FineUploader({
          // Pass the HTML element here
         element: document.getElementById('fine-uploader'),
          // or, if using jQuery
          // element: $('#fine-uploader')[0],
          // Use the relevant server script url here
          // if it's different from the default “/server/upload”
         request: {
            endpoint: 'qqFileUploader'
          }
        });
      }

      window.onload = createUploader;
    </script>
  </body>
</html>

My PHP Code qqFileUploader.php

<?php

class qqFileUploader {

    public $allowedExtensions = array();
    public $sizeLimit = null;
    public $inputName = 'qqfile';
    public $chunksFolder = 'chunks';

    public $chunksCleanupProbability = 0.001; // Once in 1000 requests on avg
    public $chunksExpireIn = 604800; // One week

    protected $uploadName;

    function __construct(){
        $this->sizeLimit = $this->toBytes(ini_get('upload_max_filesize'));
    }

    /**
     * Get the original filename
     */
    public function getName(){
        if (isset($_REQUEST['qqfilename']))
            return $_REQUEST['qqfilename'];

        if (isset($_FILES[$this->inputName]))
            return $_FILES[$this->inputName]['name'];
    }

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

    /**
     * Process the upload.
     * @param string $uploadDirectory Target directory.
     * @param string $name Overwrites the name of the file.
     */
    public function handleUpload($uploadDirectory, $name = null){

        if (is_writable($this->chunksFolder) &&
            1 == mt_rand(1, 1/$this->chunksCleanupProbability)){

            // Run garbage collection
            $this->cleanupChunks();
        }

        // Check that the max upload size specified in class configuration does not
        // exceed size allowed by server config
        if ($this->toBytes(ini_get('post_max_size')) < $this->sizeLimit ||
            $this->toBytes(ini_get('upload_max_filesize')) < $this->sizeLimit){
            $size = max(1, $this->sizeLimit / 1024 / 1024) . 'M';
            return array('error'=>"Server error. Increase post_max_size and upload_max_filesize to ".$size);
        }

        // is_writable() is not reliable on Windows (http://www.php.net/manual/en/function.is-executable.php#111146)
        // The following tests if the current OS is Windows and if so, merely checks if the folder is writable;
        // otherwise, it checks additionally for executable status (like before).

        $isWin = (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN');
        $folderInaccessible = ($isWin) ? !is_writable($uploadDirectory) : ( !is_writable($uploadDirectory) && !is_executable($uploadDirectory) );

        if ($folderInaccessible){
            return array('error' => "Server error. Uploads directory isn't writable" . (!$isWin) ? " or executable." : ".");
        }

        if(!isset($_SERVER['CONTENT_TYPE'])) {
            return array('error' => "No files were uploaded.");
        } else if (strpos(strtolower($_SERVER['CONTENT_TYPE']), 'multipart/') !== 0){
            return array('error' => "Server error. Not a multipart request. Please set forceMultipart to default value (true).");
        }

        // Get size and name

        $file = $_FILES[$this->inputName];
        $size = $file['size'];

        if ($name === null){
            $name = $this->getName();
        }

        // Validate name

        if ($name === null || $name === ''){
            return array('error' => 'File name empty.');
        }

        // Validate file size

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

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

        // Validate file extension

        $pathinfo = pathinfo($name);
        $ext = isset($pathinfo['extension']) ? $pathinfo['extension'] : '';

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

        // Save a chunk

        $totalParts = isset($_REQUEST['qqtotalparts']) ? (int)$_REQUEST['qqtotalparts'] : 1;

        if ($totalParts > 1){

            $chunksFolder = $this->chunksFolder;
            $partIndex = (int)$_REQUEST['qqpartindex'];
            $uuid = $_REQUEST['qquuid'];

            if (!is_writable($chunksFolder) && !is_executable($uploadDirectory)){
                return array('error' => "Server error. Chunks directory isn't writable or executable.");
            }

            $targetFolder = $this->chunksFolder.DIRECTORY_SEPARATOR.$uuid;

            if (!file_exists($targetFolder)){
                mkdir($targetFolder);
            }

            $target = $targetFolder.'/'.$partIndex;
            $success = move_uploaded_file($_FILES[$this->inputName]['tmp_name'], $target);

            // Last chunk saved successfully
            if ($success AND ($totalParts-1 == $partIndex)){

                $target = $this->getUniqueTargetPath($uploadDirectory, $name);
                $this->uploadName = basename($target);

                $target = fopen($target, 'wb');

                for ($i=0; $i<$totalParts; $i++){
                    $chunk = fopen($targetFolder.DIRECTORY_SEPARATOR.$i, "rb");
                    stream_copy_to_stream($chunk, $target);
                    fclose($chunk);
                }

                // Success
                fclose($target);

                for ($i=0; $i<$totalParts; $i++){
                    unlink($targetFolder.DIRECTORY_SEPARATOR.$i);
                }

                rmdir($targetFolder);

                return array("success" => true);

            }

            return array("success" => true);

        } else {

            $target = $this->getUniqueTargetPath($uploadDirectory, $name);

            if ($target){
                $this->uploadName = basename($target);

                if (move_uploaded_file($file['tmp_name'], $target)){
                    return array('success'=> true);
                }
            }

            return array('error'=> 'Could not save uploaded file.' .
                'The upload was cancelled, or server error encountered');
        }
    }

    /**
     * Returns a path to use with this upload. Check that the name does not exist,
     * and appends a suffix otherwise.
     * @param string $uploadDirectory Target directory
     * @param string $filename The name of the file to use.
     */
    protected function getUniqueTargetPath($uploadDirectory, $filename)
    {
        // Allow only one process at the time to get a unique file name, otherwise
        // if multiple people would upload a file with the same name at the same time
        // only the latest would be saved.

        if (function_exists('sem_acquire')){
            $lock = sem_get(ftok(__FILE__, 'u'));
            sem_acquire($lock);
        }

        $pathinfo = pathinfo($filename);
        $base = $pathinfo['filename'];
        $ext = isset($pathinfo['extension']) ? $pathinfo['extension'] : '';
        $ext = $ext == '' ? $ext : '.' . $ext;

        $unique = $base;
        $suffix = 0;

        // Get unique file name for the file, by appending random suffix.

        while (file_exists($uploadDirectory . DIRECTORY_SEPARATOR . $unique . $ext)){
            $suffix += rand(1, 999);
            $unique = $base.'-'.$suffix;
        }

        $result =  $uploadDirectory . DIRECTORY_SEPARATOR . $unique . $ext;

        // Create an empty target file
        if (!touch($result)){
            // Failed
            $result = false;
        }

        if (function_exists('sem_acquire')){
            sem_release($lock);
        }

        return $result;
    }

    /**
     * Deletes all file parts in the chunks folder for files uploaded
     * more than chunksExpireIn seconds ago
     */
    protected function cleanupChunks(){
        foreach (scandir($this->chunksFolder) as $item){
            if ($item == "." || $item == "..")
                continue;

            $path = $this->chunksFolder.DIRECTORY_SEPARATOR.$item;

            if (!is_dir($path))
                continue;

            if (time() - filemtime($path) > $this->chunksExpireIn){
                $this->removeDir($path);
            }
        }
    }

    /**
     * Removes a directory and all files contained inside
     * @param string $dir
     */
    protected function removeDir($dir){
        foreach (scandir($dir) as $item){
            if ($item == "." || $item == "..")
                continue;

            unlink($dir.DIRECTORY_SEPARATOR.$item);
        }
        rmdir($dir);
    }

    /**
     * Converts a given size with units to bytes.
     * @param string $str
     */
    protected 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;
    }
}

When I upload as file, I get the follwing two errors and my file upload fails:

Error 1

OPTIONS file:///C:/Users/upload/qqFileUploader  jquery.fineuploader-3.4.1.js:3903
handleStandardFileUpload jquery.fineuploader-3.4.1.js:3903
api.upload jquery.fineuploader-3.4.1.js:3989
upload jquery.fineuploader-3.4.1.js:3041
qq.FineUploaderBasic._upload jquery.fineuploader-3.4.1.js:1437
qq.FineUploaderBasic._uploadFileOrBlobDataList jquery.fineuploader-3.4.1.js:1415
qq.FineUploaderBasic.addFiles jquery.fineuploader-3.4.1.js:1049
qq.FineUploaderBasic._onInputChange jquery.fineuploader-3.4.1.js:1340
qq.UploadButton.onChange jquery.fineuploader-3.4.1.js:1117
(anonymous function) jquery.fineuploader-3.4.1.js:680

Error 2

[FineUploader] Error when attempting to parse xhr response text (SyntaxError: Unexpected end of input) jquery.fineuploader-3.4.1.js:155
qq.log jquery.fineuploader-3.4.1.js:155
qq.FineUploaderBasic.log jquery.fineuploader-3.4.1.js:939
qq.UploadHandler.log jquery.fineuploader-3.4.1.js:1146
parseResponse jquery.fineuploader-3.4.1.js:3683
onComplete jquery.fineuploader-3.4.1.js:3732
(anonymous function) jquery.fineuploader-3.4.1.js:3766

When debug is set to true, I get this:

[FineUploader] xhr - server response received for 0 jquery.fineuploader-3.4.1.js:150
[FineUploader] responseText = <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL php/qqFileUploader.php was not found on this server.</p>
<hr>
<address>Apache/2.2.15 (CentOS) Server at Port 80</address>
</body></html>
Margalo answered 8/4, 2013 at 20:46 Comment(0)
S
2

You haven't set your endpoint correctly, it appears. Your endpoint must be a relative or absolute URL pointing at the location on your server setup to handle Fine Uploader's requests. It also looks like you may not be running your app in a webserver. It seems like you are simply opening up a web browser and pointing at an html file on your filesystem. That is never going to work.

Please see the demos on fineuploader.com as well as the request option documentation in the readme.

Stevestevedore answered 8/4, 2013 at 20:50 Comment(7)
I am testing this locally.By the wya, is the php file I am using correct?Margalo
Are you hosting your app in a web/app server locally, such as Apache, Jetty, Tomcat, or nginx?Stevestevedore
No, I was initially doing it locally. Now, I used my server, and it give me the following error: [FineUploader] Error when attempting to parse xhr response text (SyntaxError: Unexpected token <). it is line number jquery.fineuploader-3.4.1.js:155Margalo
i read the doc but i did not get how an end point should be set. can you please elaborate, sir?Margalo
The endpoint must be a relative or absolute URL/path pointing at the location on your server setup to handle Fine Uploader's requests. Same concept as the action attribute on a form element.Stevestevedore
let us continue this discussion in chat,pleaseMargalo
Has someone experienced similar issue?Margalo

© 2022 - 2024 — McMap. All rights reserved.