[PHP]Laravel5をOS X(Mac)のローカルサーバーにインストールする

Laravel はオープンソースの PHP アプリケーションフレームワークの一つで、CakePHP や CodeIgniter、FuelPHP などと並び多くの注目を集めています。
この記事では、Mac に Laravel 5 をインストールする手順や発生した問題とその解決方法について書き留めておきます。

現在の環境とインストール予定のバージョンはこちらです。

OS X Yosemite 10.10
Laravel 5.0 または Laravel 5.1

詳細な説明に入る前にインストールの流れを見ておきます。

(1) Composer のインストール
(2) Composer を使って Laravel をインストール
(3) Composer を使って Laravel プロジェクトを作成

すべてが順調に行けば以上の3ステップで導入できますが、実際にはいくつかの問題が発生し、遠回りすることになりました。順を追って説明していきます。


Composer のインストール

Composer は PHP のパッケージ管理ツールです。これを使うことにより依存関係を解決してパッケージをインストールしたり、アップデートを行うことができます。Laravel 専用のツールというわけではなく、Cake PHP などのインストールにも使われています。

インストールするには次のコマンドをコンソールで実行します。

curl -sS https://getcomposer.org/installer | php

実行すると composer.phar ファイルがダウンロードされます。
そのままでは使いにくいのでパスの通っているディレクトリに移動させます。

sudo mv composer.phar /usr/local/bin/composer

これで composer と入力しただけで composer.phar が実行できるようになりました。
試しにバージョンを確認してみます。

composer --version
Composer version 1.0-dev (e64470c987fdd6bff03b85eed823eb4b865a4152) 2015-05-28 14:52:12

正しくインストールされていればバージョンが表示されます。


Laravel のインストール

Laravel インストールには Composer を使って次のようにします。
最新の情報は公式ドキュメント(5.0 / 5.1)を参照してください。

composer global require "laravel/installer=~1.1"

Laravel プロジェクトの作成

Laravel をインストールしたので Composer から Laravel プロジェクトが作れるようになります。
ただし、作成するにはサーバーが次の要件を満たしている必要があります。

【Laravel 5.0】

PHP >= 5.4
Mcrypt PHP Extension
OpenSSL PHP Extension
Mbstring PHP Extension
Tokenizer PHP Extension

【Laravel 5.1】

PHP >= 5.5.9
OpenSSL PHP Extension
Mbstring PHP Extension
Tokenizer PHP Extension

PHP のバージョンを確認するために「$ php -v」コマンドを入力すると、「PHP 5.5.20 」であることがわかりました。Yosemite に標準搭載されている PHP のバージョンには問題ないようです。「which php」コマンドで場所を確認すると「/usr/bin/php」にあることがわかります。
しかし、標準搭載の PHP には Laravel 5.0 に必要な Mcrypt というエクステンションがインストールされていないため、このまま Laravel プロジェクトの作成をしようとすると次のような警告が出ます。(Laravel 5.1 では必要ありません)

Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - Installation request for laravel/framework v5.0.16 -> satisfiable by laravel/framework[v5.0.16].
    - laravel/framework v5.0.16 requires ext-mcrypt * -> the requested PHP extension mcrypt is missing from your system.

そのため、先に「ext-mcrypt」を使えるようにしておく必要があります。

方法は2つあり、もし開発に MAMP を使っているのなら、そちらの PHP をコンソールから使えるように修正し、ext-mcrypt を有効にするという手があります。

【MAMP の PHP をコンソールから使う場合】

コンソールで「php」というコマンドを使った時、通常は「/usr/bin/php」が実行されます。そこで、.bash_profile ファイルにパスを通して、「/Applications/MAMP/bin/php/」の中にある PHP が実行されるように変更します。

$ vi ~/.bash_profile

vi で .bash_profile ファイルを開いたら、次の行を追加します。

export PATH=/Applications/MAMP/bin/php/php5.6.7/bin:$PATH

