Zend Framework入門

第2章 Zend Frameworkの基本

前へ | 目次へ |次へ  | Yamada-Lab

2.2 MVCモデルの基本

 Zend FrameworkではMVC(Model - View - Controller)モデルというアーキテクチャが採用されています。

Model

 Model(モデル)は、データ管理を担当する部分です。データは一般にデータベースやファイルに保存されます。またRSSデータなどの場合もあります。モデルは、データベースなどにデータを保存したり、読み込んだり、更新したり、削除したりする機能を有します。

■View

 View(ビュー)は、入力や出力のための画面表示を担当する部分です。ユーザインタフェース部分であり、いわゆるHTML記述の部分です。

■Controller

 Controller(コントローラ)は、全体の制御を行います。つまり、クライアントから処理要求を受け、データの読み込みや保存をモデルに依頼し、データの入出力のためのクライアント画面の表示をビューと連携して行います。

リクエスト リクエスト データ書き込み  

クライアント
 


View
(画面表示)
 



Controller
(全体制御)
  


Model
(データ管理)
 


データベース
/外部ファイル
など  
レスポンス 画面表示要求 データ読み取り  

MVCモデルと処理フロー

■Zend_Controllerの基本

 Zend Frameworkでコントローラを担当するクラス群(コンポーネントという)をZend_Controllerといいます。

 一般にWebアプリケーションでは、以下の3つのステップを繰り返し行っています。

@クライアント(ユーザ)からのリクエストを受ける

A必要な処理をサーバで行う

Bレスポンスをクライアントに返す(画面に表示する)

 Zend Frameworkでは、このステップを以下のように細分化して実行します。

リクエスト
フロント
コントローラ
 

ルータ
 

ディスパッチャ
 
アクション
コントローラ
 

レスポンス
   
クライアントからのリクエストをすべて一元的に受け取る
 
リクエストの内容を解析し、処理を担当するアクションコントローラを決定する
 
ルータが決定したアクションコントローラに処理を委譲する
 
ページ対応の実際の処理を行う
   

Zend Frameworkの基本処理フロー

■Zend Frameworkのディレクトリ構造

 Zend Frameworkでは、MVCモデルに対応し、一般に以下のディレクトリ構造にします。

/html                         公開ディレクトリ
   .htaccess                    Zend_Controllerを利用するための設定
   index.php                    フロントコントローラ


