Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

file upload progress during upload [closed]

I'm having some problem with file upload progress. I'm using zend framework 2.2 on xampp, windows 7.

Form (SignupForm) :

namespace Application\Form;

 use Zend\Form\Form;
 use Zend\Form\Element;

 class SignupForm extends Form
 {  
     public function __construct($name = null)
     {
        $this->add(array(
            'name' => 'username',
            'type' => 'Text',
            'options' => array(
                'label' => 'Username',
                'label_attributes' => array(
                    'class' => 'formlabel',
                ),
            ),
        ));
                      $this->add(array(
            'type' => 'Zend\Form\Element\File',
            'name' => 'fileupload',
            'attributes' => array(
                'id' => 'fileupload',
            ),
            'options' => array(
                'label' => 'Photo',
                'label_attributes' => array(
                    'class' => 'formlabel',
                ),
            ),
        ));
     }
 }

Controller (IndexController) :

<?php

namespace Application\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Application\Model\Signup;
use Application\Form\SignupForm;

class IndexController extends AbstractActionController {

    protected $userTable;
    protected $userTablee;

    public function getSignTable($table, $object) {
        if (!$this->$object) {
            $sm = $this->getServiceLocator();
            $this->$object = $sm->get($table);
        }
        return $this->$object;
    }

    public function indexAction() {
        return new ViewModel();
    }

