« symfonyを使って文字コードUTF-8でDB操作をする方法 | メイン | 通勤路 »

symfonyでURLを.htaccessでRewriteする方法

私の週末は十数行程度のコード修正と数え切れないsymfonyソースコードのCtrl+Z(元に戻す)に集約される。。。

symfonyのチュートリアルでは開発環境がどうであれ

http://askeet/

のようにプロジェクト名をURLにしてアクセスするように進められているが、まず、他のシステムを動かすためにわざわざhttpd.confとhostを書き換えてApacheを再起動するのは面倒だし、前回の文字化け投稿と同様、納品先のことも考慮したらhttpd.confでの設定が出来ないことも考慮する必要が出てくる。

と言うわけでhttpd.confを使わずに

http://localhost/symfony/projectname/

で表示させる方法。

まず、

http://localhost/symfony/projectname/web/

これはすぐに出来る。つーか、彼らの http://askeet/ にする設定を外せばいいだけ。

只、そうするとsymfonyが提供するお洒落なJava Scriptタブやエラー画面が表示されなくなる。どうでもいい魚の骨。

httpd.confでの設定ではPEARディレクトリへの参照パスは許されているが、.htaccess では権限エラーになってしまう。Windowsでそこの設定を変更するのを調べるのは面倒なので、htdocs配下に

PEAR\data\symfony\web\sf

の中身全部をコピー(突っ込み歓迎)。ちなみに私は htdocs/symfony/ 配下にコピー。

symfony/projectname/web/.htaccess を修正。

  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteRule ^sf/(.*)$ /symfony/sf/$1 [L]

を #RewriteBase のすぐ下あたりに追加。

へい、mod_rewriteです。簡単に説明すると

RewriteCond %{REQUEST_FILENAME} !-d

はリクエストファイルの文字列がディレクトリでは無い場合

RewriteCond %{REQUEST_FILENAME} !-f

はリクエストファイルの文字列がファイルでは無い場合

つまり、そこに存在しない場合(と私は解釈@突っ込み歓迎)

その存在しないリクエストファイルの文字列が「sf/」で始まり、任意の1文字が0回以上ある集合体で終わる場合(カッコで囲むので$1と言う変数で認識してくれる)

/symfony/sf/

の後ろに$1を付け足し

そいつらの在りかをそこで探しておくれ

で、[L]はこのリクエストファイルの文字列でのrewriteはここで終了、と言う意味。

以後のmod_rewriteの説明は割愛。

魚の骨が取れることを確認。

次に

http://localhost/symfony/projectname/web/

ではなく、

http://localhost/symfony/projectname/

で表示できるようにがんばることにする。そこからまた苦労が始まる。。。

もちろん、webの中身を一個上のフォルダに移動すればそれだけで完了だ。しかしそこには生きる上での喜びがない(私の場合)。

と言うわけで、まずは

symfony/projectname/

.htaccess

を作成。つーか、私はsymfonyさんのをコピーした。理由:共通性を図るため。理由:手間を省くため。

で、

Options +FollowSymLinks +ExecCGI


  RewriteEngine On
  #RewriteBase /

以外は全部消す。下のErrorDocumentは消しても残してもどちらでも良い。

そこで凄いことに気付く。

http://localhost/symfony/projectname/

としたら

ディレクトリ構造丸見えじゃん!

いかんざき!

つーわけで

Options +FollowSymLinks +ExecCGI

の下に

Options -Indexes

を追加。見んなよ、と言う意味。

RewriteBaseのコメントを外し

RewriteBase /symfony/projectname/web/

とする。書き換える時はこれを頭につけておくれ、と言う意味。

その下に

  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteRule ^(.*)\.php/(.*)$ $1.php/$2 [QSA,L]

  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteRule ^(.*)$ index.php/$1 [QSA,L]

