18

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

Tchoupi
  • 14,560
  • 5
  • 37
  • 71
Arthur Kushman
  • 3,449
  • 10
  • 49
  • 64
  • Have you tried debugging your script? Does your session work? Can you set a `$_SESSION` variable and read it properly? Do you have error logging enabled, do you see any notice / warning? – Tchoupi Aug 22 '12 at 12:03
  • Yes, sessions working properly and of course I've tried to debug the script, the error is edited above in a question. I've forgot to add it at 1st time. – Arthur Kushman Aug 22 '12 at 12:29
  • Possible duplicate of [PhP Upload progress in PhP 5.4 is not working. Session variables not set](http://stackoverflow.com/questions/21703081/php-upload-progress-in-php-5-4-is-not-working-session-variables-not-set) – dev.meghraj Feb 23 '16 at 07:43

5 Answers5

5

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();
Community
  • 1
  • 1
Petr Sobotka
  • 703
  • 7
  • 8
1

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

Community
  • 1
  • 1
dev.meghraj
  • 8,542
  • 5
  • 38
  • 76
0

At the point where your script is calling move_uploaded_file() and the successive print_r(), the upload has already completed.

If you want to get access to the upload progress, you must

  • submit the uploaded form into a different browser window (so the JS on your current page can continue to run) or frame (use the target attribute on the form)
  • use an ajax call to repeatedly poll the server to query for the progress of the current session's upload.

The explanation on http://php.net/manual/en/session.upload-progress.php refers to different requests to the same session, not to the data inside of the same request.

A bit of Googling turned up http://www.sitepoint.com/tracking-upload-progress-with-php-and-javascript/ which goes into much more details and provides copy & pastable examples.

pilif
  • 12,548
  • 5
  • 34
  • 31
0

If you use DockerCompose with separate containers for NGINX and PHP, the session upload_progress_xxx will not be updated. It only works with PHP Server API set to "Apache x.x Handler".

I removed NGINX and instead used only the official PHP/Apache image and now it works fine. Here is my Docker-Compose file:

version: '3'
services:

   php:
     image: "php:7.0-apache"
     ports:
       - "8080:80"
     volumes:
       - ./www:/var/www/
       - ./etc/php/php.ini:/usr/local/etc/php/php.ini
Terje
  • 1
0

I know its a bit late but maybe this could help someone else.

Make sure you have set session.autostart in the php.ini to "On" without the quotes. This was the problem for me, so I was getting an empty array trying to track the upload progress.

I made a working upload progress with php.

Please see:

https://github.com/TychaK/Track-Upload-Progress-using-Session-Upload-Progress-PHP-JavaScript-Ajax

I hope this helps out other devs :-)

ahcyT
  • 560
  • 4
  • 11