FuelPHP 勉強会 大須 vol. 1
          水野 史土
     mizuno@php-web.net
FuelPHP とは

● 軽量&シンプルなフレームワーク
  ○ ファイル 756(5.1 MB)、含ドキュメント
  ○ cf. CakePHP2.1.3 ファイル 1,356(8.8 MB)
● 最初から PHP5.3 前提
● ルールが緩い
● オープンソース
  ○ https://github.com/fuel
  ○ 多くのユーザーがコミットしている
フォルダ構成

         fuel 本体
            app
            core
            packages

         public 公開部分
fuel/app フォルダ

           コントローラ、モデルは
           classes 配下

           ビューは app/views を使う
作ってみたサイト

● FuelPHP クラス名検索
 ○   http://fuel.php-web.net/
 ○   FuelPHP のクラス名から、ソースコード閲覧
 ○   PHP のリフレクション機能を活用
 ○   Model は未使用


● 使用したソースコード
 ○   https://github.com/twitter/bootstrap
 ○   https://github.com/jquery
 ○   https://github.com/pornel/PHPTAL
 ○   https://github.com/kenjis/sample-contact-form/
http://fuel.php-web.net/
http://fuel.php-web.net/ の構造

リフレクション             ビュー
(通常のアプリ            PHPTAL
のモデル部分)



         コントローラ
コントローラ

● fuel/app/classes/controller に置く

fuel/app/classes/controller/methodlist.php

