Windows Server 2008R2でcakephp3 ＠ IIS / SQLServer2008R2 / php7（チュートリアルまで）

# 概要

タイトルのとおり、Windows Server 2008R2(aws)でcakephp3を動かします。

# EC2インスタンス

Windows_Server-2008-R2_SP1-English-64Bit-SQL_2008_R2_SP3_Express-2017.01.11 (ami-bb364bdc)
を使いました。

# php7.0の設定【7.1じゃないよ】

2017/3/25現在、**SQLServerのPDOドライバがphp7.1に未対応なので！！**php7.0をインストールします。

## phpの解凍・配置

http://windows.php.net/download/#php-7.0
`C:\php`に色々配置するのがphp.iniのデフォルト設定に沿っているので、`C:\php`に解凍します。7.1をインストールしてもPDOドライバが動きません！！

## 実行に必要な再頒布可能ライブラリのインストール

https://www.microsoft.com/ja-jp/download/details.aspx?id=48145
で手に入るライブラリをインストールします。

## php.iniの編集

```ini:php.ini(コメントアウト外す)
extension=php_intl.dll
extension=php_mbstring.dll
extension=php_openssl.dll
```

```ini:php.ini(追加)
extension=php_sqlsrv_7_ts_x64.dll
extension=php_pdo_sqlsrv_7_ts_x64.dll
error_log = syslog
```

## Pathを通す

System(System Properties) -> Advanced  -> Environment Variables...
Pathを選択し、末尾に;C:\phpを追加します。

## SQLServer用PDOの解凍・配置

https://www.microsoft.com/en-us/download/details.aspx?id=20098
から`SQLSRV40.EXE`を拾ってきて実行し、`C:\php\ext`を解凍先に指定して解凍します。

## phpの設定ができていることの確認

コマンドラインで`php -v`と入力します。特に問題なくphpのバージョンが出ればOKです。
この時点で、変なメッセージが出たりする場合には、メッセージを読んで対応します。
php7ts.dllがどうのこうの、というエラーダイアログが２つ出る場合は、phpのバージョンが7.1になっていないか確認しましょう。

# SQLServerの設定

既に入っているSQLServerにDBとユーザーを追加します。

## データベースの作成

オブジェクトブラウザで右クリックして、適当にデータベースを作成します。
照合順序はデフォルト設定でOK。（Latin1...）

## ユーザーの作成

SQLServer認証可能なユーザーを（SQLServer Management Studioで）作成します。
上で作成したデータベースの所有者をこのユーザーにしておきます。

## SQLServer認証の許可

オブジェクトブラウザのサーバーで右クリックしてプロパティを表示すると、Securityの上の方のラジオボタンでWindows Authentication mode/SQL Server and Windows Authentication modeの選択ができるので、SQL Server認証を許可します。

## ODBCドライバのインストール

https://www.microsoft.com/en-us/download/details.aspx?id=53339
よりmsodbcsql.msiを拾ってきてインストールします。

## SQLServerの設定ができていることの確認（確認しなくてもよい）

・SQLServer Management Studioで、上で設定した新しいユーザーでアクセスをできるかチェックします。
・コマンドを指定して実行（Windowsキー + r）でodbcad32と入力し、Addを押して、上で設定した内容でアクセスしようとしたときにアクセスできるかをチェックします。※このときのホスト名はサーバーのローカルIPで接続できるか確認します。

# cakephpのインストール

composerを使います。ので、composerのインストールを行い、composerを実行し、IISの設定を行います。

## composerのインストール

https://github.com/composer/windows-setup/releases/
からインストール用のファイルを入手して実行します。Composer-Setup.4.5.0.exeでした。
インストールができたら、composer.pharの場所を検索しておきます。
（以下では、composer.pharをC:\phpにコピーしていますが、多分そのままcomposer.pharをパス指定しても実行できると思います。）

## cakephpのインストール

```
cd C:\inetpub\wwwroot
php C:\php\composer.phar create-project --prefer-dist cakephp/app someapp
```
これで、少し時間をかけてcakephpのプロジェクトが作成されます。

## IISのウェブサイト作成

Internet Informatin Service(IIS) Managerを開き、ウェブサイトを作成します。
ドキュメントルートは`C:\inetpub\wwwroot\someapp\webroot`です。
証明書がついているので、既存のウェブサイトとの衝突を避ける目的でSSL(https)にしておきます。

## FastCGIの設定

上で追加したウェブサイトをクリックし、Handler MappingsのAdd module mappings...で*.php、Fastcgi module、C:\php\php-cgi.exeを追加します。
http://main.tinyjoker.net/Tech/PHP/CakePHP%20%A4%F2%20IIS7.5%20%A4%C7%C6%B0%A4%AB%A4%B9.html
のFastCGIの設定などが参考になります。

## URL置換ルールを設定する

cakephpを自然に動かすためにはURL置換ルールを設定する必要があるらしいので、URL置換ルールを設定します…が、そのためにまず追加でプログラムをインストールします。

### rewrite_2.0_rtw_x64.msi

https://www.microsoft.com/ja-jp/download/details.aspx?id=7435
にあります。

### URL置換ルールの追加

公式の内容を参考に、以下のweb.configをwebroot直下に配置するか、IISの管理ツールで対応するURL置換ルールを直接追加します。

