Search code examples
javascriptphpextjsextjs4

How to use the extra params in ExtJS Upload Widget by Ivan Novakov


I am using this upload widget in my web application.

I am using the FormDataUploader and I am able to upload files to a server directory quite well. However, I wanted to send extra parameters as well to the php file handling the upload. This is what I attempted:

var uploadPanel = Ext.create('Ext.ux.upload.Panel', {
    uploader : 'Ext.ux.upload.uploader.FormDataUploader',

    uploaderOptions : {
       url : 'uploadGallery.php'
    },

    synchronous : true,

    uploadParams : {
        ID_Person : ID_Person,
        ID_CI : ID_CI
    }

});

As you can see, I used the uploadParams, however, my PHP couldn't seem to receive it. In my php file, I have:

$ID_Person = $_GET['ID_Person'];
$ID_CI = $_GET['ID_CI'];

However, my PHP seems to be unable to get these params.

What I did next was to use the default ExtJS Uploader as such:

var uploadPanel = Ext.create('Ext.ux.upload.Panel', {
    uploaderOptions : {
        url : 'uploadExtJS.php'

    },

    synchronous : true,

    uploadParams : {
        ID_Person : ID_Person,
        ID_CI : ID_CI
    }

});

At first, I used the old PHP file which was able to get the extra params I sent. However, it seems that I needed to use a different PHP file for the ExtJS uploader.

This is what my PHP file looks like:

<?php
/**
 * Example processing of raw PUT/POST uploaded files.
 * File metadata may be sent through appropriate HTTP headers:
 *   - file name - the 'X-File-Name' proprietary header
 *   - file size - the standard 'Content-Length' header or the 'X-File-Size' proprietary header
 *   - file type - the standard 'Content-Type' header or the 'X-File-Type' proprietary header
 * 
 * Raw data are read from the standard input.
 * The response should be a JSON encoded string with these items:
 *   - success (boolean) - if the upload has been successful
 *   - message (string) - optional message, useful in case of error
 */
require __DIR__ . '_common.php';
$config = require __DIR__ . '_config.php';

error_reporting(-1);
ini_set('display_errors', 'On');

/*
 * You should check these values for XSS or SQL injection.
 */
if (!isset($_SERVER['HTTP_X_FILE_NAME'])) {
    _error('Unknown file name');
}
$fileName = $_SERVER['HTTP_X_FILE_NAME'];
if (isset($_SERVER['HTTP_X_FILENAME_ENCODER']) && 'base64' == $_SERVER['HTTP_X_FILENAME_ENCODER']) {
    $fileName = base64_decode($fileName);
}
$fileName = htmlspecialchars($fileName);

$mimeType = htmlspecialchars($_SERVER['HTTP_X_FILE_TYPE']);
$size = intval($_SERVER['HTTP_X_FILE_SIZE']);


$inputStream = fopen('php://input', 'r');
// $outputFilename = $config['upload_dir'] . '/' . $fileName;
$outputFilename = 'gallery' . '/' . $fileName;
$realSize = 0;
$data = '';

if ($inputStream) {
    if (! $config['fake']) {
        $outputStream = fopen($outputFilename, 'w');
        if (! $outputStream) {
            _error('Error creating local file');
        }
    }

    while (! feof($inputStream)) {
        $bytesWritten = 0;
        $data = fread($inputStream, 1024);

        if (! $config['fake']) {
            $bytesWritten = fwrite($outputStream, $data);
        } else {
            $bytesWritten = strlen($data);
        }

        if (false === $bytesWritten) {
            _error('Error writing data to file');
        }
        $realSize += $bytesWritten;
    }

    if (! $config['fake']) {
        fclose($outputStream);
    }
} else {
    _error('Error reading input');
}

if ($realSize != $size) {
    _error('The actual size differs from the declared size in the headers');
}

_log(sprintf("[raw] Uploaded %s, %s, %d byte(s)", $fileName, $mimeType, $realSize));
_response();

However, I am getting an Internal Server 500 Error - Meaning that there was something probably wrong with my php file.

I mainly have two questions:

  1. How do I make the uploadParams work with the FormDataUploader?
  2. How do I write a PHP uploader for an ExtJS Data Uploader?

