それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

Slim framewrork はpathinfoの解釈が変なので対応する

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 なら初期設定が入っててカンタンに出来るんですよね。

いまだに、ApachePHPですが、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/fcgirailsデプロイしても全然気にならないね。

mod_rewriteさえ使ってしまえば、なんでもあり。いくらでもURLを綺麗にできる。

参考資料

http://docs.slimframework.com/configuration/settings/#debug http://help.slimframework.com/discussions/problems/28-path_info-problem