PHP Slim 環境構築(1) Hello, World

# PHP Slim 環境構築(1) Hello, World

## Introduction

docker-composeを使った、PHP [Slimフレームワーク](http://www.slimframework.com/)の構築を行いましたので、備忘録を兼ねて手順をまとめていきます。

## 材料

今回使用したものは、以下の通りです。なお、これらのインストール方法についてはこの記事では述べません。
なお、バージョン違い等によって動作が異なる場合がありますのでご注意願います。

- Ubuntu Desktop 18.04 LTS
- IntellilJ IDEA ULTIMATE 2019.2
- Docker 19.03.2
- docker-compose 1.23.2
- php (CLI) 7.2.19
- composer 1.9.0

## まずはHello, World

お約束ですが、Hello, Worldまで行ってみましょう。

### Dockerコンポーネント構成

フロントとなるnginxコンポーネント、バックエンドとして動くphp-fpmコンポーネントの二段構成です。

```
nginx(FrontEnd) - php-fpm(BackEnd)
```

- nginx (1.17.3)
- php (7.3.9)

### ソースツリー

完成後のソースツリーは、以下の通りになります。

```shell
$(PROJECTROOT)/
  compose/               - Dockerコンポーネントルート
    web_hoge/            - BackEndコンポーネント(php-fpm)
    web_front/           - FrontEndコンポーネント(nginx)
    docker-compose.yml   - docker-compose用定義ファイル
  src/                   - ソースルート
    hoge/                - ユーザソースコード
    vendor/              - Slimフレームワークなどのソースコード
    composer.json
    composer.lock
```

### ソースツリー構築

まず、プロジェクトルートを作成します。IDEで作るか、手動で作成して後でインポートするかはお好みで。
まず、プロジェクトルート下にソースのルートパスを作成し、slimフレームワークと、slimのpsr7実装をインストールします。

```shell
$ cd $(PROJECTROOT)
$ mkdir src
$ cd src
$ composer require slim/slim:4.2.0 slim/psr7:0.5.0
```

続いて、BackEnd側の"Hello, World"コードを作成します。echo "Hello, World"ではつまらないので、一応、slimフレームワークを使ってみます。

```shell
$ mkdir -p hoge/public
```

```PHP:/src/hoge/public/index.php
<?php

use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;

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

$app = AppFactory::create();

$app->get('/', function (Request $request, Response $response, $args) {
    $response->getBody()->write('Hello, World!');
    return $response;
});

$app->run();
```

次に、Dockerコンポーネントの作成です。まずディレクトリ作成。

```shell
$ cd $(PROJECTROOT)
$ mkdir compose
$ cd compose
$ mkdir web_hoge
$ mkdir web_front
```

続いて、docker-composeファイルの作成です。


```YML:/compose/docker-compose.yml
version: '3'

services:
  web_front:
    build:
      context: ./web_front
    links:
      - web_hoge
    ports:
      - "80:3128"
    container_name: web_front
    networks:
      - local_net

  web_hoge:
    build:
      context: ./web_hoge
      args:
        - environment=local
    domainname: localhost
    volumes:
      - ../src/hoge:/var/www/hoge
      - ../src/vendor:/var/www/vendor
    container_name: web_hoge
    networks:
      - local_net

networks:
  local_net:
    driver: bridge
    ipam:
      driver: default
      config:
        - subnet: 172.28.0.0/24
```

FrontEnd dockerコンポーネントのDockerfileです。docker-composeでマウントしているvolumeのuid/gidが1000/1000なので、dockerの中からwww-dataがオーナになるように、www-dataユーザを作り直しています。

```dockerfile:/compose/web_front/Dockerfile
FROM nginx:1.17.3

COPY default.conf /etc/nginx/conf.d/default.conf

RUN deluser www-data \
    && addgroup --system --gid 1000 www-data \
    && adduser --system --home /var/www --no-create-home --uid 1000 --gid 1000 \
       --disabled-password --disabled-login --shell /usr/sbin/nologin www-data

EXPOSE 3128
```

続いて、FrontEndのnginxの設定ファイルです。
hoge.localhostでアクセスすると、FrontEndコンポーネントの方にアクセスするようにしています。

```conf:/compose/web_front/default.conf
server {
  listen 3128;
  server_name hoge.localhost;
  access_log /dev/stdout;
  error_log /dev/stderr;
  root /var/www/hoge/public;

  location / {
    try_files $uri $uri/ /index.php?$query_string;
    index     index.php;
  }

  location ~ \.php$ {
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass web_hoge:9000;
    fastcgi_index index.php;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param PATH_INFO $fastcgi_path_info;
  }
}

server {
  listen 3128 default_server;
  server_name _;

  location / {
    return 404;
  }
}
```

hoge.localhostを/etc/hostsに定義しておきます。

```conf:/etc/hosts
127.0.0.1  hoge.localhost   (追加)
```

FrontEnd側のDockerfileです。ひとまず使いそうなextensionを入れてしまっていますが、実際にはextensionの増減が必要です。
なお、environmentがlocalのときだけxdebugを有効にしています(docker-compose.ymlのargs/environment参照)。

また、redisモジュールのインストールだけソースから行っていますが、これは、redisのシリアライズにigbinaryを有効にするためです。

```Dockerfile:compose/web_hoge/Dockerfile
FROM php:7.3.9-fpm-alpine3.10

ARG environment

RUN apk upgrade --update \
  && apk --no-cache --virtual .build-deps add make g++ gcc re2c autoconf \
  && apk --no-cache add gettext-dev libzip-dev curl-dev \
  && docker-php-ext-install -j$(nproc) gettext mbstring zip opcache ctype json bcmath sockets curl \
  && pecl channel-update pecl.php.net

# PDO(MySQL)
RUN docker-php-ext-install -j$(nproc) pdo_mysql

# PDO(PostgreSQL)
RUN apk --no-cache add postgresql-dev \
  && docker-php-ext-install -j$(nproc) pdo_pgsql

# YAML (2.0.4)extension=yaml.so
RUN apk --no-cache add yaml-dev \
  && pecl install yaml-2.0.4 \
  && docker-php-ext-enable yaml

# APCu (5.1.17)  extension=apcu.so
RUN pecl install apcu-5.1.17 \
  && docker-php-ext-enable apcu

# igbinary (3.0.1) extension=igbinary.so
RUN pecl install igbinary-3.0.1 \
  && docker-php-ext-enable igbinary

# msgpack (2.0.3) extension=msgpack.so
RUN pecl install msgpack-2.0.3 \
  && docker-php-ext-enable msgpack

# redis (5.0.2) extension=redis.so  (igbinary enabled)
RUN curl -fsSL https://github.com/phpredis/phpredis/archive/5.0.2.tar.gz -o redis.tar.gz \
  && mkdir -p /usr/src/php/ext/redis \
  && tar xzf redis.tar.gz -C /usr/src/php/ext/redis --strip-components=1 \
  && rm redis.tar.gz \
  && docker-php-ext-configure redis --enable-redis-igbinary \
  && docker-php-ext-install -j$(nproc) redis

# xdebug(2.7.2) extension=xdebug.so
RUN if [ "${environment}" = "local" ]; then \
     pecl install xdebug-2.7.2 \
  && docker-php-ext-enable xdebug \
  && echo "xdebug.remote_enable=1" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini \
  && echo "xdebug.remote_connect_back=0" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini \
  && echo "xdebug.remote_autostart=0" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini \
  ; fi

RUN apk del --purge .build-deps \
  && docker-php-source delete \
  && rm -rf /var/cache/apk/* \
  && rm -rf /tmp/*

RUN deluser www-data \
    && addgroup -g 1000 -S www-data \
    && adduser -u 1000 -D -S -G www-data www-data
```

### ビルド

では、ビルドしてみましょう。

```shell
$ cd $(PROJECTDIR)/compose
$ docker-compose build
```

問題なさそうなら、up!

```shell
$ docker-compose up -d
```

ローカルのブラウザから、http\://hoge.localhost/にアクセスすると、"Hello, World!"が表示されるはずです。
なお、ルーティングは"/"しか設定していないので、http\://hoge.localhost/fugafugaとか入力すると、errorが出てしまいます。

## Changes

[2019/9/19]
- web_hoge/DockerfileのPHPextから、mysqliを削除、pdo_mysqlとpdo_pgsqlを追加