ZendFramework2学习笔记 文件上传、文件上传进度

    修改php.ini以适应文件的要求:

//php.ini

file_uploads = On
post_max_size = 600M
upload_max_filesize = 600M
session.upload_progress.enabled = On
session.upload_progress.freq =  "1%"
session.upload_progress.min_freq = "1"

    以上我们限制了文件大小限制在不超过600MB。

    关于文件上传进度的获取方式,zf2提供了三个类:

Zend\Progressbar\Upload\ApcProgress
Zend\ProgressBar\Upload\SessionProgress
Zend\Progressbar\Upload\UploadProgress
    其中SessionProcess要求php5.4以上,本文以SessionProcess为例,其他2个使用方法一样。

    首先创建文件上传的From:

//Test/Form/TestForm.php

<?php

namespace Test\Form;

use Zend\Form\Form;
use Zend\InputFilter\InputFilter;
use Zend\InputFilter\InputFilterAwareInterface;
use Zend\InputFilter\InputFilterInterface;
use Zend\InputFilter\InputFilterProviderInterface;

use Zend\Validator\File\Extension;  
use Zend\Validator\File\Size;
use Zend\Validator\File\ImageSize;
use Zend\Validator\File\MimeType;
use Zend\Filter\File\RenameUpload;

class TestForm extends Form  implements InputFilterProviderInterface{
    
    protected $inputFilter; 
    
    public function __construct($name = null) {

        parent::__construct($name?$name:'test');

        //添加一个文本框
        $this->add(array(
            'name' => 'userName',
            'type' => 'Text',
            'options' => array(
                'label' => 'name:',                
            ),
            'attributes' => array(
                'size' => 60,
                'maxlength' => 100,
            ),
        ));
        
        //添加文件上传input
        $this->add(array(
            'name' => 'u',
            'type' => 'File',
            'options' => array(
                'label' => 'file:',                
            ),
            'attributes' => array(
                'id' => 'u_e',
            ),
        ));
        
        //提交按钮
        $this->add(array(
            'name' => 'send',
            'type' => 'Submit',
            'attributes' => array(
                'value' => 'ok',
            ),
        )); 
    }
    
    
   public function getInputFilterSpecification() {
       
        //文件上传后保存到临时目录的filter
        $renameUpload = new RenameUpload(array(
                                    "target"    => __DIR__."/../../../../../uploads",
                                    "randomize" => true,
                                    "use_upload_name" => true,
                                ));
        //验证文件扩展名
        $extention = new Extension('png,jpeg,jpg,bmp,gif,mp4');
        //验证文件大小
        $size = new Size(array('min'=>'1kB', 'max'=>'600MB'));
        //验证文件MIME类型
        $mime = new MimeType(array('image/png','image/jpeg','image/jpg','image/bmp','image/gif','video/mp4','enableHeaderCheck' => true));
        
        return array(
            'userName' => array(
                'required' => true,
                'filters'  => array(
                    array('name' => 'StringTrim'),
                    array('name' => 'StringToLower'),
                ),
                'validators' => array(
                    array('name' => 'NotEmpty'),
                    array('name' => 'Alnum'),
                    array(
                        'name'    => 'StringLength',
                        'options' => array(
                            'encoding' => 'UTF-8',
                            'min'      => 3,
                            'max'      => 256,
                        ),
                    ),
                    array(
                        'name'    => 'Db\NoRecordExists',
                        'options' => array(
                            'table' => 'user',
                            'field' => 'name',
                            'adapter' => $this->adapter,
                        ),
                    ),
                ),
            ),
            'u' => array(
                'required' => true,        
                'filters'  => array(
                    $renameUpload,
                ),
                'validators' => array(
                    $extention,
                    $size,
                    //$imgSize,
                    $mime,
                ),
            ), 
        );
    }
}

    然后创建view:

//Test/view/test/test/testform.phtml

<?php

$this->tform->setAttribute('action', $this->url('test', array('action' => 'testform')));
$this->tform->setAttribute('method', 'POST');
$this->tform->prepare();

echo "<div class='tf'>";
echo '<div>'.$this->form()->openTag($this->tform).'</div>';


//获取文件上传进度必须要使用该view helper,formFileSessionProgress会创建一个id为progress_key的hidden的input记录文件上传进度获取需要的id
//SessionProgress对应formFileSessionProgress,ApcProgress对应formFileApcProgress,UploadProgress对应formFileUploadProgress
echo $this->formFileSessionProgress();

