MacでPHPバージョンが切り替えられる開発環境作り


##目的
+ PHPのバージョン切り替え
+ PHPのオプション設定を自分でいじりながら構築したい
+ oci8がついているPHPモジュールの作成
+ pdo_ociも使えるようにする（5.3系だけ）
+ MAMPとMacPortsから離れる

## 注意
+ Apacheのバージョンが既に変わっているので（2.2.23の部分）、コピペする前に確認すること。
+ MySQLも変わっているかもしれないので、コケたらググること。


#準備の準備
##Instant Clientの設置

下記リンクから64bit版を取ってくる。

http://www.oracle.com/technetwork/topics/intel-macsoft-096467.html

32bit版だとPHPをコンパイルするときにコケたので、11.2.0.3.0の64bit版を使用する。
BasicとJDBC、SQL*PlusとSDKとWRCをダウンロードする（WRCは要らないかもしれない）。

今回は/Library/OracleにInstant Clientを設置する。
ダウンロードディレクトリに移動して、全部解凍して同じディレクトリに突っ込む。

```zsh
cd ~/Downloads/
sudo unzip -d /Library/Oracle/ instantclient-basic-macos.x64-11.2.0.3.0.zip
sudo unzip -d /Library/Oracle/ instantclient-jdbc-macos.x64-11.2.0.3.0.zip
sudo unzip -d /Library/Oracle/ instantclient-sdk-macos.x64-11.2.0.3.0.zip
sudo unzip -d /Library/Oracle/ instantclient-sqlplus-macos.x64-11.2.0.3.0.zip
sudo unzip -d /Library/Oracle/ instantclient-tools-macos.x64-11.2.0.3.0.zip
```

oci付きでbuildするために、下記のようにシンボリックリンクを作る。

```zsh
cd /Library/Oracle/instantclient_11_2
sudo ln -s libclntsh.dylib.11.1 libclntsh.dylib
```

.zshrcや.bash_profile（.bashrcではなく）に下記を追加してpathを通す。

```~/.zshrc
export ORACLE_HOME=/Library/Oracle/instantclient_11_2
export SQL_PATH=$ORACLE_HOME
export PATH=$PATH:$ORACLE_HOME
export NLS_LANG=Japanese_Japan.AL32UTF8
export DYLD_LIBRARY_PATH=/Library/Oracle/instantclient_11_2

# 必要であれば
#export ORACLE_SID=XE
```

DYLD_LIBRARY_PATHを設定すると、sudoするときに何かメッセージが出てくるようになるが、それは無視する。

お決まりの反映。

```zsh
source .zshrc
```

Navicatとかで接続確認してみる。
繰り返すが、64bit版にしないとPHPのコンパイルでコケる。

Homebrewのdoctorが通らなくなるため、下記部分を一旦コメントアウトする。

```~/.zshrc
# 一旦コメントアウトで、後で外す
#export DYLD_LIBRARY_PATH=/Library/Oracle/instantclient_11_2
```

反映。

```zsh
source .zshrc
```

参考URL
http://qiita.com/items/5145486fffd590014599



##Homebrewのインストール

MacPortsのアンインストールとXcodeコマンドラインツール必須。

MacPortsアンインストール参考URL
http://abeerforyou.com/?p=334

完了したら下記コマンドを叩いてHomebrewをインストール。

```zsh
ruby -e "$(curl -fsSL https://raw.github.com/mxcl/homebrew/go)"
```

準備できたと言ってくるまで下記のコマンドを叩く＆メッセージ見て直す。
「brew prune」を叩けと言われたら素直に従う。

```zsh
brew doctor
```

とりあえずアップデートをかけておく。

```zsh
brew update 
```
/usr/local/binと/usr/local/sbinにパスを通す。

```~/.zshrc
export PATH=/usr/local/bin:/usr/local/sbin:$PATH 
```

また、先ほどOracleの設定の最後で付けたコメントアウトを解除する。

```~/.zshrc
# 先ほどのコメントアウトを外す
export DYLD_LIBRARY_PATH=/Library/Oracle/instantclient_11_2
```

反映。

```zsh
source .zshrc
```
参考URL
http://yonchu.hatenablog.com/entry/20110226/1298723822