    public function signupAction() {
        $form = new SignupForm();
        $form->get('submi')->setValue('Submit');

        $request = $this->getRequest();
        if ($request->isPost()) {
            $album = new Signup();
            $t = $this->getSignTable('dbAdapter\dbtable=user', 'userTablee');
            $form->setInputFilter($album->getInputFilter($t));
            $data = array_merge_recursive(
                    $this->getRequest()->getPost()->toArray(),
                    $this->getRequest()->getFiles()->toArray()
            );
            $form->setData($data);

            if ($form->isValid()) {
                $album->exchangeArray($form->getData());
                $this->getSignTable('Album\Model\AlbumTable\dbtable=user', 'userTable')->saveUser($album);
//--------------------------------------------------file upload progress--------------------  
// Form is valid, save the form!
            if (!empty($post['isAjax'])) {
                return new JsonModel(array(
                    'status'   => true,
                    'redirect' => $this->url()->fromRoute('upload-form
/success'),
                    'formData' => $album,
                ));
            } else {
                // Fallback for non-JS clients
                return $this->redirect()->toRoute('upload-form
/success');
            }
        } else {
            if (!empty($post['isAjax'])) {
                 // Send back failure information via JSON
                 return new JsonModel(array(
                     'status'     => false,
                     'formErrors' => $form->getMessages(),
                     'formData'   => $form->getData(),
                 ));
            }                
$filter = new \Zend\Filter\File\RenameUpload("./public/photo/" . $album->username);
                $filter->setUseUploadExtension(true);
                $filter->setRandomize(true);
                $filter->filter($data['fileupload']); 
            } 
        }
        return array('form' => $form);
    }

public function uploadProgressAction()
{
    $id = $this->params()->fromQuery('id', null);
    $progress = new \Zend\ProgressBar\Upload\SessionProgress();
    return new \Zend\View\Model\JsonModel($progress->getProgress($id));
}    

}

Model (Signup) :

namespace Application\Model;
use Zend\Http\PhpEnvironment\Request;

use Zend\InputFilter\InputFilter;
use Zend\InputFilter\InputFilterAwareInterface;
use Zend\InputFilter\InputFilterInterface;
use Zend\Validator;

class Signup implements InputFilterAwareInterface {
    public $username;
    public $fileupload;
    protected $inputFilter;
    public function exchangeArray($data) {
$this->username = (!empty($data['username'])) ? $data['username'] : null;        
$this->fileupload = (!empty($data['fileupload'])) ? $data['fileupload'] : null;
    }

    public function getArrayCopy() {
        return get_object_vars($this);
    }

    public function setInputFilter(InputFilterInterface $inputFilter) {
        throw new \Exception("Not used");
    }

    public function getInputFilter($adapter = null) {
        if (!$this->inputFilter) {
            $inputFilter = new InputFilter();
$inputFilter->add(array(
                'name' => 'fileupload',
                'required' => true,
            ));
            $this->inputFilter = $inputFilter;
        }
        return $this->inputFilter;
    }
}

View (index) :

<?php
$this->plugin('basePath')->setBasePath('/zendtest/public');
$title = 'Signup';
$this->headTitle($title);
?>
<h1><?php echo $this->escapeHtml($title); ?></h1>
<div class="signupform">
    <?php
    $form->prepare();
    $form->setAttribute('action', $this->url('signup', array('action' => 'signup')));
    $form->setAttribute('method', 'post');
    $form->setAttribute('class', 'signform');
    $form->setAttribute('enctype', 'multipart/form-data');
    echo $this->form()->openTag($form);
    $errmsg = $form->getMessages();
    ?>
    <!--  ----------------------------------------username  -->
    <div class="signupformrow">
        <?php
        echo $this->formLabel($form->get('username'));
        echo $this->formInput($form->get('username'));
        if ($errmsg) {
            if (isset($errmsg['username'])) {
                foreach ($errmsg['username'] as $key => $value) {
                    ?>
                    <span class="formerror">
                        <?php
                        if ($key == "isEmpty") {
                            echo"Username required";
                        } else {
                            echo $value;
                        }
                        ?>
                    </span>
                    <?php
                }
            } else {
                ?>
                <span class="formins"><img src="<?php echo $this->basePath('/images/tick.png'); ?>" /></span>
                <?php
            }
        } else {
            ?>
            <span class="formins">(Username must be 5-69 characters and alphanumeric only)</span>
            <?php
        }
        ?>
    </div>
    <!--  ----------------------------------------file   -->
    <?php echo $this->formFileSessionProgress(); ?>
    <div class="signupformrow">
        <?php
        echo $this->formLabel($form->get('fileupload'));
        echo $this->formFile($form->get('fileupload')); 
        if ($errmsg) {
            if (isset($errmsg['fileupload'])) {
                print_r($errmsg['fileupload']);
                foreach ($errmsg['fileupload'] as $key => $value) {
                    ?>
                    <span class="formerror">
                        <?php
                        if ($key == "isEmpty") {
                            echo'Photo required';
                        } else {
                            echo $value;
                        }
                        ?>
                    </span>
                    <?php
                }
            }
        }
        ?>
    </div>
    <!--  ----------------------------------------submit   -->     
    <div class="signupformrow">
        <label class="formlabel"></label>
        <button>Submit</button>
    </div>
    <?php
    echo $this->form()->closeTag();
    ?>
<!-- ---------------------------------------file upload progressbar-------------------------------------- -->
<div id="progress" class="help-block">
    <div class="progress progress-info progress-striped">
        <div class="bar"></div>
    </div>
    <p></p>
</div>

<script src="<?php echo $this->basePath('/js/jquery.min.js'); ?>"></script>
<script src="<?php echo $this->basePath('/js/jquery.form.js'); ?>"></script>
<script>
var progressInterval;

function getProgress() {
    // Poll our controller action with the progress id
    var url = '<?php echo $this->url('signup') ?>/upload-progress?id=' + $('#progress_key').val();
    $.getJSON(url, function(data) {
        if (data.status && !data.status.done) {
            var value = Math.floor((data.status.current / data.status.total) * 100);
            showProgress(value, 'Uploading...');
        } else {
            showProgress(100, 'Complete!');
            clearInterval(progressInterval);
        }
    });
}

function startProgress() {
    showProgress(0, 'Starting upload...');
    progressInterval = setInterval(getProgress, 900);
}

function showProgress(amount, message) {
    $('#progress').show();
    $('#progress .bar').width(amount + '%');
    $('#progress > p').html(message);
    if (amount < 100) {
        $('#progress .progress')
            .addClass('progress-info active')
            .removeClass('progress-success');
    } else {
        $('#progress .progress')
            .removeClass('progress-info active')
            .addClass('progress-success');
    }
}

$(function() {
    // Register a 'submit' event listener on the form to perform the AJAX POST
    $('#signup').on('submit', function(e) {
        e.preventDefault();

        if ($('#fileupload').val() == '') {
            // No files selected, abort
            return;
        }

        // Perform the submit
        //$.fn.ajaxSubmit.debug = true;
        $(this).ajaxSubmit({
            beforeSubmit: function(arr, $form, options) {
                // Notify backend that submit is via ajax
                arr.push({ name: "isAjax", value: "1" });
            },
            success: function (response, statusText, xhr, $form) {
                clearInterval(progressInterval);
                showProgress(100, 'Complete!');

                // TODO: You'll need to do some custom logic here to handle a successful
                // form post, and when the form is invalid with validation errors.
                if (response.status) {
                    // TODO: Do something with a successful form post, like redirect
                    // window.location.replace(response.redirect);
                } else {
                    // Clear the file input, otherwise the same file gets re-uploaded
                    // http://stackoverflow.com/a/1043969
                    var fileInput = $('#fileupload');
                    fileInput.replaceWith( fileInput.val('').clone( true ) );

                    // TODO: Do something with these errors
                    // showErrors(response.formErrors);
                }
            },
            error: function(a, b, c) {
                // NOTE: This callback is *not* called when the form is invalid.
                // It is called when the browser is unable to initiate or complete the ajax submit.
                // You will need to handle validation errors in the 'success' callback.
                console.log(a, b, c);
            }
        });
        // Start the progress polling
        startProgress();
    });
});
</script>
</div>

module.config :

<?php

return array(
    'router' => array(
        'routes' => array(
            'home' => array(
                'type' => 'Zend\Mvc\Router\Http\Literal',
                'options' => array(
                    'route'    => '/zendtest/',
                    'defaults' => array(
                        'controller' => 'Application\Controller\Index',
                        'action'     => 'index',
                    ),
                ),
            ),
            'application' => array(
                'type'    => 'Literal',
                'options' => array(
                    'route'    => '/zendtest/application',
                    'defaults' => array(
                        '__NAMESPACE__' => 'Application\Controller',
                        'controller'    => 'Index',
                        'action'        => 'index',
                    ),
                ),
                'may_terminate' => true,
                'child_routes' => array(
                    'default' => array(
                        'type'    => 'Segment',
                        'options' => array(
                            'route'    => '/[:controller[/:action]]',
                            'constraints' => array(
                                'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
                                'action'     => '[a-zA-Z][a-zA-Z0-9_-]*',
                            ),
                            'defaults' => array(
                            ),
                        ),
                    ),
                ),
            ),
//===================================signup================================================================
             'signup' => array(
                 'type'    => 'segment',
                 'options' => array(
                     'route'    => '/zendtest/application/signup[/][:action][/:id]',
                     'constraints' => array(
                         'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
                         'id'     => '[0-9]+',
                     ),
                     'defaults' => array(
                         'controller' => 'Application\Controller\Index',
                         'action'     => 'signup',
                     ),
                 ),
             ), 
        ),  // routes end
    ), // router ends
    'service_manager' => array(
        'factories' => array(
            'translator' => 'Zend\I18n\Translator\TranslatorServiceFactory',
        ),
    ), 
    'translator' => array(
        'locale' => 'en_US',
        'translation_file_patterns' => array(
            array(
                'type'     => 'gettext',
                'base_dir' => __DIR__ . '/../language',
                'pattern'  => '%s.mo',
            ),
        ),
    ), 
    'controllers' => array(
        'invokables' => array(
            'Application\Controller\Index' => 'Application\Controller\IndexController'
        ),
    ), 
    'view_manager' => array(
        'display_not_found_reason' => true,
        'display_exceptions'       => true,
        'doctype'                  => 'HTML5',
        'not_found_template'       => 'error/404',
        'exception_template'       => 'error/index',
        'template_map' => array(
            'layout/layout'           => __DIR__ . '/../view/layout/layout.phtml',
            'application/index/index' => __DIR__ . '/../view/application/index/index.phtml',
            'application/index/signup' => __DIR__ . '/../view/application/signup/index.phtml',
            'error/404'               => __DIR__ . '/../view/error/404.phtml',
            'error/index'             => __DIR__ . '/../view/error/index.phtml',
        ),
        'template_path_stack' => array(
            __DIR__ . '/../view',
        ),
    ), 
);

my signup page open at "/zendtest/application/signup/".

When I click on the submit button then nothing happens.

Update :

If I use the following code then please tell me how can I add file upload progressbar to my form by using "Zend\ProgressBar\Upload\UploadProgress". how should I change my controller or model or view ?

controller :

if ($form->isValid()) {
                $album->exchangeArray($form->getData());
                $album->act_code = Rand::getString(5);
                $album->dkey = Rand::getString(5);
                $this->getSignTable('Album\Model\AlbumTable\dbtable=user', 'userTable')->saveUser($album);
//==================================================file========================================
                $filter = new \Zend\Filter\File\RenameUpload("./public/photo/" . $album->username);
                $filter->setUseUploadExtension(true);
                $filter->setRandomize(true);
                $filter->filter($data['fileupload']);
            }
        }

model for filter and validation (Signup.php) :

