• [Zend Framework] Zend_Logでログのローテーション

    前回は簡単な使い方を書きましたが、今回は拡張する人用の情報を書きます。 クラスの構成 こんな感じになっています ┌─────────────------------------─┐ ┌────------------------------──────────-─┐┌─---------------────────┐ │ Wads_Log_RotationFile_Abstract │◇┬→│ Wads_Log_RotationFile_Writer_Interface ││Zend_Log_Writer_Abstract│ └───────-------------------──────┘ │ ├───────------------------------─────────┤└──-------------─────────┘ ▲ │ │ + update() │ ▲ │ │ └─────────────---------------------──────┘ │ ┌────────-----------───┐ │ △ │ │Wads_Log_RotationFile │ │ ├─────────────────────────────────┘ └─-----------──────────┘ │ ┌────────────────────────────┐ │ │Wads_Log_Writer_RotationFile│ │ ├────────────────────────────┤ │ │ + update() │ │ └────────────────────────────┘ │ ┌──────────────────────────────────────┐ └→│Wads_Log_RotationFile_Policy_Abstract │ ├──────────────────────────────────────┤ │ + trigger() │ │ + rollOver() │ └──────────────────────────────────────┘ ▲ ┌────────────────────┴───────────────────┐ ┌──────────────────────────────────────┐┌──────────────────────────────────┐ │Wads_Log_RotationFile_Policy_Datetime ││Wads_Log_RotationFile_Policy_Size │ ├──────────────────────────────────────┤├──────────────────────────────────┤ │ + trigger() ││ + trigger() │ │ + rollOver() ││ + rollOver() │ └──────────────────────────────────────┘└──────────────────────────────────┘ デザインパターンでいうと、ObserverとAdapterパターンあたりを意識しています。 PHPによるデザインパターン入門の本が役に立ちました。コンポーネントは、大きく分けると、
  • [Zend Framework]Zend_Logでログのローテーション

    勉強会で話したZend_Logを拡張してログのローテーションをできるようにしたものです。 log4jやlog4phpを参考にしながら、基本的な機能の部分をZend_Logに合わせて作りました。 前回の記事でも書きましたが、logrotateなどを使用してサーバー側でローテーションできないような場合(junichiroさんがコメントで仰っているようにレンタルサーバーなど)に、使用するといいかもしれません。 ソースはこちら 特徴 特定の期間やログのサイズをもとにローテーションを行うことができる ローテーションの方法を自由に拡張できる Zend_Logを使っていれば、writerを変更するだけで設定ができる 構成 Wads/ Log/ Writer/ RotationFile.php RotationFile/ Writer/ Interface.php Policy/ Abstract.php Datetime.php Size.php RotationFile.php Wads_Log_Writer_RotationFile クラスが、既存のZend_Log_Writer を拡張してローテーションに対応させたものです。これに、Wads_Log_RotationFile というローテーションを行うクラスを設定して使用します。 また、Wads/Log/RotationFile/Policy 以下にあるクラスでどのようにローテーションを行うか決めています。 現在は、ログファイルのサイズでローテーションを行うWads_Log_RotationFile_Policy_Sizeと、日付や時間、曜日でローテーションを行うWads_Log_RotationFile_Policy_Datetime の2つを用意しています。 使用方法 Wads_Log_RotationFileクラスのオブジェクトを生成する 1で生成したオブジェクト指定してWads_Log_Writer_RotationFileのオブジェクトを生成する Wads_Log_Writer_RotationFileのオブジェクトをZend_Logに追加する Zend_Logのlog()関数などを使ってログを書き出す 3以降は通常のZend_Logの使い方と同じです。 使用例です。 // ログファイル名 $logfile = "/var/log/foo/test.log"; // ローテーション方法指定 $opt = array( 'policy' => 'size', // Wads\_Log\_RotationFile\_Policy\_Size使用する 'backupindex' => 3, 'size' => 40 ); // 1(上の■ 使用方法 の番号) $lotation = new Wads\_Log\_Rotation($logfile, $opt); // 2 ('a' は fopen の mode) $writer = new Wads\_Log\_Writer\_RotationFile($logfile, 'a', $lotation); // 3 $log = new Zend\_Log(); $log->addWriter($writer); /\* .
  • [勉強会] ZendFramework勉強会@Tokyo で話してきました

    ちょっと遅くなってしまいましたが、4/4に開催されたZendFramework勉強会@TokyoのLTで話してきました。 準備不足もさることながら、半分くらいで制限時間が来てしまうなど非常にグダグダでしたので、出席された皆さんには申し訳ないと思っています。 発表資料はこちらにおいておきます。firefoxで見てください。 いくつか勉強会報告の記事を読んでいたら、junichiroさんのブログでこんな意見がありました。 ブログが続かないわけ Zend\_Log にローテーションの機能をつけようという話。 僕の個人的な感想としては、疑問符がつくないようだったが、(略) (略) logrotate と比較して、ZendFramework で実装することのメリットを提示して もらえたら、より面白かったと思う。 まず、作った経緯ですが、 権限的にlogrotateの設定ができない状態だったので、アプリ側でやる必要があった log4phpとでもよかったが、Zend Frameworkの(拡張も含む)で完結させたかった Zend Frameworkでも作っている気配が無かったので作ってみた という感じです。わりと無駄なものを作るのが好きなきらいがあります。 メリットとしては ZFが使える環境ならどこでもログのローテーションできる 時間やサイズ以外でも、任意のタイミング、方法でローテーションができるように拡張可能 という感じでしょうか。あまりいい答えではないですね。。。 実際自分も、常にアプリ側でローテーションを行なっているかというとそうではなく、むしろlogrotateを使ってやっているケースのほうが多いです。 選択肢の一つとしてZend Frameworkのコンポーネントにあってもいいんじゃないかな、と思っているのが実際のところです。 先ほどのjunichiroさんのブログを見ると、一応よい好評もあったようなので、ほっとしています。 調子に乗ってプロポーサルしてみようかな、なんて思っています。 ソースはgithabにおきました。 ほかのものもおいてありますが、完全に自分用なのであまり使えないかもしれません。 使い方や拡張方法は次のエントリーで書いてみようと思っています。
  • [Zend Framework] Zend_Filter_InputをZend_Controllerで使ったときのメモ

    Zend Frameworkを使って、MVCフレームワークで開発しているとき、Zend_Filter_Inputを使ってフォームで入力された値のフィルタリングを行う処理を記述した時のメモ。 以下のようなフォームで、入力された値についてチェックをかける場合。``` 登録する情報を入力 ユーザー名: パスワード: パスワードの確認: ユーザ名は半角英数字、5文字以上10文字以下 パスワードは半角英数字、5文字以上10文字以下 ```普通にZend\_Filter\_Inputを使ってフィルタリング処理をアクションメソッドに書くと以下のようなになります。``` class RegisterController extends Zend\_Controller\_Action { .... public function confirmAction() { $validate = array( 'id' => array( 'Alnum' array('StringLength', 5, 10), 'presence' => 'required', 'message' => array( 0 => ... // Alnumに対するエラーメッセージ 1 => ... // StringLengthに対するエラーメッセージ ) ), 'password1' => array( 'Alnum' array('StringLength', 5, 10), 'presence' => 'required', 'message' => array( 0 => ... // Alnumに対するエラーメッセージ 1 => ... // StringLengthに対するエラーメッセージ ) ), 'password2' => array( 'Alnum' array('StringLength', 5, 10), 'presence' => 'required', 'message' => array( 0 => .
  • [Zend Framework]Zend_Domを使ってみた

    Zend Framework 1.6から追加されたZend_Domを使ってみました。 XPathだけではなく、CSSセレクタによるDOMドキュメントの問い合わせを行うことができます。 以下のような感じでドキュメントを読み込ませてみました。``` require_once ‘Zend/Dom/Query.php’; $str =< « EOD title item 1 item 2 EOD; $zend_dom = new Zend_Dom_Query($str); echo “Document Type is “; echo $zend_dom->getDocumentType() . “\n”; echo “Document is \n”; echo $zend_dom->getDocument() . “\n”; 結果は以下のとおりです。 Document Type is docHtml Document is title item 1 item 2 getDocumentType()でドキュメントのタイプが取得できます。 ドキュメントのタイプは、Xml、html、xhtmlの3タイプで判別されます。判別の方法は以下のようになっています。 public function setDocument($document) { if (‘< ?xml’ == substr(trim($document), 0, 5)) { return $this->setDocumentXml($document); } if (strstr($document, ‘DTD XHTML’)) { return $this->setDocumentXhtml($document); } return $this->setDocumentHtml($document); }
  • [Zend Framework][php] Zend_Feedを使ってWebページのフィードを生成する

    Zend_Feedを仕様すると、WebページのフィードをRSS形式とAtom形式で簡単に作ることができます。 まずは配列形式でフィードデータを生成します。 $feed\_data = array( 'title' => 'wadsのblog', 'link' => 'http://wadslab.net/feed/', 'published' => time(), 'charset' => 'UTF-8', 'description' => 'wadsのblogです', 'author' => 'wads', 'entries' => array( array( 'title' => '\[git\] Subversionからgitへ移行する', 'link' => 'http://wadslab.net/2008/07/subversion-git/', 'description' => 'ソースコードなどを管理するリポジトリを...', 'guid' => 'http://wadslab.net/2008/07/subversion-git/', 'lastUpdate' => strtotime('2008-07-17 23:34:45'), ), array( ... ) .... ) ); 上のフィードのデータは結構省略しています。ちゃんとした配列の構造はリファレンスマニュアルをご覧ください。 続いて、この配列をZend_Feed::importArray()を使って読み込み、出力をすれば完了です。また、imprtArray()は第二引数で、フィードの形式を選択できます(Atom形式か、RSS形式か)。 全体的には以下のような流れになります。 class FeedController extends Zend\_Controller\_Action { public function preDispatch() { // viewRendererは切っておく $this->getFrontController()->setParam('noViewRenderer', true); } public function indexAction() { $format = $this->getRequest()->getParam('format', 'atom'); $feed\_data = array( .
  • [Zend Framework] Zend_Httpを使ってAPIからファイルをアップロードする

    Zend_Httpを使ってAPIからファイルをアップロードするプログラムを作ってみました。 http://example.com/api/file_post というAPIがあって、これを使ってファイルをアップロードすると仮定しています。 コードは以下のようになっています。``` require_once ‘Zend/Http/Client.php’; $url = “http://example.com/api/file_post”; $filename = “example.jpg”; $client = new Zend_Http_Client($url); // オプションの設定は省略 $client->setFileUpload($filename, ‘file’, null, ‘image/jpeg’); $response = $client->request(‘POST’); これだけで完了です。通常のフォームからのアップロードと同様に、サーバのスクリプトから$\_FILES\['file'\] で参照することができます。 Zend\_Http\_ClientのsetFileUpload()関数でアップロードするファイルを設定して、request()関数でHTTPリクエストをかけます。 リファレンスガイドではsubmit()関数を使っていたのですが、そのような関数は定義されていなかったので代わりにrequest()関数を使用しています。 続いて、setFileUpload()関数の引き数について説明します。 最初の引数では、アップロードするファイル名を指定します。ただし、この引数は第3引数の値で内容が変わってきます。 第3引数がnullの場合は、ここで指定されたファイルが実際にアップロードされます。もしnullでない場合はアップロードするときのファイル名としてこの値が使われるだけで、ファイルの内容は第3引数のものが使用されます。 $filename = “text.txt”; $text = “this is upload test”; $client->setFileUpload($filename, ‘file’, $text, ‘text/plain’); $response = $client->request(‘POST’); この場合、たとえローカルに別の内容でtext.txtというファイルが存在していても、「this is upload test」という内容で送信されます。 2番目の引数ではフォーム名を指定します。 のxxxにあたる部分ですね。 サーバスクリプト側では $_FILES[‘file’]
  • [Zend Framework] [php]独自のZend_Viewのビューヘルパーの作り方②

    前回で独自のビューヘルパークラスを作る方法がわかったので、今回は実際に作ることにします。 作るヘルパーの内容は、自分も普段よく使っているもので、出力しようとする文字列の長さが指定したものより長い場合に、指定した長さで文字列を切り取って表示する処理を行うものです。 たとえば、「あいうえおかきくけこさしすせそ」という入力があり、最大の文字列長を10文字と指定した場合には、「あいうえおかきくけこ…」として出力されるような処理です。名前はstrcutとしておきます。 ヘルパーはビュースクリプトで以下のように使います。``` < ?php echo $this->strcut($this->text, 10) ?> 早速作ってみます。 strcut.phpというファイルに以下のようにクラスを定義します。 < ?php class Wads_View_Helper_Strcut { public function strcut($str, $len, $omit=’…') { if(!is_string($str)) { $str = (string)$str; } $str = htmlspecialchars($str, ENT\_QUOTES); if((int)$len > 0 && mb\_strlen($str) > (int)$len) { $str = mb\_substr($str, 0, $len-1); if(is\_string($omit) && $omit != "") { $str .= htmlspecialchars((string)$omit, ENT\_QUOTES); } } return $str; } } クラス名のプレフィックスとしてWads\_View\_Helperをつけました。ヘルパーと同じ名前のpublic関数を定義して、この関数内ではechoなどで出力せず、切り取った文字をエスケープして返しています。これで[前回書いたビューヘルパーを作るためのルール](http://wadslab.net/2008/07/zend_view/)すべてをみたしたことになります。 ビューヘルパーの第1引数には出力する文字を、第2引数には切り取る文字列の長さを、第3引数にはもし文字列を切り取った場合に、最後に付加する省略をあらわす文字列を指定します。第3引数は省略できます。 あとはこのファイルがあるディレクトリをスクリプトパスに追加するだけです。たとえば、コントローラ内で $this->view->setHelperPath('/path/to/helpers’, ‘Wads_View_Helper’); のようにセットできます。 以上で最初に書いたように、ビュースクリプト内で < ?
  • [Zend Framework][php] 独自のZend_Viewのビューヘルパーの作り方①

    独自のZend_Viewのビューヘルパーはいくつかのルールをみたせば簡単に作ることができます。 ヘルパー名とビューヘルパーのクラス名の最後の部分は同じにする(ただしMixedCaps方式) ビューヘルパーのクラスにはヘルパー名と同じ名前のpublicメソッドが定義されている メソッド内ではechoとかprintを行ってはいけない。printやechoされる内容をエスケープして返す クラスはヘルパーと同じ名前のファイルに作成する fooというヘルパーを作ると仮定して、上記についてひとつずつ説明します。 1. ヘルパー名とビューヘルパーのクラス名の最後の部分は同じにする fooというヘルパーを作る場合、クラス名の最後にはFooという名前がないといけません。また、クラス名には「_(アンダースコア)」区切りでプレフィックスをつけることができます。というわけで、クラス名の最後にという表現になっています。``` class Foo class My_Foo class My_View_Helper_Foo はどれもクラス名としてOKです。2番目の例だとMyが、3番目の例だとMy\_View\_Helperがプレフィックスになります。 ただし、プレフィックスにはView\_Helperを含めることが推奨されているので、2番目よりも3番目の名前のほうがいいです。 **2\. ビューヘルパーのクラスにはヘルパー名と同じ名前のpublicメソッドが定義されている** つまりこういうことです class My_View_Helper_Foo { … public function foo($input) { … } … } **3\. メソッド内ではechoとかprintを行ってはいけない。printやechoされる内容をエスケープして返す** ビューヘルパー内で出力するのではなく、ビュースクリプトにて < ?php echo $this->foo($this->name); ?> のように出力するようにします。クラスのメソッド内では、エスケープ済みの結果を返すようにするだけです。 class My_View_Helper_Foo { … public function foo($input) { … return htmlspacealchars($output) } … } **4\. クラスはヘルパーと同じ名前のファイルに作成する** 今回の場合は、Foo.phpというファイルにクラスを定義します。 以上の条件をみたしていれば、ビューヘルパーのパスのどこかにファイルを置いておくだけで自動的に読み込み、インスタンス化してくれます。ビューヘルパーのパスを追加するには、Zend\_ViewクラスのsetHelperPath()を使います。 $view = new Zend_View(); $view->setHelperPath('/path/to/helpers’, ‘My_View_Helper’); ?> パスは既存のパスにスタックのように積み重ねられていきます。つまり後から追加されたパスが先に検索されることになります。 setHelperPath()の第2引数ではビューヘルパーのプレフィックスを指定できます(最後の_は省略可です)。もし指定しない場合はデフォルトで’Zend_View_Helper_‘がプレフィックスとなります。