「php5.6.7」の部分はインストールされている MAMP によって異なります。環境に合わせて書き換えてください。
.bash_profile への変更はログインし直すか下記コマンドを実行しない限り即時には反映されません。

source ~/.bash_profile

MAMP に入っている PHP には ext-mcrypt が付属されています。有効になっていない場合は php.ini を書き換えて有効にします。php.ini は「/Applications/MAMP/bin/php/php5.6.7/conf/php.ini」にあります。
「;extension=mcrypt.so」となっている部分を探して「extension=mcrypt.so」のように先頭の「;」を外したら、MAMP の Apache を再起動させます。

【標準搭載されている PHP に ext_mcrypt をインストールする場合】

Mac に標準搭載されている PHP に ext_mcrypt をインストールする場合は .bash_profile などを変更する必要はありません。
インストールを簡単にするために Homebrew というパッケージマネージャーを利用します。
まずはその Homebrew をインストールします。

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

インストールできていれば「brew -v」コマンドでバージョンが確認できるはずです。
次に「brew search mcrypt」コマンドで mcrypt に関連するパッケージを検索します。
こちらの環境では次のパッケージが見つかりました。

$ brew search mcrypt
libtomcrypt  mcrypt
homebrew/php/php53-mcrypt    homebrew/php/php55-mcrypt
homebrew/php/php54-mcrypt    homebrew/php/php56-mcrypt

PHP のバージョンに合ったものをインストールします。「php -v」コマンドで調べると「PHP 5.5.20」であることがわかったので「homebrew/php/php55-mcrypt」を次のようにしてインストールします。

brew install homebrew/php/php55-mcrypt

こちらで試した時は必要ありませんでしたが、こちらの二行を先に実行しておく必要がある場合もあります。

brew tap homebrew/php
brew tap homebrew/dupes

インストールが完了したら php.ini にこのエクステンションを有効にするための記述を追加します。
php.ini は /etc/php.ini にあるものが読み込まれますが、php.ini.default というファイルしかない場合があります。その場合は php.ini.default をコピーして php.ini に名前を書き換えます。
内容を確認し「;extension=mcrypt.so」という行があれば先頭の「;」を外し、無ければ「extension=mcrypt.so」」という行を追加します。追加が終わったら保存して Apache を再起動させます。再起動のコマンドはこちらです。

sudo apachectl restart

さて、これで PHP と mcrypt の準備が整いました。いよいよ Laravel のプロジェクトを作成します。まずは cd コマンドでドキュメントルートに移動します。MAMP を使っている場合は「cd /Applications/MAMP/htdocs」ですが、Mac の Apache を使っている人は「cd /Library/WebServer/Documents」になるかと思います。次にプロジェクトを作成するためのコマンドを実行します。

◆最新バージョンのインストール

composer create-project laravel/laravel プロジェクト名 --prefer-dist

◆バージョンを指定したインストール(5.0 の場合)

composer create-project laravel/laravel プロジェクト名 5.0 --prefer-dist

プロジェクト名の部分は好きなように書き換えてください。その名前のフォルダが作られます。公開ディレクトリはその中にある「public」というフォルダなので「http://localhost/プロジェクト名/public」でブラウザから確認ができるはずです。

通常は Laravel のデモ画面が表示されますが、おそらく真っ白な画面しか表示されないと思います。というのもフォルダ storage 以下に対して Apache が書き込めるようにパーミッションを設定していないからです。
そこで storage に対して 777 の権限をもたせます。

sudo chmod -R 777 storage

設定が済んだら再度「http://localhost/プロジェクト名/public」にアクセスしてみてください。
うまくいっていればデフォルトのウェルカムメッセージが表示されるはずです。

laravel5

[PHP]クラスにメソッドを動的に追加する

インスタンス化したクラスに、クラスメソッド(メンバ関数)を追加できるようにするには、そのクラスにマジックメソッド __call() を用意します。
__call() はアクセスが制限されたメソッドや、存在しないメソッドを呼びだそうとした際に実行される関数で、関数名とその引数が渡されます。