# 準備
##Formuraの追加とコマンドのインストール
Homebrewは既存ソフトはなるべく含まないようにしているらしく、元々存在しているApacheやPHPがデフォルトでは見つからないので、tapでパッケージ情報を追加する。

####Formuraの追加（Apache）
```zsh
brew tap homebrew/dupes 
```

####Formuraの追加（PHP）
```zsh
brew tap josegonzalez/homebrew-php
```

###必要そうなコマンドインストール
```zsh
brew install tree wget curl
```

###PHPで必要になるものインストール
```zsh
brew install re2c jpeg libpng mcrypt libtool openssl zlib
```

PHPはphp-versionを使う。管理用のディレクトリを用意する。

```zsh
mkdir -p ~/local/php/versions
```

##Apache

MacデフォルトのApacheを止める。

```zsh
sudo launchctl unload /System/Library/LaunchDaemons/org.apache.httpd.plist
```

####インストール

```zsh
brew install httpd
```

インストールが終わったら、apachectlの場所を確認する。

```zsh
which apachectl
```

/usr/local/sbin/apachectlになっていなければ、ターミナル再起動。
それでも変わらなければ、PATHが通ってない。 


####Apache起動
```zsh
sudo apachectl start 
```

####Apache停止
```zsh
sudo apachectl stop
```
htdocsとhttpd.confは下記にある。

- /usr/local/Cellar/httpd/2.2.23/share/apache2/htdocs 
- /usr/local/etc/apache2/httpd.conf

htdocsはパスが長いので、ホームディレクトリにエイリアスを張っておくといいかも。
必要であれば、httpd.confを編集する（<Directory /&gt;の設定とか、DirectoryIndexとかAddTypeとか）。

```/usr/local/etc/apache2/httpd.conf
<Directory />
    # 変更
    Options All
    AllowOverride All
    Order allow,deny
    Allow from all
</Directory>    

## 中略 ##

<IfModule dir_module>
    # index.phpを追加
    DirectoryIndex index.html index.php
</IfModule>    

## 中略 ##

<IfModule mime_module>

## 中略 ##

    # 追記
    AddType application/x-httpd-php .php .phtml
    AddType application/x-httpd-php-source .phps
</IfModule>
```


##MySQL
### 最新の場合（5.6系）
#### インストール

```zsh
brew install mysql 
```

###バージョンを指定する場合（5.5系など）
※2013/08/14チェック時にinstallのソースダウンロードで404と言われた

```zsh
cd /usr/local
brew versions mysql
```
バージョンがずらずら出てくるので、5.5系の最新がインストールされるようにチェックアウトする。

```zsh
git checkout 336c976 Library/Formula/mysql.rb
```
#### インストール

```zsh
brew install mysql 
```

####セットアップ
```zsh
mysql_install_db --verbose -user=$(whoami) --basedir="$(brew --prefix mysql)" --datadir=/usr/local/var/mysql --tmpdir=/tmp 
```

###MySQL起動
```zsh
mysql.server start 
```

デフォルトはrootのパスなし。
Navicatなとで接続確認してみる。

#PHP
本題。今までのことは、ここからの作業のための準備。

##OpenSSLをbrewで入れたものに切り替える
Mac標準のOpenSSLはやや古いせいか、PHPのコンパイルでコケる。
なので、コンパイル時のみbrewで入れたものを使用する。

```zsh
openssl version
brew link openssl --force
exec $SHELL -l
openssl version
```
前後でバージョンが変わったかチェック。

##php-buildとphp-versionのインストール
```zsh
brew install php-build php-version
```
php-buildの設定を書き換える。書き換える前にバックアップを作っておく。

```zsh
cd /usr/local/share/php-build/
cp default_configure_options default_configure_options_bk
```
共通設定ファイル「default_configure_options」を編集する。
「--enable-fpm」を削除し、Var_Dumpが使いたいので「--without-pear」を「--with-pear」に変更し、さらに下記の行を追加する。


```default_configure_options
--with-apxs2=/usr/local/sbin/apxs
--with-oci8=shared,instantclient,/Library/Oracle/instantclient_11_2,11.2
```

次に各バージョンごとの設定が書かれているファイルが置かれている場所に移動する。
5.2.17の設定に下記内容をファイルの先頭に追加する。

```/usr/local/share/php-build/definitions/5.2.17
configure_option "--enable-fpm"
```

5.3.19はpdo_ociをインストールする。
こちらもファイルの先頭に設定する。