    $inputFilter->add(array(
        'name' => 'fileupload',
        'required' => true,
        'validators' => array(
            $fileValidator->attach(new \Zend\Validator\File\UploadFile(array(
                        'messages' => array(
                            \Zend\Validator\File\UploadFile::NO_FILE => 'Photo required',
                        ),
                            )
                    ), true)
        ),
    ));

view :

  <?php echo $this->formFileSessionProgress(); ?>
    <div class="signupformrow">
        <?php
        echo $this->formLabel($form->get('fileupload'));
        echo $this->formFile($form->get('fileupload'));
        if ($errmsg) {
            if (isset($errmsg['fileupload'])) {
                print_r($errmsg['fileupload']);
                foreach ($errmsg['fileupload'] as $key => $value) {
                    ?>
                    <span class="formerror">
                        <?php
                        if ($key == "isEmpty") {
                            echo'Photo required';
                        } else {
                            echo $value;
                        }
                        ?>
                    </span>
                    <?php
                }
            }
        }
        ?>
    </div>

Update 2:

View :

<div class="signupform">
    <?php
    $form->prepare();
    $form->setAttribute('action', $this->url('signup', array('action' => 'signup')));
    $form->setAttribute('method', 'post');
    $form->setAttribute('class', 'signform');
    $form->setAttribute('id', 'signup');
    $form->setAttribute('enctype', 'multipart/form-data');
    echo $this->form()->openTag($form);
    $errmsg = $form->getMessages();
    ?>
    <!--  ----------------------------------------username  -->
    <div class="signupformrow">
        <?php
        echo $this->formLabel($form->get('username'));
        echo $this->formInput($form->get('username'));
        if ($errmsg) {
            if (isset($errmsg['username'])) {
                foreach ($errmsg['username'] as $key => $value) {
                    ?>
                    <span class="formerror">
                        <?php
                        if ($key == "isEmpty") {
                            echo"Username required";
                        } else {
                            echo $value;
                        }
                        ?>
                    </span>
                    <?php
                }
            } else {
                ?>
                <span class="formins"><img src="<?php echo $this->basePath('/images/tick.png'); ?>" /></span>
                <?php
            }
        } else {
            ?>
            <span class="formins">(Username must be 5-69 characters and alphanumeric only)</span>
            <?php
        }
        ?>
    </div>
    <!--  ----------------------------------------file   -->
    <div class="signupformrow">
        <?php
        echo $this->formLabel($form->get('fileupload'));
        ?>
  <div class="filediv">
        <?php
        echo $this->formFile($form->get('fileupload'));
         ?>
        <a onclick="select_file()" class="pure-button upbutton">Choose an Image</a>
        <br />
            <!--image preview-->
            <img id="upimg" name="upimg" src="" style="">
<br />

