Slimframework3でコマンドライン（CLI）

# はじめに

SlimframeworkはWebサーバーへのアクセスにしか使えないかと思いきや、コマンドラインで使うこともできます。
しかしそのためには一工夫が必要で、公式のドキュメントにも記載がなかったので調べました。

# 動いたコード

Slimframeworkのスケルトンをフォークしたものです。
[GitHub \- slimphp/Slim\-Skeleton: Slim Framework 3 skeleton application](https://github.com/slimphp/Slim-Skeleton)

2017/11/17追記:
ビルトインサーバー用の処理を削っていましたが、そのまま残すようにしました。

```php
<?php
if (PHP_SAPI !== 'cli') {
    echo 'CLI Only.';
    exit(1);
}

if (PHP_SAPI == 'cli-server') {
    // To help the built-in PHP dev server, check if the request was actually for
    // something which should probably be served as a static file
    $url  = parse_url($_SERVER['REQUEST_URI']);
    $file = __DIR__ . $url['path'];
    if (is_file($file)) {
        return false;
    }
}

require __DIR__ . '/../vendor/autoload.php';

session_start();

// Instantiate the app
$settings = require __DIR__ . '/../src/settings.php';
$argv = $GLOBALS['argv'];
array_shift($argv);
$pathInfo = implode('/', $argv);
$settings['environment'] = \Slim\Http\Environment::mock(
    [
        'REQUEST_URI' => '/' . $pathInfo,
    ]
);
$app = new \Slim\App($settings);

// Set up dependencies
require __DIR__ . '/../src/dependencies.php';

// Register middleware
require __DIR__ . '/../src/middleware.php';

// Register routes
require __DIR__ . '/../src/routes.php';

// Run app
$app->run();
```
上記のコードをcli.phpで保存したとします。
ファイル構成やコードの詳細は後述します。
これをシェルで実行させるとテンプレートのソースコードが標準出力に表示され、成功していることがわかります。

```:zsh
php cli.php /
```

```:zsh
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8"/>
        <title>Slim 3</title>
        <link href='//fonts.googleapis.com/css?family=Lato:300' rel='stylesheet' type='text/css'>
        <style>
            body {
                margin: 50px 0 0 0;
                padding: 0;
                width: 100%;
                font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
                text-align: center;
                color: #aaa;
                font-size: 18px;
            }

            h1 {
                color: #719e40;
                letter-spacing: -3px;
                font-family: 'Lato', sans-serif;
                font-size: 100px;
                font-weight: 200;
                margin-bottom: 0;
            }
        </style>
    </head>
    <body>
        <h1>Slim</h1>
        <div>a microframework for PHP</div>

        <?php if (isset($name)) : ?>
            <h2>Hello <?= htmlspecialchars($name); ?>!</h2>
        <?php else: ?>
            <p>Try <a href="http://www.slimframework.com">SlimFramework</a>
        <?php endif; ?>
    </body>
</html>

```

# コードの詳細

下記がコマンドライン実行のために入れた処理です。

```
$settings = require __DIR__ . '/../src/settings.php';
$argv = $GLOBALS['argv'];
array_shift($argv);
$pathInfo = implode('/', $argv);
$settings['environment'] = \Slim\Http\Environment::mock(
    [
        'REQUEST_URI' => '/' . $pathInfo,
    ]
);
```

Webでの実行と同様、パスからルーティングをしますが、実行させるファイル名自体はルーティングには必要ありません。
そのため、取り除くのですが、ファイル名は引数の配列の0番目です。
array_shiftをしているのはそのためです。

Slimframeworkは\$\_SERVER['REQUEST_URI']を解釈してルーティングします。
cli上で擬似的にこれを設定するために下記の設定を追加します。

```:php
$settings['environment'] = \Slim\Http\Environment::mock(
    [
        'REQUEST_URI' => '/' . $pathInfo,
    ]
);

```

# 余談

## 「cli-server」とは

Slim-Skeletonのpublic/index.phpに「PHP_SAPI == 'cli-server'」という記述があったのですが、
何のことかわからず、削除していました。
ビルトインサーバーで動いているとき、PHP_SAPIにcli-serverが設定されます。
名前が紛らわしいですが、コマンドラインからのアクセスではありません。
コマンドラインからphpを実行させたときはPHP_SAPIには「cli」が設定されます。