```/usr/local/share/php-build/definitions/5.3.19
configure_option "--with-pdo-oci=shared,instantclient,/Library/Oracle/instantclient_11_2,11.2"
```
pdo_ociに関して、同じ設定を5.2.17でやるとビルドできないので注意（Instant Clientのバージョンを落とせばいけるかも）。
最後のバージョン番号を指定してあげないと失敗する（指定したinstantclientの設置ディレクトリ名からバージョン番号を取ろうとするため）。

### PHP5.2.17のビルド
```zsh
php-build 5.2.17 ~/local/php/versions/5.2.17
```
1回目はダウンロードが発生するので、かなりに時間がかかる。
コンパイルでも時間がかかる。
なので、しばらく放置する。
同じバージョンの2度目のビルドは、/var/tmp/php-build/source下にソースが残っていればダウンロード時間はかからない。

#### モジュールファイルの移動
5.3.19をビルドする前に移動しないと上書きされて消える。

```zsh
mv /usr/local/Cellar/httpd/2.2.23/libexec/libphp5.so ~/local/php/versions/5.2.17/libphp5.so 
```
php.iniをコピーしておく（勝手に作られているようだし、いらないかも）。

```zsh
cp /var/tmp/php-build/source/5.2.17/php.ini-recommended ~/local/php/versions/5.2.17/etc/php.ini
```


### PHP5.3.19のビルド
```zsh
php-build 5.3.19 ~/local/php/versions/5.3.19  
```
#### モジュールファイルの移動
5.2.17と違い、こちらはコピーする。

```zsh
cp /usr/local/Cellar/httpd/2.2.23/libexec/libphp5.so ~/local/php/versions/5.3.19/libphp5.so 
```
php.iniを用意する（いらないかも）。

```zsh
cp /var/tmp/php-build/source/5.3.19/php.ini-development ~/local/php/versions/5.3.19/etc/php.ini
```

PATHを追加しておく。

```~/.zshrc
# php-version用
export PHP_VERSIONS=$HOME/local/php/versions
source $(brew --prefix php-version)/php-version.sh && php-version 5.3.19 >/dev/null
```

反映。

```zsh
source .zshrc
```

##PHPにモジュールを読み込ませる
5.2系。~/local/php/versions/5.2.17/etcにphp.iniがあり、その下のconf.dにiniファイルを置いて読み込ませる。php.ini自体に追記するかどうかはお好みで。

```~/local/php/versions/5.2.17/etc/conf.d/oci8.ini
extension=oci8.so
```
同様に5.3系も。5.3系ではpdo_ociも読み込ませたい。

```~/local/php/versions/5.3.19/etc/conf.d/oci8.ini
extension=oci8.so
```
```~/local/php/versions/5.3.19/etc/conf.d/pdo_oci.ini
extension=pdo_oci.so
```
5.2系でpdo_ociを使いたい場合は、instant clientのバージョンを下げれば可能かもしれない（試してない）。

あと、date関数がエラー吐いたりするので、php.iniのタイムゾーンの設定も忘れずに。

```/local/php/versions/[PHPVersion]/etc/php.ini
; 1000行目付近
date.timezone = Asia/Tokyo
```


# ApacheにPATHを通す

このままだとApacheがinstant clientを認識しないらしく（よくわからない）、pdo_ociが動かない。
なのでパスを通す

```/usr/local/Cellar/httpd/2.2.23/sbin/envvars
if test "x$DYLD_LIBRARY_PATH" != "x" ; then
  DYLD_LIBRARY_PATH="/usr/local/Cellar/httpd/2.2.23/lib:$DYLD_LIBRARY_PATH"
else
  DYLD_LIBRARY_PATH="/usr/local/Cellar/httpd/2.2.23/lib"
fi

# 追加start
DYLD_LIBRARY_PATH="/Library/Oracle/instantclient_11_2:$DYLD_LIBRARY_PATH"
# 追加end

export DYLD_LIBRARY_PATH
```

# 設定されているか一旦確認する
phpinfo();でpdo_ociが存在するか確認する。
存在しない場合は、~/local/php/versions/5.3.19/lib/php/extensions/o-debug-non-zts-yyyymmdd下にモジュールファイルが生成されているかを確認する。
存在しない場合は設定自体ミスっている可能性があるので、「php-buildとphp-versionのインストール」の項目をもう一度確認する。
それでもダメならPC再起動もやってみると、意外とすんなり通る場合がある。

