Zend Framework - 文件上传

  • 简述

    文件上传是表单编程中的主要概念之一。Zend 框架提供了通过 zend-form 和 zend-inputzend-inputfilter组件上传文件所需的所有项目。
  • FileInput 类

    zend-inputfilter 组件提供 Zend\InputFilter\File输入类来处理 html 文件输入元素 – <输入类型 = 'file' />文件输入与其他输入筛选器类似,但有少数例外。它们如下所示 −
    • 由于 PHP 将上载的文件详细信息保存在 $_FILES 全局数组中,因此 FileInput 仅通过 $_FILES 收集上载的文件信息。
    • 需要在文件输入类处理数据之前完成验证。这是与其他输入过滤器相反的行为。
    • Zend\Validator\File\UploadFile 是要使用的默认验证程序。UploadFile验证文件输入详细信息。
    要在表单中添加文件上传类型,我们需要使用输入类型File。部分代码如下 −
    
    $form->add(array( 
       'name' => 'imagepath', 
       'type' => 'File', 
       'options' => array('label' => 'Picture',), 
    )); 
    
    文件上载中使用的另一个类是 Zend\Filter\File\RenameUpload。RenameUpload用于将上传的文件移动到所需的位置。使用文件筛选器的分部类如下所示 −
    
    $file = new FileInput('imagepath'); 
    $file->getValidatorChain()->attach(new UploadFile());
    $file->getFilterChain()->attach( 
       new RenameUpload([ 
          'target'    => './public/tmpuploads/file', 
          'randomize' => true, 
          'use_upload_extension' => true 
       ]));
    $inputFilter->add($file); 
    
    在这里,RenameUpload参数如下 -
    • target − 上载文件的目标路径。
    • randomize − 添加一个随机字符串以防止上传文件的重复。
    • use_upload_extension − 将文件扩展名附加到目标上载的文件。
  • 文件上传 – 工作示例

    让我们修改 tutorial 模块并包含图片上传功能。

    修改数据库表

    让我们通过执行以下 SQL 命令将imagepath列添加到书籍表中 −
    
    ALTER TABLE `book` ADD `imagepath` VARCHAR(255) NOT NULL AFTER 'imagepath';
    

    更新 BookForm.php

    添加文件输入元素以在书籍表单中上传图片 - myapp/module/Tutorial/src/Model/BookForm.php。
    在 BookForm 类的__construct方法中包含以下代码。
    
    $this->add(array( 
       'name' => 'imagepath', 
       'type' => 'File', 
       'options' => array ('label' => 'Picture',), 
    )); 
    

    更新 Book.php

    在书籍类中执行以下更改 – myapp/module/Tutorial/src/Model/Book.php。
    • 为图片添加新的属性imagepath
    
    public $imagepath; 
    
    • 更新getInputFilter方法,如下所示 −
      • 为文件输入元素添加FileInput筛选器。
      • 设置UploadFile验证以验证文件输入元素。
      • 配置RenameUpload以将上载的文件移动到正确的目标。
    部分代码清单如下 −
    
    $file = new FileInput('imagepath'); 
    $file->getValidatorChain()->attach(new UploadFile()); 
    $file->getFilterChain()->attach( 
       new RenameUpload([ 
          'target'    => './public/tmpuploads/file', 
          'randomize' => true, 'use_upload_extension' => true 
       ])); 
    $inputFilter->add($file); 
    
    • 更新RenameUpload方法以包含imagepath属性。图像路径可能来自窗体或数据库。如果图像路径来自表单,则格式将是具有以下规范的数组 −
    
    array(1) { 
       ["imagepath"] => array(5) { 
          ["name"]     => string "myimage.png" 
          ["type"]     => string "image/png"           
          ["tmp_name"] => string 
             "public/tmpuploads/file_<random_string>.<image_ext>" 
          ["error"]    => int <error_number> 
          ["size"]     => int <size> 
       } 
    }
    
    • 如果 imagepath 来自数据库,它将是一个简单的字符串。用于解析图像路径的部分代码清单如下所示 −
    
    if(!empty($data['imagepath'])) { 
       if(is_array($data['imagepath'])) { 
          $this->imagepath = str_replace("./public", "", $data['imagepath']['tmp_name']); 
       } else { 
          $this->imagepath = $data['imagepath']; 
       } 
    } else { 
       $data['imagepath'] = null; 
    }
    
    Book 模型的完整列表如下 :
    
    <?php  
    namespace Tutorial\Model;  
    use Zend\InputFilter\InputFilterInterface; 
    use Zend\InputFilter\InputFilterAwareInterface;  
    use Zend\Filter\File\RenameUpload; 
    use Zend\Validator\File\UploadFile; 
    use Zend\InputFilter\FileInput; 
    use Zend\InputFilter\InputFilter;  
    class Book implements InputFilterAwareInterface { 
       public $id; 
       public $author; 
       public $title; 
       public $imagepath;  
       protected $inputFilter;  
       public function setInputFilter(InputFilterInterface $inputFilter) { 
          throw new \Exception("Not used");
       }  
       public function getInputFilter() { 
          if (!$this->inputFilter) { 
             $inputFilter = new InputFilter(); 
             $inputFilter->add(array( 
                'name' => 'id', 
                'required' => true, 
                'filters' => array( 
                   array('name' => 'Int'), 
                ), 
             )); 
             $inputFilter->add(array( 
                'name' => 'author', 
                'required' => true, 
                'filters' => array( 
                   array('name' => 'StripTags'), 
                   array('name' => 'StringTrim'), 
                ), 
                'validators' => array( 
                   array( 
                      'name' => 'StringLength', 
                      'options' => array( 
                         'encoding' => 'UTF-8', 
                         'min' => 1, 
                         'max' => 100, 
                      ), 
                   ), 
                ), 
             )); 
             $inputFilter->add(array( 
                'name' => 'title', 
                'required' => true, 
                'filters' => array( 
                   array('name' => 'StripTags'), 
                   array('name' => 'StringTrim'), 
                ),  
                'validators' => array( 
                   array( 
                      'name' => 'StringLength', 
                      'options' => array( 
                         'encoding' => 'UTF-8', 
                         'min' => 1, 
                         'max' => 100, 
                      ), 
                   ), 
                ), 
             ));  
             $file = new FileInput('imagepath'); 
             $file->getValidatorChain()->attach(new UploadFile()); 
             $file->getFilterChain()->attach( 
                new RenameUpload([ 
                   'target'    => './public/tmpuploads/file', 
                   'randomize' => true, 
                   'use_upload_extension' => true 
                ])); 
                $inputFilter->add($file);  
                $this->inputFilter = $inputFilter; 
          } 
          return $this->inputFilter; 
       }  
       public function exchangeArray($data) { 
          $this->id = (!empty($data['id'])) ? $data['id'] : null; 
          $this->author = (!empty($data['author'])) ? $data['author'] : null; 
          $this->title = (!empty($data['title'])) ? $data['title'] : null; 
          
          if(!empty($data['imagepath'])) { 
             if(is_array($data['imagepath'])) { 
                $this->imagepath = str_replace("./public", "", 
                   $data['imagepath']['tmp_name']); 
             } else { 
                $this->imagepath = $data['imagepath']; 
             } 
          } else { 
             $data['imagepath'] = null; 
          } 
       } 
    }
    

    更新 BookTable.php

    我们更新了BookFormBook 模型。现在,我们更新BookTable并修改了saveBook方法。这足以在数据数组中包含图像路径条目,$data
    部分代码清单如下 −
    
    $data = array('author' => $book->author, 'title'  => $book->title, 
       'imagepath' => $book->imagepath 
    ); 
    
    BookTable 类的完整代码列表如下 :
    
    <?php  
    namespace Tutorial\Model;  
    use Zend\Db\TableGateway\TableGatewayInterface;  
    class BookTable {  
       protected $tableGateway; 
       public function __construct(TableGatewayInterface $tableGateway) { 
          $this->tableGateway = $tableGateway; 
       }  
       public function fetchAll() { 
          $resultSet = $this->tableGateway->select(); 
          return $resultSet; 
       }  
       public function getBook($id) { 
          $id  = (int) $id; 
          $rowset = $this->tableGateway->select(array('id' => $id)); 
          $row = $rowset->current(); 
          if (!$row) { 
             throw new \Exception("Could not find row $id"); 
          } 
          return $row; 
       }  
       public function saveBook(Book $book) { 
          $data = array ( 
             'author' => $book->author,
             'title'  => $book->title, 
             'imagepath' => $book->imagepath 
          );  
          $id = (int) $book->id; 
          if ($id == 0) { 
             $this->tableGateway->insert($data); 
          } else { 
             if ($this->getBook($id)) {  
                $this->tableGateway->update($data, array('id' => $id)); 
             } else { 
                throw new \Exception('Book id does not exist'); 
             } 
          } 
       } 
    }
    
    更新 TutorialController.php 中的 addAction:文件上传信息将在 $_FILES 全局数组中可用,并且可以使用 Request 的 getFiles( ) 方法。 因此,合并发布的数据和文件上传信息,如下所示。
    
    $post = array_merge_recursive( 
       $request->getPost()->toArray(), 
       $request->getFiles()->toArray() 
    ); 
    
    The complete listing of the addAction() method is as follows −
    
    public function addAction() { 
       $form = new BookForm(); 
       $form->get('submit')->setValue('Add');  
       $request = $this->getRequest(); 
       if ($request->isPost()) { 
          $book = new Book(); 
          $form->setInputFilter($book->getInputFilter()); 
          $post = array_merge_recursive( 
             $request->getPost()->toArray(), 
             $request->getFiles()->toArray() 
          );  
          $form->setData($post);   
          if ($form->isValid()) { 
             $book->exchangeArray($form->getData());  
             $this->bookTable->saveBook($book);  
             
             // Redirect to list of Tutorial 
             return $this->redirect()->toRoute('tutorial'); 
          } 
       }  
       return array('form' => $form); 
    }
    

    更新视图

    最后,更改“add.phtml”并包含图像路径文件输入元素,如下所示 −
    
    echo $this->formRow($form->get('imagepath'))."<br>";
    
    完整列表如下 −
    
    <?php 
    $title = 'Add new Book'; 
    $this->headTitle($title); 
    ?> 
    <h1><?php echo $this->escapeHtml($title); ?></h1> 
    <?php  
    if(!empty($form)) {  
       $form->setAttribute('action', $this->url('tutorial', array('action' => 'add'))); 
       $form->prepare();  
       echo $this->form()->openTag($form); 
       echo $this->formHidden($form->get('id')); 
       echo $this->formRow($form->get('author'))."<br>"; 
       echo $this->formRow($form->get('title'))."<br>"; 
       echo $this->formRow($form->get('imagepath'))."<br>"; 
       echo $this->formSubmit($form->get('submit')); 
       echo $this->form()->closeTag(); 
    }
    

    运行应用程序

    最后,以 http://localhost:8080/tutorial/add 运行应用程序并添加新记录。
    结果将如以下屏幕截图所示 -
    表单页面
    新书示例
    索引页
    索引页