                </div>
        <?php
        if ($errmsg) {
            if (isset($errmsg['fileupload'])) {
                foreach ($errmsg['fileupload'] as $key => $value) {
                    ?>
                    <span class="formerror">
                        <?php
                        if ($key == "isEmpty") {
                            echo'Photo required';
                        } else {
                            echo $value;
                        }
                        ?>
                    </span>
                    <?php
                }
            }
        }
        ?>
    </div>
    <!--  ----------------------------------------submit   -->     
    <div class="signupformrow">
        <label class="formlabel"></label>
        <?php
        echo $this->formSubmit($form->get('submi'));
        ?>
    </div>
    <?php
    echo $this->form()->closeTag();
    ?>
</div>
<!--progress bar-->
        <div class="progress">
            <div class="barrr"></div>
            <div class="percenttt">0%</div>
        </div>

<script src="<?php echo $this->basePath('/js/jquery.min.js'); ?>"></script>
<script src="<?php echo $this->basePath('/js/jquery.form.min.js'); ?>"></script> 
<script type="text/javascript">

$(document).ready(function() {
    /* variables */
    var preview = $('#upimg');
    var status = $('.status');
    var percent = $('.percenttt');
    var bar = $('.barrr');

    /* only for image preview */
    $("#fileupload").change(function(){
        preview.fadeOut();

        /* html FileRender Api */
        var oFReader = new FileReader();
        oFReader.readAsDataURL(document.getElementById("fileupload").files[0]);

        oFReader.onload = function (oFREvent) {
            preview.attr('src', oFREvent.target.result).fadeIn();
        };
    });

    /* submit form with ajax request */
    $('#signup').ajaxForm({

        /* set data type json */
        dataType:'json',

        /* reset before submitting */
        beforeSend: function() {
            status.fadeOut();
            bar.width('0%');
            percent.html('0%');
        },

        /* progress bar call back*/
        uploadProgress: function(event, position, total, percentComplete) {
            var pVel = percentComplete + '%';
            bar.width(pVel);
            percent.html(pVel);
        },

        /* complete call back */
        complete: function(data) {
            preview.fadeOut(800);
            status.html(data.responseJSON.status).fadeIn();
        }

    });
});    
        function select_file(){
            document.getElementById('fileupload').click();
            return false;
        }
</script>

Form validation model(Signup.php):

class Signup implements InputFilterAwareInterface {