モジュールファイルが存在している場合は、下記コードで接続確認をしてみる。
設定は各自のOracle環境に合わせて変更する。

```/path/to/webroot/pdo_oci.php
<?php

define("DB_HOST", "##host name##");
define("DB_PORT", "##port##"); // デフォルト1521
define("DB_USERNAME", "##schema name##");
define("DB_PASSWORD", "##password##");
define("DB_SID", "##sid##");

try {
    $dbh = new PDO("oci:dbname=//".DB_HOST.":".DB_PORT."/".DB_SID, DB_USERNAME, DB_PASSWORD);
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e){
    die($e->getMessage());
}
echo 'OK';
exit(0); 
```
ブラウザからアクセスして、DBに接続できているかどうかを確認する。

### OpenSSLを戻す
他で影響が出るとイヤなので、デフォルトのバージョンを使用するように戻しておく（今のところ特に影響がないので、放置でもいいかも）。

```zsh
brew unlink openssl --force
exec $SHELL -l
openssl version
```

#ApacheにSSLを設定する

参考URL
http://javaflavor.cocolog-nifty.com/blog/2007/07/macportsapache2_dce3.html

```
sudo openssl genrsa -des3 -rand /var/log/system.log -out localhost.key 1024
sudo openssl req -new -key localhost.key -out localhost.csr
sudo openssl x509 -req -in localhost.csr -signkey localhost.key -out localhost.crt -days 3560
sudo chmod 400 localhost.*
sudo mv localhost.key localhost.key.orig
sudo openssl rsa -in localhost.key.orig -out localhost.key
sudo chmod 400 localhost.key
```

#PHPのバージョン切り替えシェルを用意する

php5.soを切り替えるためのシェルをhome下とかに置いておく。

参考URL
http://qiita.com/suin/items/26162a4ebcbbb351b879

```
# Apache PHPモジュール入れ替え

PROGRAM_APPNAME=$(basename $0)
PROGRAM_VERSION="1.0.0"

# Apacheへのパス
APACHE_PATH="/usr/local/Cellar/httpd/2.2.23"

# PHPモジュール移動先パス
APACHE_LIBEXEC_DIR="${APACHE_PATH}/libexec"

# PHPモジュール保管先
PHP_HOME=$PHP_VERSIONS

# 選択バージョン
OPT1="5.2.17"
OPT2="5.3.19"


# PHPバージョン選択
select_version() {
    echo "Please select PHP version"
    select PHP_VERSION in "$OPT1" "$OPT2"
    do
        if [ -z ${PHP_VERSION} ]; then
            continue
        else
            break
        fi
    done
    echo php "$PHP_VERSION"
}

# PHP保管先確認
check_php_home() {
    if [[ ! -d ${PHP_HOME} ]]
    then
        echo "Sorry, but ${PROGRAM_APPNAME} requires that \$PHP_HOME is set and points to an existing directory." >&2
        exit 1
    fi
}

# Apacheパス確認
check_apache_path() {
    if [[ ! -d ${APACHE_PATH} ]]
    then
        echo "Sorry, but ${PROGRAM_APPNAME} requires that \$APACHE_PATH is set and points to an existing directory." >&2
        exit 1
    fi
}

# PHPモジュールパス設定
set_up_php_module_path() {
    php_module_path=$PHP_HOME/$PHP_VERSION/libphp5.so
}

# PHPモジュールパス確認
check_php_module_path() {
    if [[ ! -f ${php_module_path} ]]
    then
        echo "Sorry, apache module not found: $php_module_path"
        exit 1
    fi
}

# libexecディレクトリ確認
check_apache_libexec_dir() {
    if [[ ! -d ${APACHE_LIBEXEC_DIR} ]]
    then
        echo "Directory not found: $APACHE_LIBEXEC_DIR"
        exit 1
    fi
}

# PHPモジュール入れ替え
replace_php_module() {
    echo "Copy $php_module_path to $APACHE_LIBEXEC_DIR/libphp5.so"
    cp $php_module_path $APACHE_LIBEXEC_DIR/libphp5.so
}

# Apache停止
stop_apache() {
    echo "Stopping apache..."
    sudo apachectl stop
    sleep 3
}

# Apache起動
start_apache() {
    echo "Starting apache..."
    sudo apachectl start
}

# Apache再起動
restart_apache() {
    echo "Restarting apache..."
    sudo apachectl restart
}

# PHP保管先確認
check_php_home

# Apacheパス確認
check_apache_path

# libexecディレクトリ確認
check_apache_libexec_dir

# PHPバージョン選択
select_version

# Apache停止
stop_apache

# PHPモジュールパス設定
set_up_php_module_path

# PHPモジュールパス確認
check_php_module_path

# PHPモジュール入れ替え
replace_php_module

# Apache起動
start_apache
```



