Zend 框架


#Zend 框架集成贡献者:Christopher Hogan

// USER CONTROLLER (example form with one action ... "index")

./modules/users/controller/UserController.php

./modules/users/views/scripts/index/index.phtml (view action)

./modules/users/views/scripts/forms/myform.phtml (view action form)

// UPLOAD CONTROLLER (example code below, this is used for uploading files sent from jquery-file-upload iframe module)

./modules/users/controller/UploadController.php

脚本示例


这是一个使用了 BlueImp JQuery FileUpload 插件的简便的上传控制器。主要思路就是你先创建一个模块,然后把 FileUpload 插件集成到你的控制器中。例如,如果你有一个名为“User”的模块,并创建了一个名为“UploadController.php”的控制器。然后你将 UploadController 的 url 设为你页面表单的提交地址。

Zend 框架集成的表单示例

页面 index.phtml

<head>
<script type="text/javascript" src="http://cdn.jquerytools.org/1.2.6/full/jquery.tools.min.js"></script>
</head>
<!-- this form uses jquery tools -->
<form id="myform" method="post" enctype="multipart/form-data action="<?=$this->url(array("module"=>"user","controller"=>"**upload**","action"=>"index"),null,true);?>">
    <?= $this->partial('forms/**myform.phtml**', array('data'=>$this->data) ?>
    <button type="submit" name="signup"><?= $this->translate->_("Submit") ?></button> 
</form>
<script> 
$("#myform").validator();
</script>

重要部分:


下面这段代码基本上就是 upload controller 的主要内容了。将它替换成“upload.php”文件,这么做是因为 ZendFramework 无法与标配的“upload.php”搭配使用,这问题你应该也已经注意到了。为了跟框架完美集成,我们提供了一个超级简单的办法去实现这一点。

<?php
/************************
 * @author Christopher Hogan <ceo@foundco.com>
 ******************************/

class User_UploadController extends Objectcode_Controller_User
{
  public $session;
  private $uploads = '/../public/images/uploads';
  private $uploads_rel = '/images/uploads/';

	public function init() {
		parent::init();  // this is just for session init (pulls session data for user_id, and email)
	}
  
  public function indexAction() {
      if ($this->_request->isOptions()) {  
        // we're using user_id and email here as a way to verify the upload and store the file in a specific directory,
        // you can strip that out for your purposes.
        $this->upload( $this->session->user['id'], $this->session->user['email'] );
      }
      if ($this->_request->isPost()) {
        $this->upload( $this->session->user['id'], $this->session->user['email'] );
      }
      if ($this->_request->isGet()) {
        $this->upload( $this->session->user['id'], $this->session->user['email'] );
      }
      if ($this->_request->isDelete() || $_SERVER['REQUEST_METHOD'] == 'DELETE') {
        $this->delete( $this->session->user['id'], $this->session->user['email'] );
      }
      exit;
  }

  public function upload($user_id, $email) {
      
      if ($user_id && $email) {
          $adapter = new Zend_File_Transfer_Adapter_Http();
          $user_path = PUBLIC_PATH. $this->uploads_rel. $user_id;

          if (!file_exists($user_path)) mkdir($user_path);

          $adapter->setDestination(PUBLIC_PATH. $this->uploads_rel. $user_id);
          $adapter->addValidator('Extension', false, 'jpg,png,gif');
  
          $files = $adapter->getFileInfo();
          foreach ($files as $file => $info) {
              $name = $adapter->getFileName($file);

              // you could apply a filter like this too (if you want), to rename the file:     
              //  $name = ExampleLibrary::generateFilename($name);
              //  $adapter->addFilter('rename', $user_path . '/' .$name);

              // file uploaded & is valid
              if (!$adapter->isUploaded($file)) continue; 
              if (!$adapter->isValid($file)) continue;

              // receive the files into the user directory
              $adapter->receive($file); // this has to be on top

              $fileclass = new stdClass();

              // we stripped out the image thumbnail for our purpose, primarily for security reasons
              // you could add it back in here.
              $fileclass->name = str_replace(PUBLIC_PATH. $this->uploads_rel, 'New Image Upload Complete:   ', preg_replace('/\d\//','',$name));  
              $fileclass->size = $adapter->getFileSize($file);  
              $fileclass->type = $adapter->getMimeType($file);  
              $fileclass->delete_url = '/user/upload';
              $fileclass->delete_type = 'DELETE';
              //$fileclass->error = 'null';
              $fileclass->url = '/'; 
        
              $datas[] = $fileclass;
          }
          
          header('Pragma: no-cache');
          header('Cache-Control: private, no-cache');
          header('Content-Disposition: inline; filename="files.json"');
          header('X-Content-Type-Options: nosniff');
          header('Vary: Accept');
          echo json_encode($datas);
      }
  }

  public function delete($user_id, $email) {
      if ($user_id && $email) {
        $file_name = $this->_request->getParam('files');
        // this has been customized to remove only specific images in certain user_id folders
        // you should modify that to your needs
        $file_path = PUBLIC_PATH. $this->uploads_rel. $user_id. '/'. $file_name;
        $success = is_file($file_path) && $file_name[0] !== '.' && unlink($file_path);
      }
      echo json_encode($success);
  }

}

标准 Blueimp/Jquery-File-Upload 表单模板:


这是 myform.phtml 的标准模板。前文中将模板拆开主要为了让你便于理解模板的哪些部分是需要修改的地方。下面的代码则是插件中的示例。引用这段代码便于展示 myform.phtml 都有哪些内容。

<div id="fileupload">
        <div class="fileupload-buttonbar">
            <label class="fileinput-button">
                <span>Add files...</span>
                <input type="file" name="files[]" multiple>
            </label>
            <button type="submit" class="start">Start upload</button>
            <button type="reset" class="cancel">Cancel upload</button>
            <button type="button" class="delete">Delete files</button>
        </div>

    <div class="fileupload-content">
        <table class="files"></table>
        <div class="fileupload-progressbar"></div>
    </div>
</div>
<script id="template-upload" type="text/x-jquery-tmpl">
    <tr class="template-upload{{if error}} ui-state-error{{/if}}">
        <td class="preview"></td>
        <td class="name">${name}</td>
        <td class="size">${sizef}</td>
        {{if error}}
            <td class="error" colspan="2">Error:
                {{if error === 'maxFileSize'}}File is too big
                {{else error === 'minFileSize'}}File is too small
                {{else error === 'acceptFileTypes'}}Filetype not allowed
                {{else error === 'maxNumberOfFiles'}}Max number of files exceeded
                {{else}}${error}
                {{/if}}
            </td>
        {{else}}
            <td class="progress"><div></div></td>
            <td class="start"><button>Start</button></td>
        {{/if}}
        <td class="cancel"><button>Cancel</button></td>
    </tr>
</script>
<script id="template-download" type="text/x-jquery-tmpl">
    <tr class="template-download{{if error}} ui-state-error{{/if}}">
        {{if error}}
            <td></td>
            <td class="name">${name}</td>
            <td class="size">${sizef}</td>
            <td class="error" colspan="2">Error:
                {{if error === 1}}File exceeds upload_max_filesize (php.ini directive)
                {{else error === 2}}File exceeds MAX_FILE_SIZE (HTML form directive)
                {{else error === 3}}File was only partially uploaded
                {{else error === 4}}No File was uploaded
                {{else error === 5}}Missing a temporary folder
                {{else error === 6}}Failed to write file to disk
                {{else error === 7}}File upload stopped by extension
                {{else error === 'maxFileSize'}}File is too big
                {{else error === 'minFileSize'}}File is too small
                {{else error === 'acceptFileTypes'}}Filetype not allowed
                {{else error === 'maxNumberOfFiles'}}Max number of files exceeded
                {{else error === 'uploadedBytes'}}Uploaded bytes exceed file size
                {{else error === 'emptyResult'}}Empty file upload result
                {{else}}${error}
                {{/if}}
            </td>
        {{else}}
            <td class="preview">
                {{if thumbnail_url}}
                    <a href="${url}" target="_blank"><img src="${thumbnail_url}"></a>
                {{/if}}
            </td>
            <td class="name">
                <a href="${url}"{{if thumbnail_url}} target="_blank"{{/if}}>${name}</a>
            </td>
            <td class="size">${sizef}</td>
            <td colspan="2"></td>
        {{/if}}
        <td class="delete">
            <button data-type="${delete_type}" data-url="${delete_url}">Delete</button>
        </td>
    </tr>
</script>

结语


本脚本非常简单。它以优雅的方式重构了默认 upload.php 的代码逻辑,唯一的区别就是它是基于 Zend 框架并只有 100 行代码。另外,如果你需要向数据库添加内容,我强烈建议你使用 Doctrine!

欢迎反馈问题和建议。谢谢!