    public $username;
    public $fileupload;
    protected $inputFilter;
    protected $usernameValidator;
    protected $fileValidator;
    protected $adapter;

    public function exchangeArray($data) {
        $this->username = (!empty($data['username'])) ? $data['username'] : null;
        $this->fileupload = (!empty($data['fileupload'])) ? $data['fileupload'] : null;
    }

    public function getArrayCopy() {
        return get_object_vars($this);
    }

    public function setInputFilter(InputFilterInterface $inputFilter) {
        throw new \Exception("Not used");
    }

    public function getInputFilter($adapter = null) {
        $this->adapter = $adapter;

        if (!$this->inputFilter) {
            $inputFilter = new InputFilter();
            $usernameValidator = new \Zend\Validator\ValidatorChain();
            $fileValidator = new \Zend\Validator\ValidatorChain();

            $inputFilter->add(array(
                'name' => 'username',
                'required' => true,
                'filters' => array(
                    array('name' => 'StripTags'),
                ),
                'validators' => array(
                            $usernameValidator->attach(
                                    new \Zend\Validator\NotEmpty(array()), true)
                            ->attach(new \Zend\Validator\Regex(array(
                                        'pattern' => '/^[a-z]+[a-z0-9_]+$/',
                                        'messages' => array(
                                            \Zend\Validator\Regex::INVALID => 'Username is not valid',
                                            \Zend\Validator\Regex::NOT_MATCH => 'Only small alphabet, digit and underscore are allowed. Username must start with an alphabet',
                                        ),
                                    )), true)
                )
            ));

            $inputFilter->add(array(
                'name' => 'fileupload',
                'required' => true,
                'validators' => array(
                    $fileValidator->attach(new \Zend\Validator\File\UploadFile(array(
                                'messages' => array(
                                    \Zend\Validator\File\UploadFile::NO_FILE => 'Photo required',
                                ),
                                    )
                            ), true)
                ),
            ));

            $this->inputFilter = $inputFilter;
        }
        return $this->inputFilter;
    }

}

it works when the form is valid, but if the form has error (suppose ‘username’ field is empty) then it doesn’t show error message (which should come from the model ‘Signup.php’) and the progressbar still shows file upload progress even the file actually not uploaded though.

And if I cut the following lines from the ‘index.phtml’ and add them to the ‘head’ of ‘layout.phtml’ then the form validation works but the file upload progressbar doesn’t works(the form submits like normal php form). But the image is shown by the jquery when the image file is selected.

//index.phtml

