Posts tagged action

WordPress API フックの使い方

2

API フックとは

プラグインやテーマの動作を WordPress 本体に連動させることができます。WordPress 本体に修正を加えなくてもカスタマイズできます。

アクションとフィルタ

API フックにはアクションとフィルタがあります。アクションは WordPress で発生するイベントによって実行されます。イベントは投稿やテンプレートの変更などユーザが行う行動です。フィルタはテーマなどで出力するテキストデータを変更するものです。
(続きを読む…)

iモードID の仕様

1

iモードID の仕様が公開されました。

作ろうiモードコンテンツ:iモードセンタの各種情報 | サービス・機能 | NTTドコモ

リンクに ?guid=ON という引数をつけないとダメらしいです。
(続きを読む…)

CakePHP1.2 のバリデーション

12

CakePHP 1.2 を使用してフォームを作成してバリデーションを使用したメモです。

下記サイトを参考にさせていただきました。
cakePHP 1.2のバリデーションを理解する – cakephp – クロアチアで働くプログラマー日記

例としてメールアドレスを2回入力させるフォームを考えて見ます。
バリデーションルールとして

  • 必須項目
  • メールアドレスとして正しい
  • メールアドレスがユニーク
  • 2回入力したメールアドレスが一致する

モデルにバリデーションを定義する

var $validate = array(
    'email' => array(
        'unique' => array(
    	    'rule' => array('checkUnique', 'email'),
    	    'message' => 'メールアドレスは既に登録されています'
    	),
        'rule1' => array(
       	    'rule' => array('email'),
       	    'message'=>'メールアドレスが正しくありません'
      	 ),
        'required' => array(
       	    'rule'=>VALID_NOT_EMPTY ,
       	    'message' => '必須項目です'
       	),
    ),
    'email_confirm' => array(
        'rule1' => array(
    	    'rule'=> array('checkCompare'),
    	    'message'=>'一致しません'
    	),
    ),
);

私はエラーメッセージをバリデーション定義にまとめておきたいので、上記のように各ルールに
'message' => 'エラーメッセージ'
として定義しています。
ここで定義しておけば、後でビューに書くフォームヘルパーでフォームを出力するときに引っかかったエラーを自動的に出力することができます。

また、自分でバリデーション関数を作成してチェックすることもできます。それが checkUnique と checkCompare です。

メールのユニークチェックは参考サイトを参考にさせていただきました。

function checkUnique($field){
    foreach( $field as $key => $value ){
        $this->recursive = -1;
        $found = $this->find(array("{$this->name}.$key" => $value));
        return !$found;
    }
}

次にメールアドレスを2回入れたものが一致するかのチェックです。
これはパスワードなどでもたまに使用するので汎用性を持たせてあります。
例えばメールアドレスのフィールド名が email の場合、確認用のフィールド名は ‘_confirm’を付けて email_confirm としておけばこの2つが一致するかチェックします。

function checkCompare($field) {
    foreach( $field as $key => $value ){
        if (preg_match('/^(.+)_confirm$/', $key, $regs)) {
            return $this->data[$this->name][$regs[1]] == $this->data[$this->name][$key];
        }
    }
}

ビューでフォームを設定

<?php echo $form->input('User/email', array('type'=>'text')); ?>
<?php echo $form->input('User/email_confirm', array('type'=>'text')); ?>

このように書いておけばバリデーションエラーがある場合は、モデルのバリデーションに定義したエラーメッセージを自動的に出力してくれます。

ちなみに上記のように書くと input タグの前に email などのフィールド名が出力されます。これを消したい場合は
<?php echo $form->input('User/email', array('type'=>'text', 'label'=>'')); ?>
と書くと表示されなくなります。

追記:
コメントで教えていただきました。label=>” だと表示されないが、label タグは残るので
<?php echo $form->input('User/email', array('type'=>'text', 'label'=>false)); ?>
とするとラベルタグも出力されなくなります。

コントローラでバリデーションチェック

以下のようになります。

function action() {
    if ($this->data) {
        if ($this->User->create($this->data) && $this->User->validates()) {
	    // バリデーションOK
	}
    }
}

他にもいろいろフォーム気がついた点があったのでそれはまた後でまとめます。

CakePHP Ajax のフォームを作成する

5

今さらなのですが CakePHP1.1 で Ajax のフォームを作成するというのをやったのでメモしておきます。

Ajax , Javascript ヘルパーを使用できるようにする

コントローラで Ajax, Javascritp ヘルパーを使用できるようにする。
var $helpers = array('Ajax', 'Javascript');

prototype.js を読み込む

webroot/js に prototype.js を配置し、ビューで読み込みます。
<?php echo $javascript->link('prototype'); ?>

ビューでフォームを作成する

今回は submit ボタンを押した後、更新中には submit ボタンを消して変わりに「更新中」というメッセージを表示し、更新終了後にメッセージをボタンの下の id=ajax_message に表示するようにしました。

<?php
$options = array(
    "update" => "ajax_message",
    "loading" => "Element.hide('ajax_button'); Element.show('ajax_loading');",
    "complete" => "Element.show('ajax_button'); Element.hide('ajax_loading');",
    );