と追加。4行目はファイル名を指定していない時( 例:http://hogehoge.nk/ )に必要。

これで

http://localhost/symfony/projectname/

で表示されるようになった。

のに・・・。

困ったことに。。。

リンク先が

http://localhost/symfony/projectname/web/

になっている。。。

普通にHTMLで組んだら

http://localhost/symfony/projectname/

なのに

link_to関数を使うとどうしても'web'がついてしまう。

そして私は更なるsymfonyソースコードの森の奥へ、長い放浪の旅に出ることになる。。。

解決案。

symfony/projectname/apps/appname/lib/

myFrontWebController.class.php

と言うクラスを生成。

PEAR\symfony\controller\sfWebController.class.php

genUrl関数をこちらのクラスでオーバーライドする(sfFrontWebController.class.phpはsfWebController.class.phpを継承している)。

最初に

$url = parent::genUrl($parameters, $absolute);

として親の関数を実行してから追加処理を加える。下記ソース。牡蠣ソース。

class myFrontWebController extends sfFrontWebController
{
  public function genUrl($parameters = array(), $absolute = false)
  {
    $url = parent::genUrl($parameters, $absolute);
    
    //切り取りたい文字列
    $cut_str = 'web/';

    if((preg_match('/\.php/', $url) ||
        preg_match('/index\.php/', $_SERVER['SCRIPT_NAME'])) &&
        (!preg_match('/^http/', $url) ||
         preg_match('/'.$_SERVER['SERVER_NAME'].'/', $url)))

      $url = substr($url, 0, strpos($url, $cut_str)).
             substr($url, strpos($url, $cut_str) + strlen($cut_str));

    return $url;
  }
}

if文の理由はCSSやJavaScriptファイルを'web'配下を参照のままで良いため。

で、

symfony/projectname/apps/appname/config/factories.yml

を修正。

all:
  controller:
    class: myFrontWebController

13行目から3行分コメントアウトし、「sf」のところを「my」に変更。

以上。

コンソールで

symfony cc

を忘れないように。

表示確認。画面遷移確認。データ修正処理確認。

パチパチパチ~~。

今のところアプリ単位やらなければならないようなのでそこはちと手間。

後、ホントは

symfony/projectname/apps/appname/lib/myWebRequest.class.php

にし

class myWebRequest extends sfWebRequest
{
  public function getScriptName()
  {
    $pathArray = $this->getPathInfoArray();
    
    $scriptName = $pathArray['SCRIPT_NAME'];
    
    //切り取りたい文字列
    $cut_str = 'web/';
    
    if(preg_match('/\.php/', $scriptName))
      
      $scriptName = substr($scriptName, 0, strpos($scriptName, $cut_str)).
                    substr($scriptName, strpos($scriptName, $cut_str) + strlen($cut_str));
    
    return $scriptName;
  }
}

とした方がカッコ良かったんだが、何故だ!CSSやJSの連中もこの影響を受ける。な~ぜ~~

後、当初は

symfony/projectname/apps/appname/config/config.php

の終わりに

sfConfig::set('sf_web_dir_name', '');
sfConfig::set('sf_web_dir', sfConfig::get('sf_root_dir'));
sfConfig::set('sf_upload_dir', sfConfig::get('sf_root_dir').DIRECTORY_SEPARATOR.sfConfig::get('sf_data_dir_name'));

で済むと思っていたのだが、どうやらこいつら定数は・・、ゴミ??変更しても全く影響ないので消すことにしよう。

さて、ここまで読んだ人は果たしているのだろうか。ここまで読んでくれた方にとってもいいネタを提供しよう。

debug_backtrace()

と言うPHP関数がある。

出来ればもっと昔から知っておきたかった。

この関数を使って

print_r(debug_backtrace());

とすればそのポイントでの関数の呼び出し元を全部吐き出してくれる。.NETでのスーパー機能をPHPでも再現できることを知った私はもはや喜び組。

ちなみに似たような関数、Rubyにもあるのかな??

最後に、PEARにsymfonyが入っていないレンタルサーバーで動かすには

開発環境のPEAR内のsymfonyグッズを

symfony/projectname/lib

内に突っ込んで

symfony/projectname/config/config.php

// symfony directories
$sf_symfony_lib_dir  = '/hoge/php/pear/symfony';
$sf_symfony_data_dir = '/hoge/php/pear/data/symfony';

を修正するだけ、・・・だと思う。

納品はまだ全然先なのでその点の検証はしばらく保留することに。



広ブロっち♪ d(^-^)

トラックバック

このエントリーのトラックバックURL:

コメントを投稿