Delay in populating session.upload_progress data
Asked Answered
C

2

0

I'm trying to check the progress of files uploaded. I'm using the Kohana framework which has a Session class, but for the upload progress I'm using native PHP sessions. I'm calling session_start() in Kohana's bootstrap.php, which means session_start() will be called on every page request.

After the upload form is submitted, I wait 1 second and then begin calling a PHP file to check the upload progress using jQuery $.ajax().

The problem is that $_SESSION[$key] ($key contains the key for the upload data) isn't set on the first call to the PHP. I've tried debugging this quite a bit, and session_id() returns the correct session ID, so the session is definitely the right one and is active. I'm also waiting 1 second before checking the upload progress, so it's not a timing issue. I could fix this by continuing even if $_SESSION[$key] is not set, but the way to check if the upload is complete is when $_SESSION[$key] is unset.

The HTML form is created on-the-fly with jQuery because this is a multi-file upload. Here's the HTML for a generated form:

<form action="ajax/upload" id="form-HZbAcYFuj3" name="form-HZbAcYFuj3" method="post" enctype="multipart/form-data" target="frame-HZbAcYFuj3">
    <iframe id="frame-HZbAcYFuj3" name="frame-HZbAcYFuj3"></iframe>
    <input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="HZbAcYFuj3">
    <input type="file" id="file-HZbAcYFuj3" name="photo" accept="image/jpeg,image/pjpeg,image/png,image/gif">
    <button type="button">+ Select Photo</button>
</form>

Here's the PHP that the JavaScript calls to check the progress:

public function action_uploadprogress()
{
    $id = isset($_POST['id']) ? $_POST['id'] : false;

    if (!$id)
        throw new Kohana_HTTP_Exception_404();

    $progress = 0;
    $upload_progress = false;

    $key = ini_get("session.upload_progress.prefix") . $id;

    if (isset($_SESSION[$key]))
        $upload_progress = $_SESSION[$key];
    else
        exit('100');

    $processed = $upload_progress['bytes_processed'];
    $size = $upload_progress['content_length'];

    if ($processed <= 0 || $size <= 0)
        throw new Kohana_HTTP_Exception_404();
    else
        $progress = round(($processed / $size) * 100, 2);

    echo $progress;
}

Here's the jQuery ajax() request:

this.send_request = function()
{
    $.ajax(
        {
            url: 'ajax/uploadprogress',
            type: 'post',
            dataType: 'html',
            data: { id: _this.id },
            success:
                function(data, textStatus, jqXHR)
                {
                    if (textStatus == "success")
                    {
                        if (data < 100)
                            setTimeout(_this.send_request, 1000);
                    }
                }
        }
    );
};
Centrist answered 12/10, 2013 at 16:35 Comment(2)
Where are you setting send_request.id?Precentor
Why the echo and not $this->response->body($progress) ?Muff
P
1

You are sending a POST called 'id' to the PHP script.

However, the documentation says that the upload progress will be available only when you send a POST with same name as session.upload_progress.name configured in php.ini.

So, in other words, if your session.upload_progress.name is set to default value (PHP_SESSION_UPLOAD_PROGRESS), you have to change the following line, in send_request function:

Change:

data: { id: _this.id }

To:

data: { PHP_SESSION_UPLOAD_PROGRESS: _this.id }

You also have to change the $_POST['id'] to $_POST['PHP_SESSION_UPLOAD_PROGRESS'] or $_POST[ini_get("session.upload_progress.name")] in the PHP script (and the name of input too in case it's not default).

The upload progress will be available in the $_SESSION superglobal when an upload is in progress, and when POSTing a variable of the same name as the session.upload_progress.name INI setting is set to. When PHP detects such POST requests, it will populate an array in the $_SESSION, where the index is a concatenated value of the session.upload_progress.prefix and session.upload_progress.name INI options. The key is typically retrieved by reading these INI settings, i.e.

Source: http://php.net/manual/pt_BR/session.upload-progress.php

Precentor answered 14/10, 2013 at 22:19 Comment(3)
Sweet, this fixed it! I've been wracking my brain for 2 weeks on this. All the examples I found only sent session.upload_progress.name in the <form> in a hidden input and not in the ajax to check the progress, but they worked even on my same server. None of these were inside of Kohana, so for some reason when inside Kohana there's a delay between when you submit the form and PHP populates the upload progress data, but sending session.upload_progress.name in the upload progress check I guess kick starts it? Not sure, but I'm happy to not think about this anymore! Thanks again.Centrist
It says I have to wait 6 hours to reward the bounty, but if all goes as planned I'll be proper drunk by then, so I'll probably send it tomorrow :)Centrist
@Rafael Figueiredo. Would you care to take a look at #21703581?Laconia
B
1

