• Mac OS Xのphpにgettextをインストール

    Macに最初から入っているphpにgettextモジュールが入っていなかったのでインストール。 インストール・設定 まずはportsでインストール $ sudo port install php5-gettext php.iniの設定 下記をphp.iniに追加 extension=gettext.so apacheを再起動 # apachectl graceful しかしなぜかうまく設定できませんでした... インストールされたgettext.soの場所をしらべると、 $ find /opt -name gettext.so /opt/local/lib/php/extensions/no-debug-non-zts-20090626/gettext.so 一方phpinfo()の出力を見ると、extension_dirは以下の場所でした extension\_dir /usr/lib/php/extensions/no-debug-non-zts-20090626 ということで、以下のようにリンクを貼って解決 $ cd /usr/lib/php/extensions/no-debug-non-zts-20090626 # ln -sf /opt/local/lib/php/extensions/no-debug-non-zts-20090626/gettext.so . 再度、apacheを再起動して設定完了 # apachectl graceful
  • WordPressをMT(Movable Type)形式でエクスポートしてブログをお引越し。

    wordpressで書いていたブログを、はてなに引っ越すことにしました。 結局こっちへ戻ってきました 実際に引っ越しを行ったバージョンはwordpress2.6です。 インポート方法 はてなで既存ブログデータをインポートするには、Movable Type形式(MT形式)でデータをエクスポートする必要があります。 今使用しているwordpressのバージョンは2.6で、MT形式でデータをエクスポートするために、WordPressExportというプラグインを使用しました。 プラグインのインストール インストール方法などはこちらをご覧ください プラグインのインストール後、管理画面の「設定」タブから「Export」をクリックすると、MT形式でデータ表示されるはずでしたが、何も出てきませんでした。 プラグインの修正 調べてみると、MT.php内21行目付近の、SQLを発行している部分で、エラーがでていることがわかりました。 MT.phpの21行目付近 $query = "SELECT $wpdb->posts.post\_date, $wpdb->posts.post\_content, $wpdb->posts.post\_title, $wpdb->users.user\_nickname, $wpdb->posts.post\_status, $wpdb->comments.comment\_author, $wpdb->comments.comment\_content, $wpdb->comments.comment\_author\_email, $wpdb->comments.comment\_author\_url, $wpdb->comments.comment\_date, $wpdb->post2cat.category\_id, $wpdb->categories.cat\_name FROM $wpdb->comments RIGHT OUTER JOIN $wpdb->posts ON ( $wpdb->comments.comment\_post\_ID = $wpdb->posts.ID ) LEFT OUTER JOIN $wpdb->users ON ( $wpdb->posts.post\_author = $wpdb->users.ID ) LEFT OUTER JOIN $wpdb->post2cat ON ( $wpdb->posts.ID = $wpdb->post2cat.post\_id ) LEFT OUTER JOIN $wpdb->categories ON ($wpdb->post2cat.category\_id = $wpdb->categories.cat\_ID) "; また、エラーがでている部分はeval()関数で実行されていたので、特にエラーなど出現せず、単に出力がない状態となっていたのです。
  • [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_Auth][cookie]Zend_Auth_Storage_Interface を実装してcookieに対応

    cookieで認証情報を引き回したかったので作ってみました。まだまだ改良の余地がありますが、とりあえず公開してしまいます。 本来はZend_Http_Cookieをうまく使いたかったのですが、Zene_Http_ClientやZend_Http_CookieJarから使われるのが前提のようなつくりだったのでうまく使えませんでした。折を見て改良していこうと思います。 そのうちCodeReposのコミット権をもらったらそっちにアップしますが、それまではここにソースを貼り付けておきます。 ・2008/06/24 追記 クラス名にZend_というプリフィックスは使えないとご指摘をいただいたので修正しました。名前はここ風にブログの管理者名にしています。 ・08/07/04 追記 CodeReposにアップしました。 ・08/08/26 追記 指摘されたミスを修正しました。CodeReposのほうが最新ですのでそちらを参照ください。 ・08/10/05 追記 ライセンスを明記しました。Zend Frameworkと同じです。 バグの修正しました。 以上修正はCodeReposへ反映しました。 ↓以下のソースは最新ではありませんので注意! < ?php require\_once 'Zend/Auth/Storage/Interface.php'; class Wads\_Auth\_Storage\_Cookie implements Zend\_Auth\_Storage\_Interface { /\*\* \* Default cookie name \*/ const COOKIENAME\_DEFAULT = 'Wads\_Auth\_Cookie'; protected $\_name = ""; protected $\_value = ""; protected $\_expire = null; protected $\_path = "/"; protected $\_domain = ""; protected $\_secure = false; protected $\_httponly = false; public function \_\_construct($option = self::COOKIENAME\_DEFAULT) { if (is\_string($option)) { $this->setName($option); } else if (is\_array($option)) { $this->setCookieParams($option); } else if ($option instanceof Zend\_Config) { $this->setCookieParams($option); } else { $option = (string)$option; } } public function \_\_get($name) { $func = "get".
  • [php][interface] phpのインターフェース小ネタ

    今日インターフェースを実装するにあたり、実装する関数で引数にデフォルト値を設定できないかなーとか思いました。以下のような感じです。``` < ?php interface MyInterface { public function foo($val); } class ImplementedClass implements MyInterface { public function foo($vals = “default”) { if(!is_string($val)) { $val = (string)$val; } echo “$valn”; } } $i = new ImplementedClass(); $i->foo(); 結果 Fatal error: Declaration of ImplementedClass::foo() must be compatible with that of MyInterface::foo() in C:tmptest9. php on line 7
  • [php][Interface] PHPのイテレータインターフェース実装

    Zend Frameworkをみているとこのこの辺など結構使っているようなのでちょっと勉強してみました。 今回はイテレータについてです。イテレータとはwikipediaによれば、*「プログラミング言語において配列やそれに類似するデータ構造の各要素に対する繰返し処理の抽象化である」*とあります。 おそらく一つのクラスだけでイテレータを実装してもあまりいいことはなく、いろいろなクラスでイテレータを実装することで繰り返しの処理を統一化できて便利になるのだと思います。たとえばforeach文は最も良い例ではないかと思います。定義済みのIteratorインターフェースを実装することで、このクラスのオブジェクトはイテレータとなりforeach文で処理を繰り返し処理を行うことができるようになります。 Iteratorにはcurrent(), key(), next(), rewind(), *valid()*のメソッドのインターフェースが定義されているので、これをサブクラスで実装します。 各メソッドは以下のような処理を行います。 current() 現在の要素の値を返す key() 現在の要素のキーを返す next() 次の要素へ内部ポインタを移動する rewind() 内部ポインタを最初の要素へ戻す valid() next()やrewindのあとに呼ばれて、現在の要素が存在する場合にtrueを返す 試しに、偶数番目の要素のみを返す配列のイテレータを作ってみました。 < ?php class EvenArray implements Iterator { private $\_array = null; private $\_size = 0; private $\_pos = 0; public function \_\_construct($array) { if(!is\_array($array)) { $array = array($array); } $this->\_array = $array; $this->\_size = count($array); $this->\_pos = 0; } public function current() { if($this->\_pos > $this->\_size) { throw new Exception('Index is out of bounds'); } return $this->\_array\[$this->\_pos\]; } public function key() { if($this->\_pos > $this->\_size) { throw new Exception('Index is out of bounds'); } return (string)$this->\_pos; } public function next() { return $this->\_pos += 2; } public function rewind() { return $this->\_pos = 0; } public function valid() { return isset($this->\_array\[$this->\_pos\]); } } このクラスを生成して、foreachで以下のように繰り返しの処理を行うことができます。
  • [PHP] unserializeと__PHP_Incomplete_Class

    昨日のZend_Feed::import() でフィードを取得した結果をキャッシュ化するとデータがおかしくなる件の続きです。 まず、Zend_Feed::import()で直接取得したフィードとキャッシュから取得したものそれぞれをvar_dump()で比較してみました。 Zend_Feed::import()の場合は、 object(Zend\_Feed\_Atom)#3 (8) { ... キャッシュから取得した場合は、 object(\_\_PHP\_Incomplete\_Class)#3 (2) { ... となっていました。 __PHP_Incomplete_Classについて調べたところ、オブジェクト型の変数をunserialize()を実行する場合には、事前に必要なクラスが定義されていないと正しく非シリアル化できないとありました。 当初の予想通りシリアライズ関連のところでおかしくなっていたようです。 前回のフィードの取得および、キャッシュ化のところを見ると、unserialize()を実行しているところは、前回の例では$cache->load()の中なので、たしかに必要なクラス(今回はZend_Feed_Atom)が定義されていませんでした。 $cache = Zend\_Cache::factory('Core', 'File', $frontendOptions, $backendOptions); if(!$result = $cache->load('rss')) { try { $result = Zend\_Feed::import('http://wadslab.net/category/Zend\_Auth/atom/'); } catch (Zend\_Feed\_Exception $e) { // フィードの読み込みに失敗しました echo "フィードの読み込み中に例外が発生: {$e->getMessage()}n"; exit; } $cache->save($result); } 対策としては、事前に必要なクラスを定義しておくほかに、unserialize_callback_func ディレクティブを利用する方法もあります。 unserialize_callback_func ディレクティブによって設定された コールバック関数は、unserializeする際に未定義のクラスをインスタ ンス化する度に呼び出されるので、この関数内で必要なクラスを定義することで__PHP_Incomplete_Classの発生を防ぐことが出来ます。 設定の方法は以下のとおりです。 // my\_callback\_funcは任意 ini\_set('unserialize\_callback\_func', 'my\_callback\_func'); function my\_callback\_func($classname) { // $classname が必要なクラス名なので、これを定義します } クラス名=ファイル名.phpになっていれば以下のように定義すればいいです。 require\_once $classname.".php" 必要なクラスがZend Frameworkの場合には、 Zend\_Loader::loadClass($classname); とすればいいでしょう。 というわけで、今回はZend Frameworkはまったく関係ありませんでした。