首页 文章

上传期间的文件上传进度[关闭]

提问于
浏览
5

我在文件上传进度方面遇到了一些问题 . 我在xampp,windows 7上使用zend framework 2.2 .

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',
        ),
    ), 
);

我的注册页面在“/ zendtest / application / signup /”打开 .

当我点击提交按钮时,没有任何反应 .

Update :

如果我使用以下代码,请告诉我如何使用“Zend \ ProgressBar \ Upload \ UploadProgress”将文件上传进度条添加到我的表单 . 我应该如何更改我的控制器或模型或视图?

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>
        
<!--image preview--> <img id="upimg" name="upimg" src="" style="">
</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;
    }

}

它在表单有效时有效,但如果表单有错误(假设'用户名'字段为空)则它不显示错误消息(应该来自模型'Signup.php')并且进度条仍然显示文件上传进度甚至实际上没有上传的文件 .

如果我从'index.phtml'剪切以下行并将它们添加到'layout.phtml'的'head'然后表单验证工作但文件上传进度条不起作用(表单提交像普通的PHP表单) . 但是,当选择图像文件时,jquery会显示图像 .

//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

3 回答

  • 1

    更新状态的JavaScript在哪里?除非有你没有发布的东西(或者我错过了),否则你实际上错过了重要的一块 .

    您在参考的教程中提到了这一点:

    有一些不同的方法可以获取进度信息到浏览器(长轮询和短轮询) . 在这里,我们将使用短轮询,因为它更简单,对服务器资源的负担更少,但请记住,它不像长轮询那样响应 . 当我们的表单通过AJAX提交时,浏览器将不断轮询服务器以获取上载进度 .

    你有三个选择:

    1 - 继续刷新要求服务器进度的页面 - 基本上它返回一个页面说“上传10%完成....”等等,直到整个表单被提交,然后你处理和处理 .

    2 - 更容易在iFrame中进行轮询/更新(因此请不断刷新iFrame)

    3 - 使用javascript调用(通过JSON上传 - 您的视图返回JSON反对HTML并且您不需要 Headers )然后通过JavaScript更新屏幕 .

    所以你需要的是将其中一种方法挂钩到你的表单中 .

    Caveat:

    话虽如此,您需要以正确的方式配置服务器 . 上传可以是基于会话,基于APC或上传进度模块 . 您可能会发现这些服务器上没有安装这些服务器以便最终部署 .


    Better overall solution (possibly).

    因此,无论如何,当你使用JS时,你也可以在现代浏览器中使用JS中的一个功能(IE9,Chrome,FF等,所以它可以保存在主要版本中) . 使用IE8它只是工作(没有进度指示器) . 我发现它是迄今为止更可靠的替代方案(如果您接受IE8用户获取上传功能而没有进度条) .

    您可以在XHR对象的upload属性中添加事件侦听器 . 随着上传进度不断调用EventLister .

    你可以将一个挂钩到每个文件(我在下面做的,你需要排队然后一次处理一个或两个,然后在完成时提交主表单)或者你可以挂钩到整个表单(一个进度条,一个处理程序服务器端=更简单,但不是很好的用户体验) .

    为了提供帮助,这里是最近项目的一个片段,但网上有一些教程可以提供帮助 . 它与您拥有的不同,但并不多,部署和控制也更简单 . 它使用jQuery,但如果使用原始JS,理论(向xhr添加事件监听器)完全相同 .

    我知道这是从你当前的方法转变 - 但我也使用你当前的方法,并发现这更好 .

    jQuery代码段/示例

    $.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');
    }
    }
    
  • 0

    假设您安装了APC,您可以执行此tutorial显示的内容或使用Session upload progress选项我相信使用APC或会话上传进度是仅使用PHP获取真正上传仪表的唯一方法

  • 0

    另一个替代方案(实际上,我最喜欢的)是使用nginx上传模块nginx upload progress module .

    因此,nginx负责上传|下载文件,PHP只负责插入/处理一些数据,JS只是轮询nginx处理程序来读取进度状态 .

相关问题