/application                     アプリケーションディレクトリ
   /controllers                  コントローラ用ディレクトリ
      IndexController.php           デフォルトのコントローラ
   /models                     モデル用ディレクトリ
   /views                      ビュー関連用ディレクトリ
      /scripts                  ビュースクリプト用ディレクトリ
         /index                デフォルトコントローラ名
            index.phtml          ビュースクリプト(<アクション名>.phtml
      /helpers                  ヘルパースクリプト用ディレクトリ
      /filters                   フィルタースクリプト用ディレクトリ

 ここでは、以下のディレクトリ構造としています。Windows Vista環境なので、「/」の代わりに「\」で記述しています。ドキュメントルートディレクトリは「c:\Apache2.2\htdocs\」です。各種サンプルスクリプトを平行して動作できるようにサンプルスクリプトごとに「サブディレクトリ1\サブディレクトリ2\」を設けることとします。

c:\Apache2.2\htdocs\zf\サブディレクトリ1\サブディレクトリ2    上記/htmlに相当
   .htaccess
   index.php

c:\Apache2.2\zendaps\サブディレクトリ1\サブディレクトリ2     上記/applicationに相当
   \controllers
   \models
   \views

■Rewriteエンジン

 Rewriteエンジンとは、リクエストされたURLを特定のルールにもとずき書き換える機能のことをいいます。Rewriteエンジンを有効にするにはApacheの環境設定ファイルであるhttpd.confファイルで以下の設定をしておく必要があります。

#LoadModule rewrite_module modules/mod_rewrite.so
を、冒頭のコメント行の記号「#」を削除し、
LoadModule rewrite_module modules/mod_rewrite.so
とする。

 さらに、ドキュメントディレクトリ(c:\Apache2.2\htdocs)内の.htaccessの設定を有効にするため、以下を追記します。

<Directory "C:/〜/htdocs">
  AllowOverride All
</Directory>

 httpd.confファイルを編集した場合は、Apacheを再起動する必要があります。Apache2.2の場合は以下により再起動します。

httpd -k restart

 次に、.htaccessファイルにRewriteルールを以下のように記述します。

.htaccess

RewriteEngine on
RewriteBase /サブディレクトリ1/サブディレクトリ2/
RewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php

 たとえば、サブディレクトリ1が「hello」でサブディレクトリ2が「01」の場合は、公開ディレクトリ「c:\Apache2.2\htdocs\zf\hello\01\」に配置する.htaccessファイルは以下のように記述します。

c:\Apache2.2\htdocs\zf\hello\01\.htaccess

RewriteEngine on
RewriteBase /hello/01/
RewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php

 この意味は、「http://localhost:8080/hello/01/・・・・・・・.拡張子」のようなURLでのリクエストがあった場合、拡張子がjs、ico、gif、jpg、png、css以外のリクエストは全て「http://localhost:8080/hello/01/index.php」を呼び出す、つまりフロントコントローラindex.phpに一元的に渡す、という意味になります。

■フロントコントローラ

 フロントコントローラindex.phpは以下のように記述します。

index.php(フロントコントローラ)

<?php
//フロントコントローラ用のコンポーネントの呼び出し
require_once 'Zend/Controller/Front.php';
/**フロントコントローラのインスタンスの取得
 *コントローラのディレクトリ指定
 *ディスパッチ
 */
Zend_Controller_Front::run('../../../../zendapps/サブディレクトリ1/サブディレクトリ2/controllers');

 たとえば、サブディレクトリ1が「hello」でサブディレクトリ2が「01」の場合は、公開ディレクトリ「c:\Apache2.2\htdocs\zf\hello\01\」に配置するindex.phpファイルは以下のように記述します。

c:\Apache2.2\htdocs\zf\hello\01\index.php

<?php
//フロントコントローラ用のコンポーネントの呼び出し
require_once 'Zend/Controller/Front.php';
/**フロントコントローラのインスタンスの取得
 *コントローラのディレクトリ指定
 *ディスパッチ
 */
Zend_Controller_Front::run('../../../../zendapps/hello/01/controllers');

 最後の行で、フロントコントローラのインスタンスの取得とアクションコントローラの指定とディスパッチを一挙に行っています。

■デフォルトコントローラ

 Zend Frameworkでは、もっとも基本となるアクションコントローラをデフォルトコントローラといいます。デフォルトコントローラはコントローラ名がindex、アクション名がindexのアクションコントローラです。コントローラ名にかかわらず、アクション名がindexであるアクションをデフォルトアクションといいます。

 デフォルトコントローラの基本的なリストを以下に示します。ファイル名はZend Frameworkの命名規則によりIndexController.phpです。コントローラファイルはコントローラ用ディレクトリに置きます。

IndexController.php(デフォルトコントローラ)

<?php
//Zend_Controllerコンポーネントのロード
require_once 'Zend/Controller/Action.php';

//デフォルトコントローラアクションを定義
//(Zend_Controller_Actionクラスを継承してコントローラクラスを生成)
class IndexController extends Zend_Controller_Action {

  //デフォルトアクションを定義(メソッドとして記述)
  public function indexAction() {

    //処理を記述

  }
}

■アクションコントローラの基本

 アクションコントローラは、フロントコントローラから委譲されて、あらかじめ定められた処理を実行します。アクションコントローラにはいくつかのアクションが含まれ、具体的な処理は個々のアクションが担当します。アクションコントローラは一つのクラスで、一つのアクションは一つメソッドに対応します。

 アクションコントローラファイルは、一つのコントローラクラスが定義されたPHPファイルで、上記のアプリケーションディレクトリ配下のコントローラ用ディレクトリ(\conntroller)に置きます。ファイル名は、クラス名+「.php」とします。

 コントローラクラスは、必ずZend_Controller_Actionクラスを継承して作成します。クラス内には具体的な処理を行う「アクション」をメソッドとして定義します。

■アクションコントローラの命名規則

対象 規則
クラス名 <アクションコントローラ名>Controller。頭文字は大文字 IndexController
ファイル名 <クラス名>.php IndexController.php
メソッド名 <アクション名>Action。頭文字は小文字。
以降単語の区切りは先頭大文字(CamelCase記法)
indexAction、editAction

■アクションの役割

 アクションは具体的な処理を行います。アクションコントローラ内のどのアクションを呼び出すかは、URLを解読してフロントコントローラが決めています。

 アクションが実行された後、Zend_Controllerは対応するビュースクリプトをデフォルトで自動的に呼び出し、画面を出力します。ビュースクリプトはMVCモデルのViewに相当します。ビュースクリプトについては後述します。

 ビュースクリプトを呼び出し、画面を出力することを「レンダリング」といい、アクション内に明示的に記述しなくても自動的にレンダリングを行うことを「自動レンダリングモード」といいます。

■Zend Frameworkのアクション呼び出し方法

 Zend Frameworkでクライアントのブラウザからリクエストを送信するには、以下のURL表記を使います。

http://mywebsite/<コントローラ名>/<アクション名>/<パラメータ1>/<パラメータ1の値>/<パラメータ2>
/<パラメータ2の値>/…

 たとえば、ここでのhttp://mywebsite/の部分はは「http://localhost:8080/zf/hello/01/」なので、

http://localhost:8080/zf/hello/01/index/hello/id/2

のURL表記の場合は、「index」アクションコントローラの「hello」アクションにパラメータ値が「id=2」でリクエストしたことになります。このようなURLの解析と該当するアクションコントローラへの処理の委譲はフロントコントローラ(公開ディレクトリ内のindex.php)が行っています。アクションコントローラ名の頭文字は、URL内では小文字とします。

■簡単なアプリケーション

 以上で、Zend_Controllerを使って具体的なアプリケーションを作成する準備ができました。最初のアプリケーションとして、「こんにちは!」の文字列を表示するもっとも簡単なアプリケーションを作成してみます。これを「Hello」アプリケーションと呼ぶこととします。

 まずは、デフォルトのアクションコントローラ(IndexController)のみを使って実行してみます。そこで、デフォルトアクション(index)に対応するindexActionメソッド内に文字列表示を実行する「 echo 'こんにちは!';」を記述します。

c:\apache2.2\zendapps\hello\01\controller\IndexController.php

<?php
//Zend_Controllerコンポーネントのロード
require_once 'Zend/Controller/Action.php';

//デフォルトコントローラアクションを定義
//(Zend_Controller_Actionクラスを継承してコントローラクラスを生成)
class IndexController extends Zend_Controller_Action {

  //デフォルトアクションを定義(メソッドとして記述)
  public function indexAction() {
    //文字列を表示
     echo 'こんにちは!';
  }
}

 ここでは、「Hello」アプリケーション専用ディレクトリ作成することとし、上記のサブディレクトリ1を「hello」、サブディレクトリ2を「01」とした、「c:\apache2.2\zendapps\hello\01\controller\」というコントローラ用ディレクトリに置きます。

 それでは、このHelloアプリケーションを動作させてみましょう。URLは公開ディレクトリが「http://localhost:8080/zf/hello/01/」で、アクションコントローラ名が「index」、アクション名が「index」ですので、以下となります。

http://localhost:8080/zf/hello/01/index/index/

 ただ、後続のパラメータがない場合は、デフォルトアクション(index)さらにデフォルトアクションコントローラ(index)の記述は省略でき、以下のように簡略化してブラウザからアクセスできます。

http://localhost:8080/zf/hello/01/

 アクセスした結果は、以下のようにエラーが表示されてしまいました。

 これは、Zend_Controllerがデフォルトの自動レンダリングモードに設定されており、デフォルトアクションに対応するindexActionメソッドの最後の部分で、ビュースクリプトを呼び出そうとして、そのビュースクリプトが見つからず、エラーなってしまったためです。

 本来なら、indexActionメソッドに対応するビュースクリプト(index.phtml)ファイルが、Zend Frameworkの規則により、ビュースクリプト用ディレクトリ(c:\apache2.2\zendapps\hello\01\views\scripts\)の下のアクションコントローラ名と同じ名称のサブディレクトリ(\index)の下に「アクション名+.phtml」のファイル名を付与して置いておく必要があったのです。

 そこで、とりあえず、自動レンダリングモードを無効にして、再度アクセスしてみます。自動レンダリングモードを無効にするために、フロントコントローラに以下の1行を挿入します。

Zend_Controller_Front::getInstance()->setParam('noViewRenderer',true);

c:\Apache2.2\htdocs\zf\hello\01\index.php

<?php
//フロントコントローラ用のコンポーネントの呼び出し
require_once 'Zend/Controller/Front.php';

//自動レンダリングを無効にする
Zend_Controller_Front::getInstance()->setParam('noViewRenderer',true);

/**フロントコントローラのインスタンスの取得
 *コントローラのディレクトリ指定
 *ディスパッチ
 */
Zend_Controller_Front::run('../../../../zendapps/hello/01/controllers');

 今度は、正しく動作します。

 しかし、上記のようにアクションメソッド(indexAction)の中に、画面表示に関するスクリプトを直接記述するのは、MVCモデルの観点からは好ましくありません。

 そこで、次の項で、HelloアプリケーションをZend_ControllerのMVCモデルに沿って作成してみます。

■簡単なアプリケーション(MVCモデル)の構造

 Zend Frameworでは、MVCモデルにもとづき処理を分離し、おのおの個別にファイル化しているので、ファイル数が多くなり、ファイルの相互関係もわかりにくくなりがちです。HelloアプリケーションをMVCモデルにより構成すると、以下のようになります。

                 HelloアプリケーションのMVCモデルによる構成

 Zend_Controllerでアプリケーションを構成する場合に最低限必要なものは、図からもわかるように次の3つです。

・フロントコントローラ
・アクションコントローラ
・ビュースクリプト

 フロントコントローラは、クライアントからのリクエストであるURLを解析し、処理を引き継ぐべきアクションコントローラ(ここではデフォルトのindexコントローラ)、とアクション(ここではデフォルトのindexアクション)を決定し、それらに処理を委譲します。処理を委譲されたデフォルトアクションコントローラは、フロントコントローラにより指定されたその中のデフォルトアクションを駆動します。デフォルトアクションは具体的な処理を実行し(ここでは、何もないが)、最後に対応するビュースクリプトにレンダリング処理を要求し、結果として画面表示のデータをクライアントに出力します。

■簡単なアプリケーション(MVCモデル)の作成

 Helloアプリケーションでは、固定的に「こんにちは!」を表示するだけですので、画面表示に対応するビュースクリプトは特に変数等を用いず、以下のような静的なHTMLスクリプトになります。ただ、<head>タグ内は、タイトルのみの極めて単純なものにしてあります。

c:\apache2.2\zendapps\hello\01\views\scripts\index\index.phtml

<html>
<head>
<title>Hello</title>
</head>
<body>
こんにちは!
</body>
</html>

 ビュースクリプトの配置先とファイル名は、以下の規則によります。アクションコントローラ名は頭は小文字です。拡張子は「.phtml」とします。

application/views/scripts/<アクションコントローラ名>/<アクション名>.phtml

 今回の例では、次のようにします。

c:\apache2.2\zendapps\hello\01\views\scripts\index\index.phtml

 また、フロントコントローラ(公開ディレクトリ内のindex.php)は、自動レンダリングモードを有効にするために、以下のように元に戻しておきます。

c:\Apache2.2\htdocs\zf\hello\01\index.php

<?php
//フロントコントローラ用のコンポーネントの呼び出し
require_once 'Zend/Controller/Front.php';
/**フロントコントローラのインスタンスの取得
 *コントローラのディレクトリ指定
 *ディスパッチ
 */
Zend_Controller_Front::run('../../../../zendapps/hello/01/controllers');

 アクションコントローラファイル(IndexController.php)は、以下のように書き直します。つまり、ビュースクリプトに書かれた静的なHTML文書を出力するだけなので、アクションメソッド(IndexAction)内では何も記述する必要がなく空にしておきます。ただ、自動レンダリングモードが有効になっているので、Zend_Controllerは、アクションメソッド(IndexAction)を終了する直前に、このアクションコントローラ(index)、アクションメソッド(index)に対応するビュースクリプト\views\scripts\index\index.phtmlを呼び出して、クライアントに出力します。

c:\apache2.2\zendapps\hello\01\controller\IndexController.php

<?php
//Zend_Controllerコンポーネントのロード
require_once 'Zend/Controller/Action.php';

//デフォルトアクションコントローラを定義
//(Zend_Controller_Actionクラスを継承してコントローラクラスを生成)
class IndexController extends Zend_Controller_Action {

  //デフォルトアクションを定義(メソッドとして記述)
  public function indexAction() {

  }
}

 再度、「http://localhost:8080/zf/hello/01/」にアクセスした結果は、以下のように正常に動作します。なお、今回は、ビュースクリプトでタイトルを明示的に「Hello」としたので、ブラウザにもそのように表示されています。

 以上、Zend Frameworkを用い、MVCモデルを尊重した簡単なアプリケーションを作成し動作させてみました。MVCモデルのModelは使用していませんが、ViewとControllerは使用しています。Zend Frameworkというフレームワークを利用しているため、環境設定やディレクトリ構造が複雑だったり、あるいはフロントコントローラファイル、アクションコントローラファイル、ビュースクリプトファイルの作成や相互関係の理解にやや時間を要しますが、Zend Frameworkの基本は理解できたかと思います。

 ここで、Helloアプリケーションで使用しているディレクトリ構造を整理しておきます。

c:\Apache2.2\htdocs\zf\hello\01 
  .htaccess          
  index.php   
       
c:\Apache2.2\zendapps\hello\01 
  \controllers        
    IndexController.php   
  \models           
  \views           
    \scripts        
      \index       
        index.phtml   

c:\ZendFramework        
  \library          

公開ディレクトリ
Rewriteエンジン制御ファイル
フロントコントローラファイル

アプリケーションディレクトリ
コントローラディレクトリ
デフォルトアクションコントローラファイル
モデル用ディレクトリ(今回使用せず)
ビュー関連ディレクトリ
ビュースクリプトディレクトリ
デフォルトアクションコントローラ用ディレクトリ
デフォルトアクション用ビュースクリプト

Zend Framework本体のディレクトリ
Zend Frameworkのライブラリーのディレクトリ

■変数表示の基本

 先のHelloアプリケーションでは、静的なHTMLデータを出力するだけで、アクションコントローラで設定した変数などを表示するしくみについては述べていませんでした。ここでは動的なHTMLデータを出力する基本的な例として、アクションコントローラで設定した変数の値を画面に表示する簡単なアプリケーションを作成します。

 ここで利用するサブディレクトリ1は「hello」、サブディレクトリ2は「02」とします。したがって、公開ディレクトリは「c:\Apache2.2\htdocs\zf\hello\02」、アプリケーションディレクトリは「c:\Apache2.2\zendaps\hello\02」とします。

 .htaccessファイルは次のように記述し、配置します。

c:\Apache2.2\htdocs\zf\hello\02\.htaccess

RewriteEngine on
RewriteBase /hello/02/
RewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php

 フロントコントローラのindex.phpファイルは以下のように記述し、配置します。

c:\Apache2.2\htdocs\zf\hello\02\index.php

<?php
//フロントコントローラ用のコンポーネントの呼び出し
require_once 'Zend/Controller/Front.php';
/**フロントコントローラのインスタンスの取得
 *コントローラのディレクトリ指定
 *ディスパッチ
 */
Zend_Controller_Front::run('../../../../zendapps/hello/02/controllers');

 自動レンダリングモードは、有効にしておきます。Zend Frameworkでは、自動レンダリングモードが推奨されています。

 アクションコントローラのIndexController.phpファイルは、以下のように記述し、配置します。

c:\apache2.2\zendapps\hello\02\controller\IndexController.php

<?php
//Zend_Controllerコンポーネントのロード
require_once 'Zend/Controller/Action.php';

//デフォルトコントローラアクションを定義
//(Zend_Controller_Actionクラスを継承してコントローラクラスを生成)
class IndexController extends Zend_Controller_Action {

  //デフォルトアクションを定義(メソッドとして記述)
  public function indexAction() {
    //文字列をview変数resultに設定
    $this->view->result = '今日は!';
  }
}

 アクションメソッドは、受け取ったリクエスト情報を処理したり、全体の制御を行う役割があるとともに、ビューの生成に必要な情報をあらかじめすべて設定しておく役割もあります。ビューの生成に必要な情報を「ビュー変数」といいます。ビュー変数の値は以下の構文で設定します。

$this->view->変数名 = 値;

自動レンダリングモードではビュースクリプトのインスタンスは「$this->view」に固定されています。

 ビュースクリプトのindex.phtmlファイルは、以下のように記述し、配置します。

c:\apache2.2\zendapps\hello\02\views\scripts\index\index.phtml

<html>
<head>
<title>Hello_02</title>
</head>
<body>
<?php print($this->result); ?>
</body>
</html>

 アクションコントローラで設定されたビュー変数を参照するには以下の構文を使います。

$this->変数名

 このサンプルへのアクセス結果は以下ののようになります。

■リクエスト処理の基本

 上記のHelloアプリケーションでは、クライアントからのリクエストは単にURLの指定だけでした。一般にクライアントからのリクエストはURLの指定のほかに、HTMLフォームを使いメニューの選択や文字列の送信を伴います。ここではHTMLフォームを使ったリクエストをZend_Controllerで処理する方法の基本について述べます。

 ここでは、ブラウザの名前欄に「○○」と入力し、そのレスポンスとしてブラウザに「今日は、○○さん!」と表示するGreetingアプリケーションを作成します。

 Greetingアプリケーションでは、「/サブディレクトリ1/サブディレクトリ2/」は、上記Helloアプリケーションの「/hello/02/」をそのまま使うこととします。ただし、アクションコントローラとしては、デフォルトアクションコントローラ(IndexController)でなく、新たにrequestアクションコントローラ(RequestController)を作成することとします。

 リクエストアクションコントローラのRequestController.phpファイルは、以下のように記述し、配置します。

c:\apache2.2\zendapps\hello\02\controller\RequestController.php

<?php
//Zend_Controllerコンポーネントのロード
require_once 'Zend/Controller/Action.php';

//requestコントローラアクションを定義
//(Zend_Controller_Actionクラスを継承してコントローラクラスを生成)
class RequestController extends Zend_Controller_Action {

  //デフォルトアクションを定義(特別な処理はなし)
  public function indexAction() {

  }

  //postアクションを定義(「送信」ボタンクリック時に呼び出される)
  public function postAction() {
    //POSTデータnameからあいさつメッセージを生成
    //(リクエストオブジェクトの取得)
    $request = $this->getRequest();
    $this->view->result = '今日は、' . $request->getPost('name')
               . 'さん!';

  }
}

 Zend_Controllerで、クライアントから送られてきたPOSTデータを受信するには、以下の構文を使います。

リクエストオブジェクト名= $this->getRequest();
変数 = リクエストオブジェクト名->getPost('変数名') ;

getPost()メソッドは、PHPのスーパーグローバル変数$_POSTに対応しています。

 たとえば、次のように使います。

$request = $this->getRequest();
$name =$request->getPost('name') ;

 ちなみに、PHPのスーパーグローバル変数$_GETに対応するクエリ情報を受信するには、以下の構文を使います。

リクエストオブジェクト名= $this->getRequest();
変数 = リクエストオブジェクト名->getQuery('変数名') ;

POSTデータやクエリ情報は、getParamメソッドでも受信できますが、取得元があいまいになるので使用しない方がいいでしょう。つまり、getParamメソッドでは、指定された変数名のデータをまずクエリ情報から取得しようとし、クエリ情報にない場合は、POSTデータから、POSTデータにない場合はユーザパラメータから、順に取得しようとします。したがって、POSTデータの変数名nameを取得しようとしてgetParam('names')とし、たまたまユーザパラメータにnamesという変数名が定義されていると、その値をPOSTデータと間違えて取得してしまいます。このようなバグはなかなか発見しにくくなります。

 requestアクションコントローラのデフォルトアクションに対応するビュースクリプトのindex.phtmlファイルは、以下のように記述し、配置します。ビュースクリプト用ディレクトリ\views\scripts\の下に、新たにrequestアクションコントローラ名と同じ名称のサブディレクトリ\request\を作成し、その下に配置します。

c:\apache2.2\zendapps\hello\02\views\scripts\request\index.phtml

<html>
<head>
<title>Greeting</title>
</head>
<body>
<!-- request/postアクションにPOSTデータを送信-->
<form method="POST" action="request/post">
名前:<input type="text" name="name" size="10">
<input type="submit" value="送信">
</form>

</body>
</html>

 requestアクションコントローラのpostアクションに対応するビュースクリプトのpost.phtmlファイルは、以下のように記述し、配置します。

c:\apache2.2\zendapps\hello\02\views\scripts\request\post.phtml

<html>
<head>
<title>Greeting</title>
</head>
<body>
<!-- ビュー変数resultの値を出力-->
<?php print($this->result); ?>
</body>
</html>

 このGreetingアプリケーションへのアクセスは、「http://localhost:8080/zf/hello/02/request/index/」のURLになります。最後のindexアクションは、デフォルトアクションなので省略可能で、「http://localhost:8080/zf/hello/02/request」でもアクセスできます。

 アクセス結果は以下のとおりです。

 名前を入力して、「送信」ボタンをクリックすると、次のようにあいさつが表示されます。

■セキュリティ対策

 Webアプリケーションでは、クライアントがブラウザからWebサーバにデータを送信し(下図の@)、Webサーバが必要に応じデータベースにアクセスし(下図A)、その結果(下図B)を、HTML形式でクライアントに返信し(下図C)、クライアントのブラウザに表示されます。この過程で、クライアントが送信データの中に悪意のスクリプトを記述したりすると、本来のWebアプリケーションで想定した処理とは異なる処理を実行し、不正アクセス、情報漏えいやデータ改ざんなどをもたらしてしまう場合があります。


      Webアプリケーションにおけるセキュリティ対策

 おのおのの位置におけるセキュリティ上の脆弱性は、Aでは「SQLインジェクション」、Cでは「クロスサイドスクリプティング」と呼ばれ、@では、双方の脆弱性の原因が混入する可能性があります。このようなセキュリティ上の脆弱性を回避するための対策として、@では「エスケープ処理」、Aでは「クォート処理」、Cでは「サニタイジング」という処理が行われます。

 ただ、これらの対策は、プログラマーが明示的にコード化する必要があり、極めて重要なことです。これらの対策を怠ると、自らのWebサーバやクラインアントが被害をこうむるばかりでなく、自らのWebサーバやクライアントに知らず知らずの内に浸入されて、DoS(サービス拒否)攻撃の踏み台されるなど、ネットワーク妨害に加担することになりかねません。

位置 脆弱性 セキュリティ対策
@  

エスケープ処理
「'」(シングルクオート)、「"」(ダブルクオート)、「\」(バックスラッシュ)、ヌル文字をエスケープ処理します。

A SQLインジェクション

クオート処理
「'」(シングルクオート)をエスケープした後、文字列全体を「'」(シングルクオート)で囲みます。

C クロスサイドスクリプティング

サニタイジング
HTML予約文字「<」、「>」、「&」、「"」を、おのおの「&lt;」、「&gt;」、「&amp;」、「&quot;」に変換する。

■エスケープ処理

 標準のphp.iniファイルでは、マジッククオートが有効(magic_quotes_gpc=On)に設定されています。その結果、POSTメソッドやGETメソッドなどからの入力値はaddslashes関数を利用して自動的にエスケープ処理されています。具体的には、「'」(シングルクオート)、「"」(ダブルクオート)、「\」(バックスラッシュ)、ヌル文字がエスケープ処理されます。

 上記のGreetingアプリケーションで、「"山田"」と入力すると、下記のように「"」の直前に「\」(バックスラッシュ)が挿入され表示されます。

 addslashes関数でエスケープ処理された入力データをアンエスケープし元に戻すには、stripslashes関数を使います。

 上記リクエストアクションコントローラのRequestController.phpファイルは、以下のようにgetPostメソッドで受信したデータをstripslashes関数でアンエスケープするように変更します。

c:\apache2.2\zendapps\hello\03\controller\RequestController.php

<?php
//Zend_Controllerコンポーネントのロード
require_once 'Zend/Controller/Action.php';

//requestコントローラアクションを定義
//(Zend_Controller_Actionクラスを継承してコントローラクラスを生成)
class RequestController extends Zend_Controller_Action {

  //デフォルトアクションを定義(特別な処理はなし)
  public function indexAction() {

  }

  //postアクションを定義(「送信」ボタンクリック時に呼び出される)
  public function postAction() {
    //POSTデータnameからあいさつメッセージを生成
    //(リクエストオブジェクトの取得)
    $request = $this->getRequest();
    $this->view->result = '今日は、'
               . stripslashes($request->getPost('name'))
               . 'さん!';
  }
}

 結果は、次のように挿入されていたバックスラッシュが削除されます。

■サニタイジング

 上記のGreetingアプリケーションで、「<b>山田</b>」と入力してみます。

 すると、「山田」が太字で表示されます。つまりHTMLタグがWebサーバで有効に受信され、かつ再度クライアントに有効に返信されていることがわかります。

 次に、「<script>alert('悪意のスクリプト')</script>」とjavascriptを入力してみます。

 すると、javascriptのスクリプトがWebサーバで有効に受信され、かつ再度クライアントに有効に返信され動作していることがわかります。

 もし、ファイルを削除するスクリプトや情報漏えいのスクリプトなど悪意のスクリプトが入力されると、セキュリティ上大きな脅威になります。

 このようなセキュリティ上の脆弱性をなくするには、クライアントから入力されたデータやメールで受け付けたデータなどをクライアントに送信する場合は、HTMLタグを無効にする必要があります。このような対策を「サニタイジング」と呼びます。サニタイジングでは、HTML予約文字「<」、「>」、「&」、「"」を、おのおの「&lt;」、「&gt;」、「&amp;」、「&quot;」に変換します。このような変換処理にはPHPのhtmlspecialchars関数が使えますが、Zend FrameworkではZend_viewが提供するescapeメソッドの使用を推奨しています。

 具体的には、ビュースクリプトのpost.phtmlファイルを、以下のように変更します。

c:\apache2.2\zendapps\hello\04\views\scripts\request\post.phtml

<html>
<head>
<title>Greeting</title>
</head>
<body>
<!-- ビュー変数resultの値を出力-->
<?php print(this->escape($this->result)); ?>
</body>
</html>

 結果は、次のように表示され、HTMLタグが無効化され、単に記号として表示されセキュリティ上の問題はなくなります。

 このように、ビュー変数経由で動的にクライアントに出力するデータにはエスケープ処理を忘れないで行います。

クロスサイトスクリプティングの脆弱性については、たとえば以下のWebサイトを参照されるとよい。
クロスサイトスクリプティング対策の基本
 http://www.atmarkit.co.jp/fsecurity/special/30xss/xss01.html
クロスサイトスクリプティング脆弱性とその対策の要領
 http://www.ipa.go.jp/security/awareness/vendor/programming/a01_02.html

 ここまで、MVCモデルにもとずいたZend Frameworkの利用法のうち、V(ビュー)とC(コントローラ)の基本について述べた。M(モデル)の基本については、次節(2.3)で述べる。

【参考文献】

藤野真吾:「PHPフレームワーク Zend Framework入門」、ソーテック社、2007/9/30、
Chapter3-02MVCモデル、pp.50-65

山田祥寛:「Zend Framework徹底入門」、翔泳社、2008/9/17
Chapter2 Zend_ControllerによるMVCプログラミングの基礎、pp.36-82

Zend Framework入門(2):Hello World!アプリケーションの作成
http://codezine.jp/article/detail/1961?mode=print

 


前へ | 目次へ |次へ  | YCポータルサイト

執筆 山田豊通
更新日: 2009年3月11日