HerokuとかPaaS上のEthnaのURLをイイ感じにする

_この記事はEthna超超超初心者向けの内容です。_

どうも、[M_Ishikawa](http://about.me/M_Ishikawa)です。初Qiita、初Advent Calendar!!!

業務で使っているEthnaをちょっとスケルトンから始めてなんか作ってみたいなと思ったのです。
が、そこでちょいと引っかかったしWebに情報がなかったので（PaaSでEthnaやる人が少ない！？）備忘録のつもりでここに書きます。

------

### EthnaのデフォルトのままのURLって、なんかイケてないですよね？

以前[HerokuでEthnaを動かしてみたときにブログ](http://d.hatena.ne.jp/ishikawam/20120413/p1)を書いたのですが、同じような環境でなんか作ります。
しかし、ページを増やそうとしたときに、たとえば名前(Ethnaでいうアクション名)を「page」にしたいとすると、アクセスURLは

```
http://xx.xx.xx/?action_page=true
```

になっちゃいます。

え…このURLちょっとヤダ…
望んでいるイイ感じのURLは、

```
http://xx.xx.xx/page
```

です。
このイケてないしヤバイURL、なんとかしたい！


そこでGoogle先生に聞いてみたところ、
[Ethna で綺麗な URL (Ethna_UrlHandler を使わない方法)](http://rd.uniba.jp/blog/2010/06/30/ethna-%E3%81%A7%E7%B6%BA%E9%BA%97%E3%81%AA-url-ethna_urlhandler-%E3%82%92%E4%BD%BF%E3%82%8F%E3%81%AA%E3%81%84%E6%96%B9%E6%B3%95/)
を教えてくれました。



```php:app/Appid_Controller.php
<?php
//…

function _getActionName_Form()
{
    if (isset($_SERVER['REQUEST_METHOD']) == false) {
        return null;
    }
        if (strcasecmp($_SERVER['REQUEST_METHOD'], 'post') == 0) {
        $http_vars =& $_POST;
    } else {
        $http_vars =& $_GET;
    }
 
    foreach ($http_vars as $name => $value)
    {
        if ($value == "" || strncmp($name, 'action_', 7) != 0) {
            continue;
        }
        // オリジナル方式 http://hostname/?action_action_name
        return parent::_getActionName_Form();
    }
 
    // かっこいい http://hostname/action/name/ 方式
    if (!empty($_SERVER['REDIRECT_URL']))
    {
        $redirect_url = $_SERVER['REDIRECT_URL'];
        $action_name = str_replace('/', '_', $redirect_url);
        return trim($action_name, '_');
    }
 
    // まあ悪くはない http://hostname/?action=action_name 方式
    if (array_key_exists('action', $http_vars))
    {
        return $http_vars['action'];
    }
}
```

さっそく試してアクセスしてみたのですが、、、


* Appid\[13997](ERR): Ethna_Controller._trigger_WWW(class/Ethna_Controller.php:875): undefined action [indexphp] [ERROR CODE(32)]


あれれ。アクション名が[indexphp]？？？
あやしいところをデバッグしてみます。

```php:app/Appid_Controller.php
<?php
//…

     // かっこいい http://hostname/action/name/ 方式
    if (!empty($_SERVER['REDIRECT_URL']))
    {
var_dump($_SERVER['REDIRECT_URL']);
        $redirect_url = $_SERVER['REDIRECT_URL'];
        $action_name = str_replace('/', '_', $redirect_url);
        return trim($action_name, '_');
    }
 ```

すると

```sh:出力
string '/index.php' (length=10)
```

えっ。。。そうじゃない、欲しいのはファイル名じゃなくてURLのパス部分！
えーっと、URLのパスを取得する環境変数はっと。いくつかあったな。

```php:app/Appid_Controller.php
<?php
//…

var_dump($_SERVER['REQUEST_URI']);
var_dump($_SERVER['SCRIPT_NAME']);
var_dump($_SERVER['PHP_SELF']);
```

すると

```sh:出力
string '/page' (length=5)
string '/www/index.php' (length=14)
string '/www/index.php' (length=14)
```

あれれ？なんかおかしい。REQUEST_URIを使えばいいのはわかった。でも、たしかPHP_SELFもURLのパスがくると思ってたら。。。
そもそもがREDIRECT_URLでもOKなはずなのに。。。ひょっとして私の環境が、変…？

そう、Herokuを使っているのでちょっと思い当たるフシが。。。

[過去のブログの下部参照](http://d.hatena.ne.jp/ishikawam/20120413/p1)


```apacheconf:.htaccess
RewriteEngine on
RewriteBase /
RewriteRule ^(.+)-info\.php$ $1-info.php [L]
RewriteCond %{SCRIPT_FILENAME} !^/app/www/ethnatest/www/
RewriteRule ^(.*)$ ethnatest/www/$1 [L]
```
これでwww以下にリダイレクトして、さらにwwwで


```apacheconf:www/.htaccess
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
```

と、二段階でリライトしてた、これが原因だ！！！
へー、なるほど、PHP_SELFとREQUEST_URIはこういうふうに差が出るのね。（前にも調べたはずだけどすぐ忘れちゃう）

というわけで、最終的には

```php:app/Appid_Controller.php
<?php
//…

function _getActionName_Form()
{
    if (isset($_SERVER['REQUEST_METHOD']) == false) {
        return null;
    }
        if (strcasecmp($_SERVER['REQUEST_METHOD'], 'post') == 0) {
        $http_vars =& $_POST;
    } else {
        $http_vars =& $_GET;
    }
 
    foreach ($http_vars as $name => $value)
    {
        if ($value == "" || strncmp($name, 'action_', 7) != 0) {
            continue;
        }
        // オリジナル方式 http://hostname/?action_action_name
        return parent::_getActionName_Form();
    }
 
    // 新かっこいい http://hostname/action/name/ 方式
    if (!empty($_SERVER['REQUEST_URI']))
    {
        $redirect_url = $_SERVER['REQUEST_URI'];
        $action_name = str_replace('/', '_', $redirect_url);
        return trim($action_name, '_');
    }
 
    // まあ悪くはない http://hostname/?action=action_name 方式
    if (array_key_exists('action', $http_vars))
    {
        return $http_vars['action'];
    }
}
```

とすることでイイ感じのURL

```
http://xx.xx.xx/page
```

にアクセスして無事ページが表示されました！やったー＼(^o^)／


PHPとかEthnaに限らずPaaS利用しているとドキュメントルート＝転送先のトップディレクトリってパターンが多いと思うので、そこで.htaccessで解決する場合は環境変数に注意しようね(・ω<)


enjoy! Ethna on heroku!!


<div>![M_Ishikawa](http://api.osae.me/retwipi/M_Ishikawa) [@M_Ishikawa](http://twitter.com/M_Ishikawa)</div>