//文本框
echo '<div>'.$this->formRow($this->tform->get('userName')).'</div>';

//文件input
//存在这样的情况:用户第一次提交后,文件上传了并检验通过了,但是文本框检验不过,此时,不需要用户重新再上传一次文件,所以,在此情况下将文件input隐藏起来
echo '<div '.($this->tempFile?'style="display:none"':'').'>'.$this->formRow($this->tform->get('u')).'</div>';
if ($this->tempFile){
    echo '<div>'.$this->tempFile['name'].'</div>';
}else{
    //上传进度显示
    echo '<div><span style="display:block; float:left;">process:</span><span id="proc" style="display:block; margin-left:60px; width:60px; height: 30px; background-color: 

#dddddd;"></span></div>';
}

echo '<div>'.$this->formRow($this->tform->get('send')).'</div>';

echo '<div>'.$this->form()->closeTag().'</div>';
echo "</div>";

echo "<hr />";

?>

<!-- 以下脚本用于定时获取并显示上传进度 -->
<script>
    
var progressInterval;

function getProgress() {
    var ul = '/test/uploadprogress?id='+$("#progress_key").val();//上传进度通过控制器test/uploadprogress获取
    $.ajax({
        type : "GET",
        url : ul,
        dataType : "json",
        success : function(data, textStatus) {
                        if (!data.done) {
                            var value = Math.floor((data.current / data.total) * 100);
                            showProgress(value);
                        } else {
                            showProgress(100);
                            clearInterval(progressInterval);
                        }
                    },
        error : function(r, t, r){
                        
                    }
    });
}

function startProgress() {
    showProgress(0);
    progressInterval = setInterval(getProgress, 400);
}

function showProgress(amount) {
    $('#proc').html(amount+"%");
}
$(document).ready(
    function(){
        $('#test').submit(startProgress);
    }
);
</script>

    最后是控制器:

//Test/Controller/TestController.php

<?php

namespace Test\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use Zend\Session\Storage\SessionArrayStorage;
use Zend\ProgressBar\Upload\SessionProgress;
use Zend\View\Model\JsonModel;

use Test\Form\TestForm;

class TestController extends AbstractActionController {

    public function testformAction() {
        $form = new TestForm();
        $inputFilter = $form->getInputFilter();

        $sessionKey = 'uploadedTempFile';
        $sessionStorage = new SessionArrayStorage();//session存储对象,文件上传成功并检验成功后,将信息保存进session,避免用户再次重新上传文件
        $tempFile = null;
        
        if ($sessionStorage->offsetExists($sessionKey)){
            $tempFile = $sessionStorage->offsetGet($sessionKey);
        }
        
        if ($this->getRequest()->isPost()){//用户提交了表单,处理表单数据           
        
            $postData = array_merge_recursive(//文件信息合并到postdata数组
                $this->getRequest()->getPost()->toArray(),
                $this->getRequest()->getFiles()->toArray()
            );
            
            if (isset($tempFile)) {//本次提交不是首次提交,并且session中有用户上传的文件的缓存数据
                if (!empty($postData['u']['name'])){//用户重新上传了文件,则原来缓存的文件要清除
                    $sessionStorage->offsetUnset($sessionKey);
                    $tempFile = null;
                }else{//用户没有上传新文件,所以,检验表单时不检验file元素
                    $inputFilter->get('u')->setRequired(false);
                }
            }
            
            $form->setData($postData);
            if ($form->isValid()) {//表单检验成功
                $data = $form->getData();
                
                if (empty($data['u']) && $tempFile){//用户没有上传新文件,所以,使用session中缓存的文件
                    $data['u'] = $tempFile;
                    
                    $fileName = $data['u']['name'];
                    $fileMIMEType = $data['u']['type'];
                    $tmpFilePathName = $data['u']['tmp_name'];
                    $fileSize = $data['u']['size'];                
                }                
                
                //保存表单
                //.......
                
                //$this->redirect()->toRoute(
                
            } else {//表单元素检验失败
                $data = $form->getData();
                $fileErrors = $form->get('u')->getMessages();
                if (empty($fileErrors) && isset($data['u']['error'])
                    && $data['u']['error'] === UPLOAD_ERR_OK
                ) {
                    $tempFile = $data['u'];
                    $sessionStorage->offsetSet($sessionKey, $tempFile);   
                }
            }
        } else {//不是用户提交的表单,清空session中的缓存数据
            if ($sessionStorage->offsetExists($sessionKey)){
                $sessionStorage->offsetUnset($sessionKey);
            }
            $tempFile = null;
        }

        return array(
            'tform'     => $form,
            'tempFile' => $tempFile,
        );        
     }