echo $ajax->form("/controller/action/", "post", $options);
?>
<?php echo $html->input('Model/Field', array('type'=>'text')); ?><br>
<input type="submit" id="ajax_button">
<div id="ajax_loading" style="display:none;">更新中...</div>
<div id="ajax_message"></div>

$ajax->form の $options の
“update” で更新するメッセージ領域を指定し、
“loading”でアップロード中の動き、
“complete” で処理終了後の動き
を指定しています。

コントローラに Ajax で処理するアクションを作成

function action() {
    $this->layout = 'ajax';
    /* $this->data にフォームの内容が渡るので必要な処理を書く */
    $this->Model->id = $this->data['Model']['id'];
    $this->Model->saveField("Field", $this->data['Model']['Field'], true);
}

$this->layout で ‘ajax’ を指定して余計なヘッダ、フッタが出ないようにします。

Ajax で出力するビューを作成する

上のコントローラのアクションで出力するビューを作成します。
上の例では saveField でフォームから送られてきたデータを使用して更新処理しています。その結果によってメッセージを送信します。

<?php
if($msg=$error->messageFor('Model/Field')) {
    echo $msg;
} else {
    echo "更新しました";
}
?>

CakePHP1.2 バッチ処理

2

CakePHP1.2 にシェル機能というのがあるのを知りました。下記エントリでメールからの処理を実際に行う方法が紹介されています。
メール受信からのシェル機能実行 – Writing Some Code

ちょうど CakePHP1.2で開発中のシステムで cron でのバッチ処理があるのでそれに応用してみたときのメモです。

バッチ処理で実行させるシェル機能を作成

今回は test という名前のシェル名にします。
app/vendors/shells/test.php を作成します。

< ?php
class TestShell extends Shell {

    var $uses = array('Model');

    function actionName(){
        /* 実際の処理を書きます */
        /* $this->uses に追加したモデルが使用できます */
        $lists = $this->Model->findAll();
    }
}
?>

シェルスクリプト

下記のようなシェルスクリプトを作成して cron から実行させます。

#!/bin/sh
cd /path/to/app
../cake/console/cake test actionName

シェルスクリプトなしで直接 cake を実行する方法もある

cake を実行するときにカレントディレクトリが app でないとだめなのですが、
-app /path/to/app
のように -app オプションで実行時に app のパスを指定することもできます。
その場合は下記のようになります。
/path/to/cake/console/cake test actionName -app /path/to/app
これを直接 cron から実行させればシェルスクリプトなしでも実行できます。

その他

vendors/shells 内のファイルですが、ファイル名が hoge_foo.php だった場合、クラス名は HogeFooShell ですが、実行するときは
cake/console/cake hoge_foo actionName
となるようです。

CakePHP 1.2 の saveAll その2

3

CakePHP 1.2 の saveAll その1 では同一モデルへの複数レコードを saveAll で保存しました。今回はアソシエーションのモデルのデータを saveAll で保存する方法です。

アソシエーションのモデルのデータを保存

モデル
user.php

< ?php
class User extends AppModel {
    var $name = 'User';
    var $hasMany = array('Comment');
}
?>

comment.php

< ?php
class Comment extends AppModel {
    var $name = 'Comment';
    var $belongsTo = array('User');
}
?>

コントローラ
users_controller.php