    <script src="<?php echo $this->basePath('/js/jquery.min.js'); ?>"></script>
    <script src="<?php echo $this->basePath('/js/jquery.form.min.js'); ?>"></script> 

    //layout.phtml

            <!-- Scripts -->
            <?php echo $this->headScript()->prependFile($this->basePath('/js/html5.js'), 'text/javascript', array('conditional' => 'lt IE 9',))
                                          ->prependFile($this->basePath('/js/bootstrap.min.js'))
                                          ->prependFile($this->basePath('/js/jquery.min.js'))
                    ->prependFile($this->basePath('/js/jquery.form.min.js')) ?>
        </head>

enter image description here

like image 508
user1844626 Avatar asked Nov 11 '22 16:11

user1844626


1 Answers

Where's the JavaScript that updates the status? Unless there's something you've not posted (or I've missed) then you're actually missing a vital chunk.

This is mentioned in the tutorial you reference:

There are a few different methods for getting progress information to the browser (long vs. short polling). Here we will use short polling since it is simpler and less taxing on server resources, though keep in mind it is not as responsive as long polling.

When our form is submitted via AJAX, the browser will continuously poll the server for upload progress.

You have three choices:

1 - keep refreshing the page that asks the server for progress - bascally it returns a page saying "uploading 10% done...." and so on until the entire form is submitted, then you process and handle.

2 - easier to do the polling / update in an iFrame (so keep refreshing the iFrame)

3 - use javascript call (get upload through JSON - your view returns JSON as oppsed to HTML and you don't need the headers) and then update the screen through JavaScript.

So what you need is to hook one of those methods in to your form.

Caveat:

Having said that, you need to have the server configured the right way. Upload can be session based, APC based or upload progress module. You may find these are not installed on the server to finally deploy too.


Better overall solution (possibly).

So, as you're using JS anyway, you may as well used a feature in JS in modern browsers (IE9+, Chrome, FF etc, so it's save to use in the main). With IE8 it just works (no progress indicator). I found it by far a more reliable alternative (if you accept IE8 users get upload functionality without progress bar).

You add an event listener in the upload property of the XHR object. The EventLister gets constantly called with progress on upload.

You could hook one to each file (that' what I did below, you need to queue then and handle one or two at a time and then submit the main form when done) or you can hook to the entire form (one progress bar, one handler server side = simpler, but not as nice user experience).

To help, here's a snippet from a recent project, but there are tutorials on the web that will help. It's a shift from what you have, but not much and it's a lot simpler to deploy and control. It uses jQuery, but the theory (add event listener to xhr) is exactly the same if you used raw JS.

I know it's a shift from your current method - but I also used your current method and find this much nicer instead.

jQuery snippet/example

$.ajax({
xhr: function() {
    var xhrobj = $.ajaxSettings.xhr();
    if (xhrobj.upload) {
        xhrobj.upload.addEventListener('progress', function(event) {
            var percent = 0;
            var position = event.loaded || event.position;
            var total = event.total;
            if (event.lengthComputable) {
                percent = Math.ceil(position / total * 100);
            }
            //Set progress
            $('#upload_' + vr_admin.currentlyUploadIndex + ' .imageProgress .imageProgressBar').css({width: percent * 2});
        }, false);
    }
    return xhrobj;
},
url: upload.php',
type: "POST",
contentType:false,
processData: false,
cache: false,
data: {data fields god here},
success: function(response){
    alert ('UPloaded');
}
}
like image 177
Robbie Avatar answered Nov 15 '22 07:11

Robbie