平井です。
プログラミングネタを続けます。

村式では、EthnaというPHPフレームワークを利用することがあります。
私がEthnaを利用するときに残念に思っているのが、URLがきれいでないということです。

標準では、Ethnaで作成したアプリケーションへのリクエストは、下記のようなURLになります。

http://example.com/?action_login=1

これを、以下のURLのようにできないでしょうか。

http://example.com/login

後者の方が、人が見て直観的に理解可能だと思います。

ユーザーさんがWebを利用する上で、URLの形式がどうであろうがあまり問題にはならないでしょう。
が、細部にもこだわってきれいなものを作りたいというのがクリエイターの性というものです。

導入が長くなりましたが、Ethnaで「きれいなURL」を実現してみましたのでご紹介します。(PHP5限定です)
といっても、ほぼ他の方のエントリの引用になりますが。

まず、そもそもEthnaにはEthna_UrlHandlerというものがあって、Ethnaが扱うURLをカスタマイズできるようになっています。
ただ設定方法がなかなか難しく、習得していません。

一方、アプリケーションが取り扱うURLをカスタマイズするライブラリに、PEARのNet_URL_Mapperというものがあります。
こちらの設定方法は比較的容易でした。

そこで、EthnaのUrlHandlerを拡張し、内部でNet_URL_Mapperを使うことで「きれいなURL」を実現します。

EthnaでNet_URL_Mapperを使う

以下エントリーを参考にしてEthna_UrlHandlerクラスを拡張し、内部でNet_URL_Mapperを使います。

EthnaでNet_URL_Mapperを使う

拡張して作成したクラス内では、Net_URL_Mapperの設定方法が利用できます。
Net_URL_Mapperの設定方法は、以下のエントリーに詳しいです。

PEAR::Net_URL_MapperでURLルーティングを制御する

以下が作成したサンプルコードです。

< ?php
/**
 *  Hoge_UrlHandler.php
 */

require_once 'Net/Url/Mapper.php';

/**
 *  URLハンドラクラス
 *
 */
class Hoge_UrlHandler extends Ethna_UrlHandler
{
    /** @var array アクションマッピング */
    var $action_map = array(

      // エントリポイントでつける名前
      'index' => array(

        // ログイン
        ‘/login’ => array(
          ‘action’ => ‘login’,
        ),

        // ページ送り
        ‘/view/:category/:offset’ => array(
          ‘action’ => ‘view’,
          ‘category’ => ‘’,
          ‘offset’ => ‘’,
        ),
      ),
    );

    /**
     *  Hoge_UrlHandlerクラスのインスタンスを取得する
     */
    function &getInstance($class_name = null)
    {
        $instance =& parent::getInstance(__CLASS__);
        return $instance;
    }

    /**
     * Net_URL_MapperでURLリライティングに対応する
     *
     * @param array $http_vars
     * @link http://labs.cybozu.co.jp/blog/tsuruoka/anubis/blog_show/45
     * @return array
     */
    function requestToAction($http_vars)
    {
        if (isset($http_vars[’__url_handler__’]) == false
            || isset($this->action_map[$http_vars[’__url_handler__’]]) == false) {
            return array();
        }
        $url_handler = $http_vars[’__url_handler__’];
        $action_map = $this->action_map[$url_handler];
        // parameter fix
        $method = sprintf(”_normalizeRequest_%s”, ucfirst($url_handler));
        if (method_exists($this, $method)) {
            $http_vars = $this->$method($http_vars);
        }
        // normalize
        if (isset($http_vars[’__url_info__’])) {
            $path = $http_vars[’__url_info__’];
        } else {
            $path = “”;
        }
        list($path, $is_slash) = $this->_normalizePath($path);
        $mapper = Net_URL_Mapper::getInstance($http_vars[’__url_handler__’]);
        foreach ($this->action_map[$http_vars[’__url_handler__’]] as $key => $value) {
            $mapper->connect($key, $value);
        }
        $result = $mapper->match($path);
        $http_vars = $this->buildActionParameter($http_vars, $result[’action’]);
        unset($result[’action’]);
        $http_vars = array_merge($http_vars, $result);
        return $http_vars;
    }
}
?>

アプリケーションがリクエストを受け取ったときに、使用するマッピングルールをEthnaに教えてあげる必要があります。
こちらにあるように、エントリポイントのファイルに記述します。

< ?php
require_once dirname(dirname(__FILE__)).'/app/Hoge_Controller.php';
// URLハンドラで使うマッピングルールを指定
$_SERVER['URL_HANDLER'] = 'index';
Hoge_Controller::main('Hoge_Controller', 'index');
?>

サンプルコード内の$action_map内のキー’index’を、エントリポイントの環境変数にセットしている’index’に対応させています。
このように設定することで、このエントリポイントからのアクセスは、URLハンドラ内の’index’と名付けたルールが適用されるようになります。

サンプルコードの例だと、Net_URL_Mapperが

http://example.com/index.php/login
↓
http://example.org/index.php?action_login=true
http://example.com/index.php/view/japan/5
↓
http://example.com/index.php?action_view=1&category=japan&offset=5

というように変換してEthnaに渡してくれるようになります。

最後にmod_rewriteで以下のような変換をすれば、URL内の「index.php」を省いてアクセスすることができます。

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) /hoge/www/index.php/$1 [L]

ご指摘等、ありましたら、お待ちしております!

コメント

デフォルトのUrlHandlerもNet_UrlMapperとほとんど同じ事ができるんですがクセがあるのが難点ですよねー.

2007年12月6日 木曜日  halt より

コメントありがとうございます。おかげさまで大助かりでした。ありがとうございました。Ethna_UrlHandler、自分にはとっつきにくくて即あきらめてしまいましたよー。

2007年12月6日 木曜日  平井 より

コード、使わせてもらいました。ありがとうございます。
ちなみにローカルではOKだったんですが、レンサバではダメでした。なにかあるんでしょうかね~?

2008年11月2日 日曜日  xylish より

コメントをどうぞ