Session Upload Progress
Asked Answered
C

2

4

I'm trying to get the Session Upload Progress feature ( http://php.net/manual/en/session.upload-progress.php ) to work in Kohana. I have managed to get it working locally without Kohana using the following code:

<?php
    session_start();
    if (isset($_GET['progress']))
    {
        // does key exist
        $key = ini_get("session.upload_progress.prefix") . 'demo';
        if ( !isset( $_SESSION[$key] ) ) exit( "uploading..." );

        // workout percentage
        $upload_progress = $_SESSION[$key];
        $progress = round( ($upload_progress['bytes_processed'] / $upload_progress['content_length']) * 100, 2 );

        exit( "Upload progress: $progress%" );
    }
?>
<!doctype html>
<head>
</head>
<body>
    <section>
        <h1>Upload Form</h1>
        <form action="" method="POST" enctype="multipart/form-data" target="upload-frame">
            <input type="hidden" name="<?php echo ini_get("session.upload_progress.name"); ?>" value="<?php //echo $uid; ?>demo">
            <p>
                <label>File:</label>
                <input type="file" name="file" required="required">
            </p>
            <p><input type="submit" name="submit" value="Upload"></p>
        </form>

        <iframe id="upload-frame" name="upload-frame" width="1280" height="600"></iframe>

        <div id="file_upload_progress"></div>
    </section>

    <script src="jquery-1.7.1.min.js"></script>
    <script>
        $(document).ready(function() {

            var uploading = false;
            $('form').submit(function() {

                uploading = true;
                $('#upload-frame').one('load', function(){
                    uploading = false;
                });

                function update_file_upload_progress() {
                    $.get("?progress", function(data) {
                        $("#file_upload_progress").html(data);
                        if (uploading) {
                            setTimeout( update_file_upload_progress, 500 );
                        }
                    })
                    .error(function(jqXHR, error) { 
                        alert(error); 
                    });
                }

                // first call
                update_file_upload_progress();
            });
      });
    </script>
</body>
</html>

However when I use this code in Kohana (separating the PHP into a controller of course) the $_SESSION variable does not get created for tracking the progress of the upload.

I believe this is something to do with how sessions in Kohana work. I cannot have session_start() at the start of the script as it conflicts with the Kohana session that's already running. If I dump out the $_SESSION or Session::instance() contents the variable that should be added by the PHP Upload Progress functionality isn't there.

So how do I get the session variable to work with Kohana?

UPDATE

I have since created a clean install of Kohana to help narrow down on this issue. I have found that by not instantiating the Session class in Kohana that I can use the code above and it works fine.

However when the Session class is instantiated which it needs to be for my web application it stops working and the $_SESSION variable containing upload progress is no longer created. This leads me to believe that the issue lies somewhere within how Kohana manages session information. I tried turning off the encryption with config settings but that didn't make a difference.

I'm using native session.

Cowbird answered 21/1, 2013 at 11:14 Comment(2)
Why not just use the progress information available in JavaScript? This jQuery form plugin has some convenient callbacks for this: malsup.com/jquery/form/progress.htmlPresumable
The JavaScript alternative is reliant on the browser. I would like to have the work done server side.Cowbird
P
2

Session cookie name has to be exactly the same as the one set in php config (session.name), e.g.:

return array(
    'native' => array(
        'encrypted' => FALSE,
        'name'      => ini_get('session.name'),
    ),
);

If you don't want to use PHP's default session cookie name you will not get around this by setting the value during runtime, i.e. this won't work:

ini_set('session.name', 'my_kohana_session_name');

You will get around this by setting the value in your .htaccess file:

php_flag session.name "my_kohana_session_name"

This way you can keep the php.ini untouched but you can keep your custom cookie name for your Kohana application.

My tests proved that session encryption does not affect the upload progress information when using native session driver. That surely because the encryption is not used when using native driver regaldess the setting. ;)

PS. One thing I would also suggest - make sure that the ajax request is not cached. Had quite a few cases when it was cached and not showing fresh responses.

Preclude answered 1/2, 2013 at 15:27 Comment(6)
I have accepted this answer as it explains the core reasons which contribute to my issue and how to resolve them, whereas my answer was a work around.Cowbird
Hi Michal, I'm having this same issue, but I'm confused with your answer here. You say that the session cookie name has to be the same as what's set in the php config, but I'm not sure how this would give you the upload progress variables in the Kohana session variable. I don't see the session cookie name used anywhere in diggersworld's code. Would you be able to explain this a little more? You give your return array() code as an example, but where is that code coming from? I'm very confused with this answer. Could you please help me understand it? Thank youEffete
Ok, I've figured this out. The array() code Michal gives is from a session configuration file that doesn't exist unless you create it. You can see an example here: kohanaframework.org/3.0/guide/kohana/… however don't use the example the Kohana docs give as-is. As far as I can tell, you can only have 1 of the 3 (native, cookie, or database) not all 3 in your configuration or it will give an ORM error. To get upload progress, only use 'native' like in Michal's example.Effete
@Cowbird Did you get this accepted answer working? Any form I have that uses a hidden input with ini_get("session.upload_progress.name") wipes the current session data when it's submitted. This is really frustrating.Effete
@Gavin: Yes it works, I had to make sure that I was using the native PHP session when retrieving the session upload values.Cowbird
Thanks @diggersworld. I had to switch to using the database for the default Kohana sessions. I could not stop it from conflicting until I did that.Effete
C
1

I have found a solution.

What I have done is isolated the code that reads the PHP generated $_SESSION variable into its own Controller. In my case I have an AJAX controller for generic AJAX checks like validating emails, web URLs etc. The controller extends from the default Controller so that it does not inherit any session information from my custom controller (which is what my other controllers extend from).

So my new standalone Controller looks like this:

<?php defined('SYSPATH') or die('No direct script access.');

class Controller_Ajax extends Controller {

    public function action_upload_progress()
    {
            // get upload progress key
            $key = (!empty($_POST['key'])) ? $_POST['key'] : FALSE; 

            // start session to get PHP 5.4 generated $_SESSION variables
            session_start();

            // does key exist
            $key = ini_get("session.upload_progress.prefix") . $key;
            if ( !isset( $_SESSION[$key] ) ) {
                exit( "uploading..." );
            }

            // workout percentage
            $upload_progress = $_SESSION[$key];
            $progress = round( ($upload_progress['bytes_processed'] / $upload_progress['content_length']) * 100, 2 );
            exit( "Upload progress: $progress%" );
    }
}

I use the same code as before for the actual form and make a minor tweak to the JavaScript, requesting this controller/action to retrieve the upload progress data. Problem solved!

Cowbird answered 23/1, 2013 at 11:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.