上記はApacheで使用するモジュールの切り替えを行うもの。
CLIのPHPの切り替えは、5.2系にするならターミナル上で次のように打つ。

```zsh
php-version 5.2.17
```
5.3系にするなら

```zsh
php-version 5.3.19
```

上記コマンドによって切り替えでエラーが発生した場合（バージョンが見つからないというエラーが出るケースがある）、正常に動作するバージョンのphp-versionのシェルに置き換える。
下記は0.9.3の内容。

``` /usr/local/Cellar/php-version/[versionNumber]/php-version.sh
################################################################################
# name: php-version
# what: function that allows switching between compiled PHP versions
# why : there is nothing wrong with trying to keep it simple...
################################################################################

function php-version {
  local PROGRAM_APPNAME='php-version'
  local PROGRAM_VERSION=0.9.3

  # correct # of arguments?
  if [ $# != 1 ]; then
    echo "${PROGRAM_APPNAME} ${PROGRAM_VERSION}" >&2
    echo ""                                      >&2
    echo "Usage  : ${PROGRAM_APPNAME} <version>" >&2
    echo "Example: ${PROGRAM_APPNAME} 5.4.3"     >&2
    return 1
  fi

  # local variables
  local _PHP_VERSION=$1
  local _PHP_VERSIONS=${PHP_VERSIONS-''}
  local _PHP_ROOT=${_PHP_VERSIONS}/${_PHP_VERSION}

  # bail-out if _PHP_VERSIONS does not exist
  if [[ ! -d ${_PHP_VERSIONS} ]]; then
    echo "Sorry, but ${PROGRAM_APPNAME} requires that \$PHP_VERSIONS is set and points to an existing directory." >&2
    return 1
  fi

  # bail-out if _PHP_ROOT does not exist
  if [[ ! -d $_PHP_ROOT ]]; then
    echo "Sorry, but ${PROGRAM_VERSION} was unable to find directory '${_PHP_VERSION}' under '${_PHP_VERSIONS}'." >&2
    return 1
  fi

  # safe to export these now!
  export PHP_VERSION=${_PHP_VERSION}
  export PHP_ROOT=${_PHP_ROOT}

  # add the "bin" path to the front (prepend) of $PATH
  export PATH="${PHP_ROOT}/bin:$PATH"

  # find php manpath
  local _MANPATH=$(php-config --man-dir)
  if [ -z $_MANPATH ]; then
    _MANPATH=${PHP_ROOT}/share/man
  fi

  # prepend $_MANPATH to $MANPATH if the directory exists
  if [ -d $_MANPATH ]; then
    export MANPATH="${_MANPATH}:$MANPATH"
  fi

  echo "SWITCHED PHP VERSION TO: ${PHP_VERSION}"
  echo "NEW PHP ROOT DIRECTORY : ${PHP_ROOT}"
}


################################################################################
# shell completion for php-version function
################################################################################

if [[ ! -d ${PHP_VERSIONS} ]]; then
  echo "Sorry, but php-version requires that the environment variable \$PHP_VERSIONS is set in order to initialize bash completion." >&2
  return 1
fi

if [[ ! -z ${PHPVERSIONDISABLE_COMPLETE} ]]; then
  return 1
fi

# completion for bash
if [[ -n ${BASH_VERSION-""} ]]; then
  _phpversions() {
    local CURRENTWD="${COMP_WORDS[COMP_CWORD]}"
    COMPREPLY=( $(compgen -d ${PHP_VERSIONS%/}/${CURRENTWD} | tr -d ${PHP_VERSIONS%/}/ | grep -vi "${PHP_VERSION}\$") )
  }

  complete -o nospace -F _phpversions php-version
  return $?
fi


```