    //获取上传进度的action
    public function uploadprogressAction()
    {
        $id = $this->params()->fromQuery('id', null);
        $progress = new SessionProgress();
        return new JsonModel($progress->getProgress($id));
    }
}
    

    由于上传过程使用了session,因此,需要添加session的启动代码,以保证刷新页面的时候不会出现session错误。

    session的参数配置:

// /config/autoload/local.php

return array(
    'session' => array(
        'config' => array(
            'class' => 'Zend\Session\Config\SessionConfig',
            'options' => array(
                'name' => 'zf2ttttt',
            ),
        ),
        'storage' => 'Zend\Session\Storage\SessionArrayStorage',
        'validators' => array(
            'Zend\Session\Validator\RemoteAddr',
            'Zend\Session\Validator\HttpUserAgent',
        ),
    ),
);

    Application启动后调用session_start:

// /module/Application/Module.php

namespace Application;

use Zend\Mvc\ModuleRouteListener;
use Zend\Mvc\MvcEvent;

use Zend\Session\SessionManager;
use Zend\Session\Container;

class Module
{
    public function onBootstrap(MvcEvent $e)
    {
        $eventManager        = $e->getApplication()->getEventManager();
        $moduleRouteListener = new ModuleRouteListener();
        $moduleRouteListener->attach($eventManager);
        
	//为表单验证对象设置默认的语言翻译器,以便验证码验证不通过时用默认语言提示用户       
       \Zend\Validator\AbstractValidator::setDefaultTranslator($e->getApplication()->getServiceManager()->get('translator'));
       //启动session
       $this->bootstrapSession($e);
    }

    public function bootstrapSession($e){
        $session = $e->getApplication()->getServiceManager()->get('Zend\Session\SessionManager');
        $session->start();        
    }

    //SessionManager工厂
    public function getServiceConfig() {
        return array(
            'factories' => array(
                'Zend\Session\SessionManager' => function ($sm) {
                    $config = $sm->get('config');
                    if (isset($config['session'])){
                        $session = $config['session'];
                        
                        $sessionConfig = null;
                        if (isset($session['config'])){
                            $class = isset($session['config']['class']) ? $session['config']['class'] : 'Zend\Session\Config\SessionConfig';
                            $options = isset($session['config']['options']) ? $session['config']['options'] : array();
                            $sessionConfig = new $class;
                            $sessionConfig->setOptions($options);
                        }
                        
                        $sessionStorage = null;
                        if (isset($session['storage'])){
                            $class = $session['storage'];
                            $sessionStorage = new $class;
                        }
                        
                        $sessionSaveHandler = null;
                        if (isset($session['save_handler'])){
                            $sessionSaveHandler = $sm->get($session['save_handler']);
                        }
                        
                        $sessionManager = new SessionManager($sessionConfig, $sessionStorage, $sessionSaveHandler);
                    } else {
                        $sessionManager = new SessionManager();
                    }
                    Container::setDefaultManager($sessionManager);
                    return $sessionManager;
                },
            ),
        );
    }
}

    另外,貌似zf2.3版本中文件上传validator的消息字符串的中文翻译在语言文件/vendor/ZF2/resources/languages/zh/Zend_Validate.php中不存在,需要自己添加下:

/vendor/ZF2/resources/languages/zh/Zend_Validate.php

return array(

    ......

    "File has an incorrect extension" => "文件扩展名不正确",
    "Maximum allowed size for file is '%max%' but '%size%' detected" => "值“%size%”超过最小值“%max%”",
    "Minimum expected size for file is '%min%' but '%size%' detected" => "值“%size%”超过最小值“%min%”",
    "File has an incorrect mimetype of '%type%'" => "文件mime类型不正确“%type%”",
    "The mimetype could not be detected from the file" => "文件中检测不到mime类型",
    "File is not readable or does not exist" => "文件不可读或者不存在",
    'File was not uploaded' => "没有上传文件"

);


   












  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值