```xml:web.config
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="Exclude direct access to webroot/*"
                  stopProcessing="true">
                    <match url="^webroot/(.*)$" ignoreCase="false" />
                    <action type="None" />
                </rule>
                <rule name="Rewrite routed access to assets(img, css, files, js, favicon)"
                  stopProcessing="true">
                    <match url="^(img|css|files|js|favicon.ico)(.*)$" />
                    <action type="Rewrite" url="webroot/{R:1}{R:2}"
                      appendQueryString="false" />
                </rule>
                <rule name="Rewrite requested file/folder to index.php"
                  stopProcessing="true">
                    <match url="^(.*)$" ignoreCase="false" />
                    <action type="Rewrite" url="index.php"
                      appendQueryString="true" />
                </rule>
            </rules>
        </rewrite>
    </system.webServer>
</configuration>
```

## ここまでの確認…をしたい場合は

https://localhost/index.php
とかにアクセスすると、一応それっぽい画面が表示されます。

## logs/tmpのアクセス権を設定する

webroot\logs, webroot\tmpに対するIISユーザのアクセス権をフルアクセスに設定します。このとき、配下のフォルダ全てにアクセス権を適用するようにします。

## app.phpを書き換える

app.phpの一部を次のように書き換えます：

```php:app.php(の一部)
    'Datasources' => [
        'default' => [
            'className' => 'Cake\Database\Connection',
            'driver' => 'Cake\Database\Driver\Sqlserver',
            'persistent' => false,
            'host' => '【xxx.xxx.xxx.xxx】',
            'port' => '1433',
            'username' => '【your_user】',
            'password' => '【your_pass】',
            'database' => '【your_db】',
            'encoding' => PDO::SQLSRV_ENCODING_UTF8,
            'timezone' => 'UTC',
            'flags' => [],
            'cacheMetadata' => true,
            'log' => false,
```
【】の部分は、環境に合わせて書き換えます。

## ここまでの確認

https://localhost/index.php
にアクセスしたときに、エラーになっている要素がなければOKです。エラーになっている要素があれば、指示に従って直します。
切り分け用に、`<?php phpinfo();`とだけ書いた拡張子がphpのファイルをwebroot直下に配置して、ブラウザからアクセスすれば、fastcgiが動いているかどうか、PDOがインストールできているかどうか、等を確認することができます。
ここまでの設定で、一応動く状態にはなるはずです。

## SQLServerへの接続でエラーが出た場合

SQLServerへの接続がうまくできない状態でエラーになると、最初は普通の画面（？）が表示されますが、この画面でリロードすると更に別のFatalなエラーが出るようになってしまいます。
SQLServerへの接続をプールしてしまっているようで、エラーになっている接続をプールして一回目よりもおかしな状態になってしまうようですね…（persistentをfalseにしても！）
一度この状態になったら、FastCGIのキャッシュが死ぬまでSQLServerに接続できないような気がするので、Ctrl + Shift + ESC等でタスクマネージャーを使ってphp-fastcgiのプロセスを殺します。※このプロセスは、SQLServerやIISのウェブサイトを再起動しても残っているので質が悪いです。多分この問題と関連するであろうissueが、Githubにopenで存在しています：
https://github.com/cakephp/cakephp/issues/9963

# おまけ：チュートリアル(bookmarks)

公式の
https://book.cakephp.org/3.0/en/tutorials-and-examples/bookmarks/intro.html
に従えば概ね問題は無いですが、以下の２点のみ注意する必要があります：

## SQLServer用のDDL

ところどころ微妙に書き方が違います、、、あとnvarchar/ntextにしているところとか

```sql:ddl.sql
CREATE TABLE users (
    id INT IDENTITY(1,1) PRIMARY KEY,
    email NVARCHAR(255) NOT NULL,
    password NVARCHAR(255) NOT NULL,
    created DATETIME,
    modified DATETIME
);

CREATE TABLE bookmarks (
    id INT IDENTITY(1,1) PRIMARY KEY,
    user_id INT NOT NULL,
    title NVARCHAR(50),
    description NTEXT,
    url NTEXT,
    created DATETIME,
    modified DATETIME,
    FOREIGN KEY (user_id) REFERENCES users(id)
);

CREATE TABLE tags (
    id INT IDENTITY(1,1) PRIMARY KEY,
    title NVARCHAR(255) UNIQUE,
    created DATETIME,
    modified DATETIME
);

CREATE TABLE bookmarks_tags (
    bookmark_id INT NOT NULL,
    tag_id INT NOT NULL,
    PRIMARY KEY (bookmark_id, tag_id),
    FOREIGN KEY (tag_id) REFERENCES tags(id),
    FOREIGN KEY (bookmark_id) REFERENCES bookmarks(id)
);
```

## Group Byの削除

これはMySQLだと大丈夫なのですかね？？
最後にBookmarksTable.phpに追加するfindTaggedメソッドの戻り値を修正します：

```php:BookmarksTable.php（findTaggedの一部）
        //return $bookmarks->group(['Bookmarks.id']);
        return $bookmarks;
```

# その他

ウェブサイトに設定した物理パスをFTPサイトに設定すれば、例えばローカルでPHPStormを使ってテスト環境サーバーに転送する、というような開発スタイルもできます。
だいたい満足ですが、SQLServerの接続関連の都合でbakeのみサーバーでやらないといけない状態になり、そこだけはちょっといまいち、、、
まあ、変な縛りがなければ、cakephpでWindows+SQLServerを使うという選択肢はあまり無いのでしょうが、、