PHP 5.3 から無名関数(Closure)が導入され、関数を変数に代入して扱うことができるようになりました。
また、PHP 5.4 では Closure のメソッドに bindTo() が追加され、クラスに関数を追加することが可能となっています。

例としてクラス Sample に hello() という関数を取り付けてみます。

<?php
class Sample
{
	private $functions = array();
	private $hello = 'Hello';
	
	function __call($name, $args){
		$callback = $this->functions[$name];
		return call_user_func_array($callback, $args);
	}
	
	public function bindCallback($name, $callback){
		$this->functions[$name] = $callback->bindTo($this, get_class($this));
	}
}

$sample = new Sample();

$callback = function($str){
	return $this->hello . ', ' . $str;
};

$sample->bindCallback('hello', $callback);

echo $sample->hello("World!");
結果: Hello, World!

$callback に関数 hello() の処理を代入し、bindCallback() で保管しておきます。
$sample->hello() でメソッドを呼ぶと、__call() が実行され、call_user_func_array() によって用意しておいた関数が実行されます。

この方法によって既存のメソッドをオーバーライド(上書き)することはできませんが、書き換えを許可するメソッドを bindCallback() で用意しておけば、プラグインのように後から機能を変更するといった使い方もできると思います。

参考:
http://php.net/manual/ja/closure.bindto.php

[PHP]WordPress用のサイトマップを独自に動的生成

WordPress のサイトマップは通常プラグインを使って作るのが一般的ですが、
条件を自由に設定する必要があったり、WordPress をサブディレクトリにインストールしている場合や、
好きな階層にサイトマップを置きたい場合、プラグインだけでは実現できないことが有ります。

サイトマップの生成には以前作った SitemapGenerator クラスを使用します。
まずはそちらを参考に sitemap_generator.php を用意して下さい。

<?php
// wp-load.php を読み込む(環境に応じて書き換えて下さい)
require_once __DIR__ . '/../wordpress/wp-load.php';

require_once __DIR__ . '/sitemap_generator.php';

$sitemap = new SitemapGenerator();

// 取得する記事の設定
$args = array(
	'posts_per_page'   => -1, // すべての記事
	'offset'           => 0,
	'category_name'    => '',
	'orderby'          => 'post_date', // 投稿順
	'order'            => 'DESC',
	'include'          => '',
	'exclude'          => '',
	'meta_key'         => '',
	'meta_value'       => '',
	'post_type'        => ['post', 'page'],	// ブログ記事と固定ページ
	'post_mime_type'   => '',
	'post_parent'      => '',
	'post_status'      => 'publish', // 公開されている記事のみ
	'suppress_filters' => false
);

// WordPress ホームページを登録
$datetime1 = new DateTime(get_lastpostmodified());
$home = array(
	'loc' => home_url(),
	'last_mod' => $datetime1->format('c'),
	'changefreq' => 'daily',
	'priority' => 1.0
);
$sitemap->add($home);

// 投稿と固定ページを登録
$posts = get_posts( $args );

foreach($posts as $post){
    $permalink = get_permalink($post->ID);
    if($permalink === false) $permalink = $post->guid;
    $datetime2 = new DateTime($post->post_modified);
    $param = array(
        'loc' => $permalink,
        'lastmod' => $datetime2->format('c'),
        'changefreq' => 'monthly',
        'priority' => 0.5
    );
    $sitemap->add($param);
}

$sitemap->generate();
exit;

「wp-load.php」は WordPress のフォルダ内にあるファイルで、これを読み込むと WordPress の関数が利用できるようになります。
設置場所の環境に合わせて正しいファイルパスに書き換えて下さい。

「http://example.com/sitemap/index.php」のように配置しておけば、「http://example.com/sitemap」にアクセスした時、自動的にサイトマップが生成され、XML として表示されます。
もしアクセスが頻繁で負荷が高いようなら generate() にファイルパスを渡して sitemap.xml としてファイルに保存しておくのも良いと思います。