PHPで言語処理100本ノック 2015(第2章:前半)

www.cl.ecei.tohoku.ac.jp

10. 行数のカウント

<?php
echo substr_count(file_get_contents($argv[1]), "\n");
echo "\n";

確認

$ wc -l hightemp.txt

11. タブをスペースに置換

<?php
echo str_replace("\t", " ", file_get_contents($argv[1]));

確認

$ expand -t 1 hightemp.txt

12. 1列目をcol1.txtに,2列目をcol2.txtに保存

<?php
$col1 = '';
$col2 = '';
$explodedByNLC = explode("\n", file_get_contents($argv[1]));
foreach ($explodedByNLC as $index => $row) {
    if ($index === count($explodedByNLC) - 1) {
        break;
    }
    $explodedByTab = explode("\t", $row);
    $col1 .= $explodedByTab[0]."\n";
    $col2 .= $explodedByTab[1]."\n";
}
file_put_contents('./col1.txt', $col1, LOCK_EX);
file_put_contents('./col2.txt', $col2, LOCK_EX);

確認

$ cut -f 1 hightemp.txt > col1_sh.txt
$ cut -f 2 hightemp.txt > col2_sh.txt

13. col1.txtとcol2.txtをマージ

<?php
$result = '';
$col1 = explode("\n", file_get_contents($argv[1]));
$col2 = explode("\n", file_get_contents($argv[2]));
foreach ($col1 as $index => $row) {
    if ($index === count($col2) - 1) {
        break;
    }
    $result .= $row . "\t" . $col2[$index] . "\n";
}
file_put_contents('./13.txt', $result, LOCK_EX);

確認

$ paste col1.txt col2.txt > 13_sh.txt

14. 先頭からN行を出力

<?php
for($i = 0; $i < $argv[2]; $i++) {
    echo explode("\n", file_get_contents($argv[1]))[$i]."\n";
}

確認

$ head -n 7 hightemp.txt

セットアップしたばかりのSymfony4をHerokuにデプロイしてみる

devcenter.heroku.com

すべてドキュメント通り、というわけにはいかないため、所々変えていかなければいけない。

Heroku CLIをインストールしておく。

$ brew install heroku/brew/heroku

Symfony4プロジェクトを作成。

$ composer create-project symfony/skeleton my-app

Heroku上にアプリケーションを作成する。
タイムゾーンも変えておく。

$ cd ./my-app
$ heroku login
$ heroku create my-app
$ heroku config:add TZ=Asia/Tokyo

プロダクション環境として動作させるために環境変数を設定する。

How to Master and Create new Environments (Symfony Docs)

$ heroku config:set APP_ENV=prod

Procfile を作る。
ここではNginxで動かす想定。
あとで作成するNginxのconfファイルを読み込むように記述する。
Symfony4は web/ ではなく public/ なので注意。

$ echo 'web: $(composer config bin-dir)/heroku-php-nginx -C nginx_app.conf public/' > Procfile

nginx_app.conf を作成して、Nginxの設定を書き込む。

Customizing Web Server and Runtime Settings for PHP | Heroku Dev Center

とりあえず、こんな感じ。

location / {
    try_files $uri /index.php$is_args$args;
}

location ~ ^/index\.php(/|$) {
    fastcgi_pass heroku-fcgi;
    fastcgi_split_path_info ^(.+\.php)(/.*)$;
    include fastcgi_params;

    fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
    fastcgi_param DOCUMENT_ROOT $realpath_root;

    internal;
}

location ~ \.php$ {
    return 404;
}

これで一通りできた。
Herokuにデプロイする。

$ git add .
$ git commit -m "comment."
$ git push heroku master

実は、まだこの状態だとアクセスしても500エラーとなり、おそらく真っ白な画面が表示される。
これは本番環境の場合、ルーティングが全く定義されていないとエラーになってしまうから(開発環境だとウェルカムページが表示される)。

tomcky.hatenadiary.jp

なので、以下を参考にコントローラを作成し、ちょっとしたページを1つでも作っておかないといけない。

Create your First Page in Symfony (Symfony Docs)

もしくは、手っ取り早く試しにデプロイできているかだけでも確認したい場合は、環境変数をdevにする。

$ heroku config:set APP_ENV=dev

これで、ページが表示されるはず。

Symfony4のウェルカムページはどうやって表示されているのか

Symfony4プロジェクトを作成するときはSymfony Skeletonを使用することが推奨されている。

symfony.com

Symfony Skeletonは最小限、かつ空のSymfonyプロジェクトを生成するのだが、あまりに空っぽ過ぎてControllerすら1つも作成されない。
php bin/console debug:router とすると、1つもルーティングが定義されていないことがわかる。

 ------ -------- -------- ------ ------
  Name   Method   Scheme   Host   Path
 ------ -------- -------- ------ ------

しかし、この状態でもウェルカムページはちゃんと表示される。
一体どうやってウェルカムページを表示しているのか。

ウェルカムページを表示する処理はSymfony本体 vendor/symfony/http-kernel/EventListener/RouterListener.php に記述されている。

<?php
// vendor/symfony/http-kernel/EventListener/RouterListener.php
// ...
try {
    // ...
} catch (ResourceNotFoundException $e) {
    if ($this->debug && $e instanceof NoConfigurationException) {
        $event->setResponse($this->createWelcomeResponse());

        return;
    }
}
// ...
private function createWelcomeResponse()
{
    $version = Kernel::VERSION;
    $baseDir = realpath($this->projectDir).DIRECTORY_SEPARATOR;
    $docVersion = substr(Kernel::VERSION, 0, 3);

    ob_start();
    include __DIR__.'/../Resources/welcome.html.php';

    return new Response(ob_get_clean(), Response::HTTP_NOT_FOUND);
}

ResourceNotFoundException が発生したときに、それがデバッグ環境で、かつ NoConfigurationException インスタンスだった場合に、ウェルカムページを作成して返していることがわかる。

NoConfigurationExceptionResourceNotFoundException を継承しており、 UrlMatcher#match のなかで、ルーティング定義がなく、かつトップページにアクセスしたときにthrowされる。

<?php
// vendor/symfony/routing/Matcher/UrlMatcher.php
// ...
public function match($pathinfo)
{
    // ...
    if (0 === count($this->routes) && '/' === $pathinfo) {
        throw new NoConfigurationException();
    }
    // ...
}

これがウェルカムページ表示の仕組み。

ちなみにこの実装から、"prod環境にするとウェルカムページは表示されずエラーが発生するのではないか"ということが推測できる。
実際にやってみる。

# .env
#...
# APP_ENV=devをprodにする
APP_ENV=prod
#...

トップページにアクセスしてみる。

Fatal error: Uncaught Symfony\Component\Routing\Exception\NoConfigurationException in ...

推測どおりエラーになった。