php のSlimFramework で pathinfoを強制する
/var/www/myslim に slim を作ったんだけど。 /var/www/myslim/index.php じゃなくて、 /var/www/myslim/webroot/index.php でslimを起動しつつ、/var/www/myslimので起動したい。
つまり、次のようなURLで起動したい
/var/www/myslim/webroot/index.php #⇐ここが起動しつつ http://example.com/myslim/?hogehoge # ⇐ このようにURLを使いたい
cakephp なら初期設定が入っててカンタンに出来るんですよね。
いまだに、Apache+PHPですが、rewrite考えればなんとかなるのでapache好き。
フォルダ構成
takuya@atom:/var/www/myslim$ tree -L 1 . ├── index.php #⇐通常はここから起動する。 ├── app/ ├── etc/ ├── lib/ ├── composer.json ├── composer.lock ├── vendor/ ├── views. └── webroot/
index.php を一階層下に持って行きたい。
. ├── index.php ## ここに書くけど、ここから起動せずに ├── app/ ├── etc/ ├── lib/ ├── composer.json ├── composer.lock ├── vendor/ ├── views. └── webroot/index.php #<-- ここで起動したい。
だけれど、 ttp://127.0.0.1/myslim/webroot/hello とかで起動はさせたくない。ttp://127.0.0.1/myslim/hello で起動したい。
つまり、document root が/var/www で、そこにデプロイしたとしても、railsみたいになっててくれるとうれしいかも?
app_root/を隠しておきたい。
たとえば、これがrails
. ├── Gemfile ├── Gemfile.lock ├── README.rdoc ├── Rakefile ├── app ├── bin ├── config ├── config.ru (ry └── vendor
ほかにもcakephp では次のようなフォルダ構成ができている。
. ├── README.md ├── bin ├── composer.json ├── composer.lock ├── composer.phar ├── config ├── db ├── index.php ├── logs ├── phpunit.xml.dist ├── plugins ├── src ├── tests ├── tmp ├── vendor └── webroot
余計なファイルを隠せる。
このフォルダ構成って楽なんですよ。バーチャルホストやサブディレクトリにガンガンテストアプリケーションや開発アプリを放り込めるしね。
/.git, vendor/ や /lib が見えないように .htaccessをチマチマ追加するのも面倒だしね
SilmFrameworkでディレクトリ構造を導入してみたい。
理想はこの形のフォルダ構成
. ├── index.php ## ここに書くけど、ここから起動せずに ├── app/ ├── etc/ ├── lib/ ├── composer.json ├── composer.lock ├── vendor/ ├── views. └── webroot/index.php #<-- ここで起動したい。
最上位の app_root/.htaccess には次の通り記述する
# index.cgi に全部の処理を貼り付ける RewriteEngine ON RewriteBase /myslim/ # /webroot/index.phpに全部の処理を貼り付ける RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^$ webroot/ [QSA,L] RewriteRule (.*) webroot/$1 [QSA,L]
目標の webroot/.htaccess には次の通り記述する。
RewriteEngine On RewriteBase /epgrec.slim/webroot/ RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.*)$ index.php/$1 [QSA,L,PT]
app_root/webroot/index.php には次の通り記述する
先の.htaccessから内部的に飛ばされてきたものを受け付ける。
webroot/index.php
<?php require_once realpath(__DIR__.'/../vendor/autoload.php'); require_once realpath(__DIR__."/../index.php"); $app->environment["PATH_INFO"] = $_SERVER["PATH_INFO"]; $app->environment["SCRIPT_NAME"] = $_SERVER["SCRIPT_NAME"]; $app->run();
一方で、app_root/index.php では、次のように通常通りにSlimを書く
webroot/index.php で起動しつつ、/index.php 側で主な処理を書いておくことにする。
<?php //php.iniの代替 ini_set("error_reporting", E_ALL & ~E_NOTICE & ~E_STRICT ); ini_set("display_errors","On"); ini_set("display_startup_errors","On"); ini_set("track_errors","1"); date_default_timezone_set("Asia/Tokyo"); //incude_pathの追加 $path = explode(":",ini_get("include_path")); $path[] = realpath(__DIR__."/lib"); ini_set('include_path',join(':',$path) ); //autoload require_once realpath(__DIR__.'/vendor/autoload.php'); //セッション session_save_path(dirname(__FILE__)."/"."var/sessions");//セッションデータの保存先をプロジェクト内部に session_cache_limiter(false); session_start(); //Slim の設定 $app = new \Slim\Slim(array( 'view' => '\Slim\Views\Smarty' , 'templates.path' => realpath(__DIR__."/views"), 'debug' => true, 'log.level' => \Slim\Log::DEBUG, 'log.enabled' => true, 'cookies.encrypt' => true, //cookie 'cookies.secret_key' => 'Life might have been happy', )); //DBの接続テストページ require_once 'init_model.php'; require_once realpath (__DIR__.'/app/ctrl/show_tables.php'); $app->get('/log',"show_log"); $app->get('/keyword',"show_keyword"); $app->get('/category',"show_category"); //indexページをロード require_once realpath (__DIR__.'/app/ctrl/show_index.php'); $app->get("/","index");
/index.php にslim のいつも通り記述してもいいし、lib や vendor に mySlim extends Slim したクラスを作ってもイイね。
static ファイルの配信
あとは、Staticファイルだけれど、これはPHPで配信しても良いし、slim使ってもいいよね。
static ファイルが /webroot/js/test.js として配信されるのは、嬉しくないので、 /js/test.js で配信したいから。
このように書いて、ファイルをwebrootから配信するようにして。
RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^$ webroot/ [QSA,L]
webroot側で
RewriteCond %{REQUEST_FILENAME} !-f
として受けてる。
階層下げるポイントはapp_root/.htaccessのこの箇所
RewriteRule (.*) webroot/index.php/$1 [QSA,L]
ここで、内部リダイレクトを作成して、/myslim/hello/world を /myslim/webroot/hello/wrold にしている。
php側ではPATH_INFOを使うように強制する。
また、次のように記述するとjs/cssをwebrootのしたから配信できる。
RewriteEngine ON
RewriteBase /myslim/
# /webroot/index.phpに全部の処理を貼り付けるばあい
RewriteRule (.*) webroot/$1 [QSA,L]
で、リダイレクト先で.htaccessが活用されて
RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.*)$ index.php/$1 [QSA,L,PT]
ここで、ファイルが存在したらファイルを配信。ファイルがなければindex.php/$1 を起動すると書いてある。
pathinfo について
slim 側がPATH_INFOの処理をうまくしてくれないので,webroot/index.phpにはpatinfoを解決するように記述した。
<?php # (略 $app->environment["PATH_INFO"] = $_SERVER["PATH_INFO"]; $app->environment["SCRIPT_NAME"] = $_SERVER["SCRIPT_NAME"]; $app->run();
と、無理矢理にpathinfoを入れてあげる。これは slim がENVではなく、new されたタイミングscript_nameからアレコレ設定しているせいだとは思うけどね。 $_SERVERやENVを使ってくれないのは悲しいですね。
これで、static ファイルとapp_root を明確に区別しつつ、httpリクエスト上では余り区別しないという楽チンなことができるようになるね。
結論
やっぱりPATH_INFO便利。
この手法とれば、apache + cgi/fcgiでrailsデプロイしても全然気にならないね。
mod_rewriteさえ使ってしまえば、なんでもあり。いくらでもURLを綺麗にできる。
参考資料
http://docs.slimframework.com/configuration/settings/#debug http://help.slimframework.com/discussions/problems/28-path_info-problem