function add() {
    if (!empty($this->data)) {
        $this->cleanUpFields();
        $this->User->create();
        if ($this->User->saveAll($this->data)===false) {
            $this->Session->setFlash('保存に失敗しました);
        } else {
            $this->Session->setFlash('保存しました');
        }
        $this->redirect(array('action'=>'index'), null, true);
    }
}

ビュー
users/add.ctp

< ?php echo $form->create('User');?>
< ?php echo $form->input('User.name');?>
< ?php echo $form->input('Comment.body'); ?>
< ?php echo $form->end('Submit');?>

CakePHP 1.2 の saveAll その1 の同一モデルへの複数レコードの保存よりも使い道は多いのではないかと思います。

追記
このエントリーは CakePHP 1.2.0.6311 beta で検証しています。

CakePHP アクションでエレメントを出力する方法

2

Rendering elements from controllers – cakebaker

上記エントリでエレメントのみを出力する方法が紹介されています。

バージョン1.2 の場合

app/views/elements/controller/hoge.thtml のエレメントを出力する場合
$this->render(DS.'elements'.DS.'controller'.DS.'hoge');

バージョン1.1 の場合

app/views/elements/controller/hoge.thtml のエレメントを出力する場合
$this->render(null, null, ELEMENTS.'controller'.DS.'hoge.thtml');

注意点

レイアウトは指定しないと default になります。Ajax などでエレメントのみを出力したい場合はレイアウトに ‘ajax’ を指定してhead タグや body タグが出力されないようにする必要があります。

v1.2$this->render(DS.'elements'.DS.'controller'.DS.'hoge', 'ajax');
v1.1$this->render(null, 'ajax', ELEMENTS."controller".DS."hoge.thtml");

CakePHP JQuery ヘルパー

3

JQuery helper for CakePHP ( PQuery port ) at NGCoders
CakePHP から JQuery を簡単に使うことができます。

正確には PQuery ヘルパーかもしれません。PQuery は JQuery を PHP から簡単に使用するライブラリで PQuery ヘルパーと同じ開発者が開発しています。
参考:PQuery – PHP and JQuery at NGCoders

インストール

JQuery helper for CakePHP ( PQuery port ) at NGCoders から JQuery ヘルパーをダウンロードし、解凍した pquery.php を /app/views/helpers にコピーします。
そのほかに jquery.js ファイルも必要になります。こちらもダウンロードして /app/webroot/js にコピーします。

コントローラ

Pquery ヘルパーと Javascritp ヘルパーを使用します
var $helpers = array('Pquery', 'Javascript');

ビュー

jquery.js の読み込み
<?php echo $javascript->link('jquery.js'); ?>

使用例

トグルボタン

<div id='msg'>Message...</div>
<?php echo $pquery->link_to_function('toggle', $pquery->toggle('#msg'));?>

フォームで送信された内容により HTML を更新
入力したテキストを /controller/action/ に GET で送信し、id=idtoupdate に受け取った HTML を表示する

<?php echo $pquery->form_remote_tag(array('url'=>'/controller/action/','update'=>'#idtoupdate'));?>
<input type='text' name='field' />
<input type='submit' />

<div id='idtoupdate'></div>

pquery.php を見ると色々なメソッドがあります。使い方はソースを見ればすぐに分かると思います。

HTTP_Request を使用してファイルをアップロードする方法

1

PEAR の HTTP_Request を使用してファイルをアップロードする方法です。

<form action='POST_URL' method='post' enctype='multipart/form-data'>
<input type='text' name='title'>
<textarea name='body'></textarea>
<input type='file' name='upload_file'>
<input type='submit'>
</form>

上記のような HTML でファイルをアップロードする場合と同じような処理をするには、下記のように HTTP_Request を使用します。

// POST パラメータ
$post_data = array(
    'title' => $title,
    'body'  => $body,
);
// アップロードパラメータ
$upload_file = array(
    'name' => 'file',
    'path' => '/path/to/file',
);
// アップロード
$rs = http_send(POST_URL, $post_data, $upload_file);

function http_send($url, $params, $upload_file=null) {
    $req = new HTTP_Request();
    $req->setMethod(HTTP_REQUEST_METHOD_POST);

    foreach ($params as $key => $val) {
        $req->addPostData($key, $val);
    }

    $req->setURL($url);
    if ($upload_file) {
        $res = $req->addFile($upload_file["name"], $upload_file["path"]);
        if (PEAR::isError($res)) {
            echo $res->getMessage();
            exit;
        }
    }

    if (!PEAR::isError($req->sendRequest())) {
        return $req->getResponseBody();
    } else {
    	return false;
    }
}

参考:PEAR :: Manual :: ファイルアップロード

CakePHP Security コンポーネントのまとめ

1

CakePHP の Security コンポーネント の動作を調べたのでまとめておきます。
この Security コンポーネントをうまく使用すればクロスサイトリクエストフォージェリ(CSRF) を防ぐことができるでしょう。

トークンの使用

フォームにワンタイムトークンを実装する方法です。

コントローラの beforeFilter メソッドでトークンをチェックするアクションを指定
function beforeFilter() {
    $this->Security->requireAuth('login');
}
ビューのフォーム内にトークンを設定

<?php echo $html->formTag(); ?>
トークンが hidden 属性で生成される

トークンが一致しない場合

requireAuth で指定したアクションに POST でアクセスがあるとセションに保存したトークンとフォームから送られてきたトークンが一致するかチェックします。またそのほかにトークンの有効期間もチェックします。有効期間は CAKE_SECURITY の設定により違います。

CAKE_SECURITY 有効期間
high 10分
medium 100分
low 300分

トークンが一致しないと SecurityComponent の blackHole メソッドが実行されます。このメソッドでは
header('HTTP/1.0 404 Not Found');
を出力して exit します。(画面は空白)

任意の処理を実行したい場合は blackHoleCallback でコールバック関数を指定します。
設定できるのは同じコントローラ内のアクションのみになります。

function beforeFilter() {
    $this->Security->blackHoleCallback = "securityError";
    $this->Security->requireAuth('login');
}

function securityError() {
	die("security error!");
}
トークンチェックをするアクションを複数指定するときはカンマでつなげる

$this->requireAuth('login', 'delete');

特定のコントローラからのポストのみ許可する

$this->Security->allowedControllers = array("users");
これを指定するとたとえトークンが一致しても許可のないコントローラからのポストの場合は blackHole メソッドを実行します。

特定のアクションからのポストのみ許可する

$this->Security->allowedActions = array("action");
これを指定するとトークンが一致しても許可のないアクションからのポストの場合は blackHole メソッドを実行します。

ポストのみ受け付けるようにする

$this->requirePost('login');
これはトークンとは違い、POST のみ許可して GET でのアクセスを不可にします。
/users/login/ のような URL でのアクセスも GET なので不可になります。
POST の処理だけを実行したいようなアクションに使用します。

Go to Top