Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make PHP upload_progress SESSION work?

Tags:

php

I'm trying to make work an upload_progress session after a bunch of changes in php.ini like:

session.upload_progress.enabled = On

;session.upload_progress.cleanup = On

session.upload_progress.prefix = "upload_progress_"

session.upload_progress.name = "123"

session.upload_progress.freq =  "1%"

session.upload_progress.min_freq = "1"

and created and html based page with form to submit files:

<form action="upload_progress.php" method="POST" enctype="multipart/form-data">
  <input type="hidden" name="<?php echo ini_get("session.upload_progress.name"); ?>" value="123" />
  <input type="file" name="file1" />
  <input type="file" name="file2" />
  <input type="submit" />
</form>

and then the server side script which uploading files properly:

session_start();
move_uploaded_file($_FILES['file1']['tmp_name'], './uploads/'.$_FILES['file1']['name']);
move_uploaded_file($_FILES['file2']['tmp_name'], './uploads/'.$_FILES['file2']['name']);
print_r($_SESSION);

There is an empty array in the $_SESSION globals, although files upload completed correctly. What is the problem with session settings?

I'm using PHP 5.4.5

Notice: Undefined index: upload_progress_123 in C:\apache\localhost\www\upload_progress.php on line 13

like image 307
Arthur Kushman Avatar asked Aug 22 '12 10:08

Arthur Kushman


2 Answers

Upload progress via session in PHP is pretty tricky and not all context and circumstances are well documented. Number of similar questions indicates it causes troubles. I've personally lost more than a day on this so here is my advice to help you out.

  1. Obvious essential requirement: PHP version >= 5.4.0 and PHP not running as FastCGI. (How to find out.)
  2. For better debugging disable immediate session property cleaning in php.ini
    session.upload_progress.cleanup = Off
    This way you can check the contents of a session after the upload is done.
  3. Find out where session are being stored (variable session.save_path in php.ini, typical value on linux machines is /var/lib/php/sessions) and inspect them, look for an index named upload_progress_xxxxxxxxxxx after upload is initiated.

  4. To activate a particular upload progress tracking usually a hidden HTML form element is used. It must be sent before the file. If you think about it it's logical: when PHP is processing the request it must first encounter the signal to start tracking the file upload progress and after that recognize the file itself. The other way around, it won't work.

    <form action="upload_progress.php" method="POST" enctype="multipart/form-data">
        <input type="hidden" 
            name="<?php echo ini_get("session.upload_progress.name"); ?>" value="123" />
        <input type="file" name="myfile1" />
        <input type="submit" />
    </form>
    
  5. Carefully with AJAX submitting. Although it's unlikely, some JS libraries may change the order of elements in a HTTP request. You should check the actual HTTP communication using Developer tools in you browser and ensure that the order of elements being sent is in accordance with the previous point.

  6. Session name. While you may use any possible session name in your code, PHP does not know it and writes the upload progress always to the default session, usually PHPSESSID (consult your php.ini's property session.name to check the actual value.) This behavior is not a bug.
    If you mind two sessions are being created you should either change your code to use the default value or change the default value of session.name which is not always possible (e.g. shared hosting). Notice that the value can also be changed via .htaccess.

  7. Some PHP frameworks (Zend, Cake PHP) have it's own structure of session contents and PHP engine will corrupt the session when writing the upload progress into the session. Causing loss of stored information and thus effects like sign-outs, damages to tracking etc. Issue, issue, issue. I came to the conclusion that in that case 2 different sessions must be used.

My final solution

I'm using Zend Framework and I ended up with two separate sessions. I use the following plain PHP script to report a specific file upload progress. The script is totally isolated from Zend Framework and uses the default PHPSESSID namespace.

session_start();

if(!isset($_GET['id']))
  die("unsupported");

$id = $_GET['id'];

if(!preg_match('/^[a-zA-Z0-9]{1,32}$/', $id))
  die("unsupported");

$sessionKey = ini_get('session.upload_progress.prefix') . $id;
$uploadInfo = (isset($_SESSION[$sessionKey])) ? $_SESSION[$sessionKey] : null;

$status  = [
    'total'    => 0,
    'current'  => 0,
    'rate'     => 0,
    'message'  => '',
    'done'     => false,
];

if($uploadInfo === null)
{
  header('Content-Type: application/json');
  echo json_encode($status);
  return;
}

$status = $uploadInfo + $status;
$status['total']   = $status['content_length'];
$status['current'] = $status['bytes_processed'];

$time = time() - $status['start_time'];
$status['rate'] = ($time > 0) ? $status['bytes_processed'] / $time : 0;

if (!empty($status['cancel_upload'])) {
    $status['done'] = true;
    $status['message'] = 'The upload has been canceled';
}

header('Content-Type: application/json');
echo json_encode($status);

The application made on top of Zend Framework sets it's own session namespace in Module.php's onBootstrap() method:

$sessionManager = new \Zend\Session\SessionManager();
$sessionManager->setName('myFancyNamespace');
$sessionManager->start();
like image 171
Petr Sobotka Avatar answered Oct 13 '22 13:10

Petr Sobotka


Upload progress can be seen in $_SESSION Array, so can check progress in another php request.

$_SESSION will be available till files are being uploaded not after files have been uploaded. so once you handled files it will be gone. you should print_r this in separate request while files are being uploaded. not in the same request.

like in this example

check_progress.php

<?php 
if(isset($_SESSION['upload_progress_123']))){
   print_r($_SESSION['upload_progress_123']);
}
?>

Sample array

<?php
$_SESSION["upload_progress_123"] = array(
 "start_time" => 1234567890,   // The request time
 "content_length" => 57343257, // POST content length
 "bytes_processed" => 453489,  // Amount of bytes received and processed
 "done" => false,              // true when the POST handler has finished, successfully or not
 "files" => array(
  0 => array(
   "field_name" => "file1",       // Name of the <input/> field
   // The following 3 elements equals those in $_FILES
   "name" => "foo.avi",
   "tmp_name" => "/tmp/phpxxxxxx",
   "error" => 0,
   "done" => true,                // True when the POST handler has finished handling this file
   "start_time" => 1234567890,    // When this file has started to be processed
   "bytes_processed" => 57343250, // Number of bytes received and processed for this file
  ),
  // An other file, not finished uploading, in the same request
  1 => array(
   "field_name" => "file2",
   "name" => "bar.avi",
   "tmp_name" => NULL,
   "error" => 0,
   "done" => false,
   "start_time" => 1234567899,
   "bytes_processed" => 54554,
  ),
 )
);

Complete tutorial can be found here as pilif said

http://www.sitepoint.com/tracking-upload-progress-with-php-and-javascript/

http://oliversmith.io/technology/2011/12/04/php-5-4-file-upload-progress-and.html5-progress-bars/

see this answer as well. PhP Upload progress in PhP 5.4 is not working. Session variables not set

like image 1
dev.meghraj Avatar answered Oct 13 '22 13:10

dev.meghraj