class Controller_Methodlist extends Controller
{
   public function action_index()
   {
   …
コントローラのクラス

● Controller_(ファイル名) というクラス名
  ○ (ファイル名) の先頭は大文字


● Controller を継承する
コントローラのメソッド名

● action_hoge メソッド
  ○ URL/クラス名/hoge でアクセス可能
  ○ URL/クラス名/ => action_index
● action_ をつけないメソッド
  ○ ブラウザからは(たぶん)呼び出しできない


fuel.php-web.net では、
フォームを作るメソッド _form()
$this->_form() で呼び出している
特殊なメソッド名

● before()
  ○ 他のメソッドの呼び出し前に実行
● after($response)
  ○ 他のメソッドの呼び出し後に実行

fuel.php-web.net では未使用
URL とコントローラの対応
     URL/methodlist/index
                 ↓
  methodlist.php の action_index()


    URL/methodlist/list/Arr
                ↓
 methodlist.php の action_list('Arr')
ルーティング

● fuel/app/config/routes.php で設定


_root_ トップページへアクセスした時
( http://fuel.php-web.net/ )

_404_ 見つからない時
(キャッチオール的に使える)
(404 レスポンス を指定する必要あり)
fuel/app/config/routes.php
return array(
   '_root_' => 'methodlist/index',
   '_404_' => 'methodlist/404',
);

         fuel.php-web.net にアクセス
                     ↓
fuel.php-web.net/index.php/methodlist/index
ビューのファイルを指定する

$view = View::forge('methodlist/index');

素のビューを使う場合は、
View::forge(フォルダ/ファイル名)で指定する
ビューに渡すデータ設定 方法1

$view = View::forge('methodlist/index');
$view->set('title', 'クラス名検索');

$view->set(変数名, 値)
ビューに渡すデータ設定 方法2

$view = View::forge('methodlist/index');
$view->title = 'クラス名検索';

$view->変数名 = 値
ビューに渡すデータ設定 方法3
$data['title'] = 'クラス名検索';
return View::forge('methodlist/index',$data);

連想配列に格納 → View::forge に引数で渡す
標準以外のビューを使う

Twig
Mustache
Markdown
Dwoo
Jade
Haml
Smarty
Phptal
app/config/config.php
  'always_load' => array(
     'packages' => array(
         'parser', // ここを追加する
     ),
     ...
  );
app/vendor にライブラリを設置する

ライブラリをダウンロードする
app/vendor 以下に置く
app/vendor/PHPTAL/PHPTAL.php


Mustache と markdown はデフォルトで入っている
PHPTAL のライセンス

FuelPHP : MIT

PHPTAL : LGPL

ライブラリは MIT とは限らない
PHPTAL を使う

● コントローラ
         View::forge
             ↓
      View_Phptal::forge


      config で設定できる?
PHPTAL を使う

● FuelPHP で使う場合
  ○ 拡張子 .phptal (*)
  ○ 明示的に指定すれば .html でも可


● ファイルは app/views フォルダに置く




* FuelPHP 以外では .html のこともある
PHPTAL の特徴 1

● テンプレートファイル(HTML) の属性に記述する

   <h1 tal:content="title">title here</h1>
                      ↓
     <h1>FuelPHPクラス名検索</h1>

● テンプレートをブラウザで表示して確認可能
app/views/methodlist/template.phptal
<body onload="prettyPrint()">
    <div class="container">
         <div class="hero-unit">
         <h1 id="applypos" tal:content="title" >title here</h1>
         </div>
         <div class="alert alert-error" tal:condition="exists:
error_message" tal:content="error_message" >error message sample</div>

<p tal:replace="structure html_form" >Form</p>
<div class="row" metal:define-slot="content" >
    contents here
</div>
         <footer>
             <p class="pull-right"><a href="http://fuel.php-web.net/"
>http://fuel.php-web.net/</a> is programmed by <a href="http://php-web.
net/">PHPでWEB作成</a></p>
             <p>
                  <a href="http://fuelphp.com">FuelPHP</a> is released
under the MIT license.<br />
             </p>
         </footer>
    </div>

</body>
</html>
PHPTAL の特徴 2

● ビュー変数の出力をデフォルトエスケープ
  ○ FuelPHP もデフォルトエスケープする


● FuelPHP のエスケープを無効にする方法
    'auto_filter_output' => false,

● HTML 属性をクォートしないとエラー
  ○ エラー例: <div class=menu>メニュー</div>
PHPTAL の特徴 3

● 継承できる (ただし、ややこしい)

● 親 template.phptal
<html metal:define-macro="template">
<div metal:define-slot="content">

● 子 index.phptal
<html metal:use-macro="template.phptal/template"
>
<div metal:fill-slot="content">
PHPTAL のデメリット

● パフォーマンス
 ○ smarty より遅いらしい http://d.hatena.ne.
   jp/tanakahisateru/20100906/1283766620


● テンプレート HTML が厳密
 ○ 例えば、</p> 無しだとエラー


● 日本語の情報が少ない
CSRF とは

● Cross Site Request Forgery

● 取り消しできない重要な処理を実行させる
  ○ by 「安全な Web アプリケーションの作り方」 (徳丸浩)


● 被害者自身の操作で意図しないHTTPリクエスト
  を送信させる攻撃
  ○ by 「PHP逆引き516の大全」(大家正登, 鮫島康浩, 谷
    中志織, 茂木健一)
CSRF 対策

● 重要な処理の直前の画面でトークン発行
 ○ $form->add(Config::get('security.
   csrf_token_key'),'token',array
   ('type'=>'hidden','value'=>Security::
   fetch_token())) ;
 ○ $form->add_csrf(); (Form のみ?)


● 重要な処理実行時にチェック
  ○ クッキー(*)の値と照合する
 ○ Security::check_token()


* FuelPHP では(デフォルトでは)クッキーを使用
トークンを発行する箇所



   入力画面       実行


  トークン発行      チェック
トークンを発行する箇所



   入力画面            実行


  トークン発行          チェック


           罠ページ   正規のトークンが
                  無いので処理を
                  実行しない
トークンを発行する箇所



入力画面   確認画面      実行



                チェック



  確認画面がある場合はどうなるか?
トークンを発行する箇所



入力画面    確認画面      実行



       トークン発行    チェック


     確認画面がある場合
  重要な処理実行の直前 = 確認画面
XSS とは

● クロスサイトスクリプティング

● 外部からの入力などに応じて表示が変化する
  箇所があり、この部分のHTML生成の実装に問
  題がある
 ○ by 「安全な Web アプリケーションの作り方」 (徳丸浩)


● 2つ以上のサイトをまたがって、脆弱なサイトに
  悪意のあるスクリプトを混入させる
 ○ by 「PHP逆引き516の大全」(大家正登, 鮫島康浩, 谷
   中志織, 茂木健一)
XSS 対策

● 出力 HTML をエスケープする
  ○ FuelPHP/PHPTAL はデフォルトエスケープ
    ■ エスケープ漏れが生じにくい


● HTML 属性値をクォートする
  ○ PHPTAL は、クォート無しをハネる
    ■ ミスによる脆弱性が防げる
バリデーション

● 入力値の間違いを早期に発見して再入力を促
  すことにより、ユーザビリティを向上する
 ○ by 「安全な Web アプリケーションの作り方」 (徳丸浩)


● 間違った処理を継続することによるデータの不
  整合などを防ぎ、システムの信頼性を向上させ
  る
 ○ by 「安全な Web アプリケーションの作り方」 (徳丸浩)
バリデーション

● add_rule で追加していく
$form->add('classname','クラス名')
      ->add_rule('trim')
      ->add_rule('valid_string',array
('alpha','dashes'))
      ->add_rule('required')
      ->add_rule('max_length',30)
      ;

php の関数(trim 等)も使用できる
valid_string はややこしい&ハマりやすい
バリデーション

 $val = $form->validation();
 if ($val->run())
 {
    検証を通過した場合
 }
 else
 {
    検証に失敗した場合
 }
reflection
● クラスや関数等の情報を表示する
  ○   メソッド、プロパティの情報取得
  ○   コメントの取得
  ○   クラス/関数が定義されているファイル名、行数の取得
  ○   protected/private メソッド実行


● PHP の機能
  ○ ReflectionClass が用意されている
  ○ FuelPHP 以外でも利用可能
Reflection クラスのメソッド

getFileName()
getStartLine()
getEndLine()
getMethods()

詳細は PHP マニュアル参照
http://www.php.net/manual/ja/book.reflection.php
クラスのソースコードの表示

getFileName() でファイル名を取得
そのファイルを読み込む
getStartLine(), getEndLine() で範囲をチェック
getMethods() でメソッド一覧を取得
ユニットテスト

● 個々のメソッドのテスト
 ○ メソッドの返り値のチェック等


● テストケースを残す
 ○ 繰り返し実行可能
ユニットテスト

● FuelPHP では、PHPUnit を利用する

● oil から実行可能
  ○ php oil test
  ○ php oil test --group=App
  ○ php oil test --group=Core
FuelPHP をインストールしたルートで実行する
ユニットテストを書く

● app/tests フォルダに置く

● @group App アノテーションを書く

/**
 *
 * @group App
 */
class Test_SourceView extends TestCase
assertEquals で値が等しいかチェック
function test_sourceview()
{
   $classname = 'Date';
   $expected = 'クラス名:'.$classname;
   $data = Controller_Methodlist::_sourceview($classname);
   $title = $data->title;
   $this->assertEquals($expected,$title);
}
例外のテスト(アノテーションをつける)
/**
 * @expectedException InvalidArgumentException
 **/
function test_sourceview_argument_null_raises_exception()
{
    $data = Controller_Methodlist::_sourceview('');
}
ユニットテスト

● カバレッジ(*)も確認できる
 ○ php oil test --group=App --coverage-html ./report/
 ○ xdebug の設定が必要


* コードのうち、どれくらいがテストされているか
 = テストされている部分/コード全体
テスト通過 : 緑、 未テスト : 橙
今後の予定

● 開催日時・頻度
 ○ 平日夜で良いか?
 ○ 定期開催するか?頻度は?


● 考えているネタ
 ○ 効率的なWebアプリケーションの作り方
 ○ Novius OS http://www.novius-os.org/

FuelPHP Osu Nagoya vol.1