Lets see if I can get some of that sweet sweet bounty.. My first thought is that the $key string is not getting set properly.

Try echoing its value out and doing a print_r on the entire $_SESSION variable to keep track of things.

Now I don't see a 'success' output from action_uploadprogress() at all. I see 100 which I guess indicates done but you aren't checking for that in js. I would recommend looking into that. Might as well echo out your calculations as well. I assume its very unlikely but make sure that you are uploading files properly and are able to determine their current size without any issue.

Another issue could be with how you are handling ajax with jquery. I'm not 100% sure about this but I think the success option has been depreciated (1.5+).

From : http://api.jquery.com/jQuery.ajax/

$.ajax({
    type: "POST",
    url: "some.php",
    data: { name: "John", location: "Boston" }
}).done(function( msg ) {
    alert( "Data Saved: " + msg );
});

The only way I've seen success being used is like this....

  $.ajax({
        type: "POST",
        url: '/login/spam',
        data: formData,
        success: function (data) {
            if (data == 'value') {
                 //Do stuff
            }
        }
    }); 

However I could be completely wrong about this....your setup might be perfectly fine. What I want you to do is get is directly in the success/done function is

 alert(data);
 alert(textStatus); //if you still use it

This will tell you if you are getting a proper response from your ajax query.

I will check back a few times tonight and I'll be around tomorrow to help. Tell me if anything I said helps anything.

Burnsides answered 14/10, 2013 at 21:2 Comment(1)
Hey I really appreciate your detailed response. Rafael Gomes Figueiredo actually got the problem exactly right and that fixed it.Centrist
P
1

You are sending a POST called 'id' to the PHP script.

However, the documentation says that the upload progress will be available only when you send a POST with same name as session.upload_progress.name configured in php.ini.

So, in other words, if your session.upload_progress.name is set to default value (PHP_SESSION_UPLOAD_PROGRESS), you have to change the following line, in send_request function:

Change:

data: { id: _this.id }

To:

data: { PHP_SESSION_UPLOAD_PROGRESS: _this.id }

You also have to change the $_POST['id'] to $_POST['PHP_SESSION_UPLOAD_PROGRESS'] or $_POST[ini_get("session.upload_progress.name")] in the PHP script (and the name of input too in case it's not default).

The upload progress will be available in the $_SESSION superglobal when an upload is in progress, and when POSTing a variable of the same name as the session.upload_progress.name INI setting is set to. When PHP detects such POST requests, it will populate an array in the $_SESSION, where the index is a concatenated value of the session.upload_progress.prefix and session.upload_progress.name INI options. The key is typically retrieved by reading these INI settings, i.e.

Source: http://php.net/manual/pt_BR/session.upload-progress.php

Precentor answered 14/10, 2013 at 22:19 Comment(3)
Sweet, this fixed it! I've been wracking my brain for 2 weeks on this. All the examples I found only sent session.upload_progress.name in the <form> in a hidden input and not in the ajax to check the progress, but they worked even on my same server. None of these were inside of Kohana, so for some reason when inside Kohana there's a delay between when you submit the form and PHP populates the upload progress data, but sending session.upload_progress.name in the upload progress check I guess kick starts it? Not sure, but I'm happy to not think about this anymore! Thanks again.Centrist
It says I have to wait 6 hours to reward the bounty, but if all goes as planned I'll be proper drunk by then, so I'll probably send it tomorrow :)Centrist
@Rafael Figueiredo. Would you care to take a look at #21703581?Laconia

© 2022 - 2024 — McMap. All rights reserved.