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>