Solution

  • Got it to work.

    The uploadExtJS.php file should look like:

    <?php
    /**
     * Example processing of raw PUT/POST uploaded files.
     * File metadata may be sent through appropriate HTTP headers:
     *   - file name - the 'X-File-Name' proprietary header
     *   - file size - the standard 'Content-Length' header or the 'X-File-Size' proprietary header
     *   - file type - the standard 'Content-Type' header or the 'X-File-Type' proprietary header
     * 
     * Raw data are read from the standard input.
     * The response should be a JSON encoded string with these items:
     *   - success (boolean) - if the upload has been successful
     *   - message (string) - optional message, useful in case of error
     */
    // require  __DIR__ . '_common.php';
    // $config = require  __DIR__ .  '_config.php';
    
    require_once '_common.php';
    $config = require_once '_config.php';
    
    error_reporting(-1);
    ini_set('display_errors', 'On');
    
    /*
     * You should check these values for XSS or SQL injection.
     */
    if (!isset($_SERVER['HTTP_X_FILE_NAME'])) {
        _error('Unknown file name');
    }
    $fileName = $_SERVER['HTTP_X_FILE_NAME'];
    if (isset($_SERVER['HTTP_X_FILENAME_ENCODER']) && 'base64' == $_SERVER['HTTP_X_FILENAME_ENCODER']) {
        $fileName = base64_decode($fileName);
    }
    $fileName = htmlspecialchars($fileName);
    
    $mimeType = htmlspecialchars($_SERVER['HTTP_X_FILE_TYPE']);
    $size = intval($_SERVER['HTTP_X_FILE_SIZE']);
    
    
    $inputStream = fopen('php://input', 'r');
    $outputFilename = $config['upload_dir'] . '/' . $fileName;
    // $outputFilename = 'gallery' . '/' . $fileName;
    $realSize = 0;
    $data = '';
    
    if ($inputStream) {
        if (! $config['fake']) {
            $outputStream = fopen($outputFilename, 'w');
            if (! $outputStream) {
                _error('Error creating local file');
            }
        }
    
        while (! feof($inputStream)) {
            $bytesWritten = 0;
            $data = fread($inputStream, 1024);
    
            if (! $config['fake']) {
                $bytesWritten = fwrite($outputStream, $data);
            } else {
                $bytesWritten = strlen($data);
            }
    
            if (false === $bytesWritten) {
                _error('Error writing data to file');
            }
            $realSize += $bytesWritten;
        }
    
        if (! $config['fake']) {
            fclose($outputStream);
        }
    } else {
        _error('Error reading input');
    }
    
    if ($realSize != $size) {
        _error('The actual size differs from the declared size in the headers');
    }
    
    _log(sprintf("[raw] Uploaded %s, %s, %d byte(s)", $fileName, $mimeType, $realSize));
    _response(true, "okay");
    

    _common.php looks like:

    <?php
    
    function _log($value){
        error_log(print_r($value, true));
    }
    
    
    function _response($success = true, $message = 'OK'){
        $response = array(
            'success' => $success,
            'message' => $message
        );
    
        echo json_encode($response);
        exit();
    }
    
    function _error($message){
        return _response(false, $message);
    }
    

    _config.php should look like:

    <?php
    return array(
        'upload_dir' => 'gallery',
        'fake' => false
    );
    ?>
    

    and now I'm working on using a unique name using uniqid() and microtime(), as well as saving the images to a subdirectory (or any folder under your main upload/gallery folder) using the uploadParams() property.

    EDIT 1: RENAMING THE UPLOADED FILE

    just change this line:

    $fileName = htmlspecialchars($fileName);
    

    to:

    $fileName = uniqid() . '_' . microtime();
    

    EDIT 3: TO GET THE CUSTOM SUB DIRECTORY FROM YOUR ADDITIONAL PARAMS

    First, make sure than when you create your Upload Dialog from your ExtJS web app, you do this:

    var uploadPanel = Ext.create('Ext.ux.upload.Panel', {
        uploaderOptions : {
            url : 'uploadExtJS.php'
    
        },
        synchronous : true,
        uploadParams : {
            ID_1 : ID_1,
            ID_2 : ID_2 // you can put waaay more if you want
        }
    });
    

    and in your uploadExtJS.php, do this (between the part where you define your new file name and the part where you check for input stream)

    $fileName = uniqid() . '_' . microtime();
    
    $mimeType = htmlspecialchars($_SERVER['HTTP_X_FILE_TYPE']);
    $size = intval($_SERVER['HTTP_X_FILE_SIZE']);
    
    $ID_1 = $_GET['ID_1'];
    $ID_2 = $_GET['ID_2'];
    
    $newFilePath = $config['upload_dir'] . '/' . $ID_1 . '/' . $ID_2;
    
    if (!file_exists($newFilePath)) {
        mkdir($newFilePath, 0777, true);
    }
    
    $inputStream = fopen('php://input', 'r');
    $outputFilename = $newFilePath . '/' . $fileName;
    
    $realSize = 0;
    $data = '';
    

    As you can see, I defined a $newFilePath variable, checked if it was existing before making it, then uploaded to that directory.

    Hope this helps anyone who encounters the issue in the future.