1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【独習PHP第4版】本書の環境XAMPPをDockerで実現

Last updated at Posted at 2023-02-19

『独習PHP第4版』の環境構築はXAMPPですが、既にDockerをインストールしていたため。これで一冊最後まで学習ができたので記録。

目次

1.先にまとめ
2.起動したら必ずやること
3.dockerのため本書と違うところ

1. 先にまとめ

【使用環境】
・OS : Windows10
・Docker Desktop : 4.16.2
・Docker Engine: 20.10.22
・WSL2(Ubuntu) : Ubuntu 20.04.5 LTS (Focal Fossa)
・VSCode : 1.75.0

全体図

selfphp
  |---mariadb
  |    |___data                         //空ディレクトリ
  |    |___Dockerfile
  |---php
  |    |___docker-php-ext-xdebug.ini
  |    |___Dockerfile
  |    |___myphp.ini
  |---web                               //ドキュメントルート(後述)。PHPのコードはこの下に。
  |    |___parts                        //呼び出して使う関数はここに保管
  |    |     |___DbManager.php          //PHPとデータベースを接続するためのファイル
  |    |___index.php                    //好きに作業する
  |___docker-compose.yml

MariaDB(MySQL)

Dockerfile
FROM mariadb:10.7.7-focal
EXPOSE 3306

MySQLの場合はFROM mysql:8.0-debianとした。

PHP

docker-php-ext-xdebug.ini
[xdebug]
zend_extension=xdebug
xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.client_host=host.docker.internal
;デバッグを実行すると、PHPコンテナ内の/tmp/xdebug.logにログが出力される。
xdebug.log=/tmp/xdebug.log
xdebug.client_port=9003
Dockerfile
FROM php:8.2-rc-apache
# ① 「user」という名の一般ユーザーを作成。
ARG USERNAME=user
ARG GROUPNAME=user
ARG UID=1000
ARG GID=1000
RUN groupadd -g $GID $GROUPNAME && \
    useradd -m -s /bin/bash -u $UID -g $GID $USERNAME
# ②「libzip-dev」「unzip」「pdo_mysql」「zip」「xdebug」「mhsendmail」をインストール&有効化
RUN apt-get update \
  && apt-get install -y --no-install-recommends libzip-dev unzip \
  && docker-php-ext-install pdo_mysql zip \
  && pecl install xdebug \
  && docker-php-ext-enable xdebug \
  && curl -sSL https://github.com/mailhog/mhsendmail/releases/download/v0.2.0/mhsendmail_linux_amd64 -o mhsendmail \
  && chmod +x mhsendmail \
  && mv mhsendmail /usr/local/bin/mhsendmail
# ③ ComposerをPHPコンテナ内に取り入れる
COPY --from=composer/composer:latest-bin /composer /usr/bin/composer
# ④ 自作の設定ファイル「myphp.ini」「docker-php-ext-xdebug.ini」をPHPコンテナに適用させる
COPY myphp.ini /usr/local/etc/php/conf.d
COPY docker-php-ext-xdebug.ini /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
# ⑤ PHPコンテナ内に入った時のカレントディレクトリを指定
WORKDIR /var/www/html
EXPOSE 80

【参考】
https://qiita.com/Spritaro/items/602118d946a4383bd2bb
Composer公式ドキュメント「Docker Image」の項にて。イメージはdockerが提供している「composer」でなく、Composer公式の「composer/composer」を使用。『dockerのイメージは、公式が直接公開したものではないので、最新版を受け取るのに数日遅れる。バイナリのみの同等のものがない』らしい。

myphp.ini
[Core]
sendmail_path = "/usr/local/bin/mhsendmail --smtp-addr=mailhog:1025"
[Date]
date.timezone = "Asia/Tokyo"
[mbstring]
mbstring.language = "Japanese"
[Session]
;session使用時、実データがPHPコンテナ内の/tmp下に保存される。
session.save_path = "/tmp"
;以下は、本書で紹介されている「推奨値」を設定。
session.cookie_httponly = "On"
session.cookie_samesite = "Lax"
session.sid_length = "48"
session.sid_bites_per_character = "6"
session.use_strict_mode = "On"

web

DbManager.php
<?php
$dsn = 'mysql:dbname=selfphp; host=db; charset=utf8';
$usr = 'root';
$passwd = 'myrootpassword';
try {
  $db = new PDO($dsn, $usr, $passwd);
  print '接続に成功しました。';
}catch (PDOException $e) {
  die("接続エラー:{$e->getMessage()}");
} finally {
  $db = null;
}

このコードは『独習PHP第4版』から拝借。

docker-compose.yml

docker-compose.yml
version: '3'
services:
  app:
    build:
      context: ./php
      dockerfile: Dockerfile
    volumes:
      - type: bind
        source: "./web"
        target: "/var/www/html"
    ports:
      - "80:80"
    depends_on:
      - db
  db:
    build:
      context: ./mariadb
      dockerfile: Dockerfile
    volumes:
      - type: bind
        source: "./mariadb/data"
        target: "/var/lib/mysql"
    ports:
      - "3306:3306"
    environment:
      # MySQLのイメージを使用するなら、環境変数は「MYSQL_ROOT_PASSWORD」に。
      - MARIADB_ROOT_PASSWORD=myrootpassword
  mailhog:
    image: mailhog/mailhog
    ports:
      - "8025:8025"
  • 通常の起動・停止
    docker-compose up -dで起動、 docker-compose downで停止。この起動はキャッシュを使うので、もしファイルを修正したら、起動時はdocker-compose up -d --buildでビルドから始める。
  • コンテナ名
    docker-composeコマンドで起動したら、コンテナ名は「作業中のディレクトリ名-コンテナ名-1」となる。例えばPHPコンテナ名は「selfphp-app-1」。(docker psで確認可)
  • ウェブ上で表示できるか確認する
    index.phpにアクセスするには「http://localhost:80/index.php」。
    web/var/www/htmlのマウントによって、ウェブで公開する部分(ドキュメントルート)を設定している。(PHPイメージのドキュメント「php:<version>-apache」の項にて)
    image.png
    ・ ブラウザ上でのパスを確認したいなら、print __FILE__;で出力するとよい。
  • mariadb/data/var/lib/mysqlのマウント
    データを保持するため。MariaDBイメージのドキュメントより「Where to Store Data」の項。コンテナを停止する度にコンテナは削除される。データベースやテーブルなどのデータは、MariaDBコンテナ内で作成するのでデータも都度消えてしまう。マウントすることでデータを常に保持できる。
  • コンテナ内に入る。docker exec -it コンテナ名 /bin/bash
  • PHPコンテナ内での作業
    ・ Composerを使ってパッケージをインストールする時。
    ・ sessionが正しく機能しているかチェックする時(コンテナ内の/tmplsで確認)。
    ・ デバッグのログを見たい時(コンテナ内の/tmp/xdebug.logに出力される)。
  • MariaDBコンテナ内での作業
    ・ データベースやテーブルを作成したり、SQLを実行する時。
    PHPとデータベースを接続するためにIPアドレスを確認する時。

2. 起動したら必ずやること

①launch.jsonに"pathMappings"を追記する。
(②zend_extensionの値を書き直す。)
③PHPとデータベースを接続する時、DockerではhostのIPアドレスを毎回確認する。
④Composerを利用する時は、PHPコンテナにユーザーを指定して入る。

簡単です!

①launch.jsonに"pathMappings"を追記する。

これはデバッグを実行するために必要な作業。
事前に、VSCodeの拡張機能をインストールする所から「PHP Debug」を検索し、インストールしておく。
image.png
(1)初めての方は、虫マーク→「create a launch.json file.」→「PHP」を選択。selfphp下に.vscode/launch.jsonファイルが自動作成される。
image.png
(2)launch.jsonファイルを見て、portが「9003」であることを確認。
image.png
そしてこの"port: 9003"の下に以下のコードを追記。

launch.json
      "pathMappings": {
        "/var/www/html":"${workspaceFolder}/web"
      }
  • 左側(/var/www/html)はPHPコンテナのドキュメントルートのパス。
  • 右側(${workspaceFolder}/web)は作業中のドキュメントルートのパス。
    docker-compose.ymlファイルからも分かるように、/var/www/htmlとマウントしている部分。${workspaceFolder}は今、VSCodeで開いているディレクトリ(selfphpディレクトリ)。
    ▼【完成したlaunch.json
    image.png
    (3)正しくデバッグできるか確認する。
    簡単にチェック用のindex.phpを作成する。このコードは『独習PHP第4版』から拝借。
index.php
<?php
$msg = 'こんにちは、世界!';
print $msg;

デバッグしたいファイルindex.phpを開いた状態で虫マーク→「Listen for Xdebug」であることを確認して横の三角をクリック(デバッグ開始)。
image.png
↓このマークが出る。ちなみに終了は一番右の四角をクリック。
image.png
index.phpのコード左側をクリックしてブレークポイントを設置。ブレークポイントの行は実行せず、一時停止する。
image.png
ブラウザからhttp://localhost:80/index.phpindex.phpにアクセス→VSCodeに戻る。下のようにブレークポイントで止まっていればOK。
image.png
ブレークポイントの行は実行されずに止まるので、$msgの値はまだ初期化されていないと出る。これでデバッグは問題なく使用できる。

【参考】
https://zenn.dev/ikeo/articles/244d6a8042bcd8c55fe9
https://qiita.com/gigosa/items/90431be7a6a79db78480

(②zend_extensionのパスを書き換える)

  • Xdebug公式のドキュメント「Configure PHP」の項にて、もしXdenugが表示されなかったり、ファイルが見つからないと出たらXdebugのファイルパスを明示的に設定する。
  • PHPコンテナ内に入り、cd/usr/local/lib/php/extensionsあたりまで行く。lscdで追ってパスを確認する。
docker-php-ext-xdenug.ini
[xdebug]
zend_extension=xdebug

docker-php-ext-xdenug.ini
[xdebug]
zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20210903/xdebug.so

ファイルを変更したので、Dockerを停止→docker-compose up -d --buildで起動する。

③PHPとデータベースを接続する時、DockerではhostのIPアドレスを毎回確認する。

こんなことしなくてもよいみたいです。
hostの部分は、MariaDbコンテナの「IPアドレス」ではなく「コンテナ名」を書けばOK。コンテナ名は、docker-compose.ymlファイルのservicesにある。ここでMariaDbコンテナをdbと名付けた。正式名selfphp-db-1を使ってもどちらでもよい。
【修正前】host=172.19.0.2
【修正後】host=db

DbManager.php
<?php
$dsn = 'mysql:dbname=selfphp; host=db; charset=utf8';
$usr = 'root';
$passwd = 'myrootpassword';
try {
  $db = new PDO($dsn, $usr, $passwd);
  print '接続に成功しました。';
}catch (PDOException $e) {
  die("接続エラー:{$e->getMessage()}");
} finally {
  $db = null;
}

hostにはMariaDbコンテナのIPアドレスを書く。起動すると変わることがあるので毎回確認する。
(1)起動後、docker exec -it selfphp-db-1 /bin/bashでMariaDBコンテナに入る。
(2)cat /etc/hostsで確認。

127.0.0.1       localhost
         ~省略~
172.23.0.2      12ab34cd56ef    ←こっち。つまり172.23.0.2をhostに書く。

一番下、MariaDBのコンテナIDと共に表示されている方のIPアドレス。同じものをhostに書く。

  • mysql:dbname=selfphpの「selfphp」とは、MariaDBで作成したデータベース名。Dockerの場合、MariaDBコンテナに入る→mariadb -p(MySQLの場合はmysql -p)→パスワード入力(docker-compose.ymlMARIADB_ROOT_PASSWORDで設定済)でMariaDBを起動。CREATE DATABASE selfphp;でデータベースを作成。テーブルも作っておく。
  • $passwdは、先ほど入力したパスワード。

(3)http://localhost:80/parts/DbManager.phpでファイルにアクセスし、「接続に成功しました。」が出ればOK。

④Composerを利用する時は、PHPコンテナにユーザーを指定して入る。

Composerを利用する時は、docker exec -it -u user selfphp-app-1 /bin/bashでPHPコンテナに入ること。

  • コンテナに入る時は、-u(--user) userでユーザーを指定しないとrootユーザーで入ることになる。 そのため、コンテナ内で作業して作られたファイルなどが全てroot権限で、後で全く編集できなくなり困った。
  • そもそもComposerのドキュメントにrootで実行するなと書かれている。なので、PHPのDockerfileで「user」という名のユーザーを作成した。これがないとrootでしか入れない。
  • ちなみにroot権限で作業してしまい、ファイルが編集できなくて詰んだ時は…userに権限を変更する。以下のコマンドをそのまま実行。
    (1)chown -R user:user ./
    カレントディレクトリ下の使用者権限を全て変更。user:userの部分は、ユーザー名:グループ名。
    (2)find . -type f -print | xargs chmod 644
    カレントディレクトリ下の、ファイルの実行権限を全て644に変更。
    (3)find . -type d -print | xargs chmod 755
    カレントディレクトリ下の、ディレクトリの実行権限を全て755に変更。

【参考】https://cpoint-lab.co.jp/article/202206/22876/

3. dockerのため本書と違うところ

①mb_send_mail()を使ってメール送信

※ 本書では、XAMPPに元から入っている「sendmail」を使って実際にメールを送信しますが、僕の知識不足のため、導入が簡単な「MailHog」と「mhsendmail」を使いました。学習に支障はありませんが、本書通りにできたら追記します(検証中)。
※ もし「sendmail」を使いたい方は、PHPコンテナにインストールする必要があるので、PHPのDockerfileに「sendmail」を追記してください。

Dockerfile
~ 省略 ~
apt-get install -y --no-install-recommends libzip-dev unzip sendmail \

MailHogの使い方は簡単

  • 「MailHog」は、PHPのアプリでメール機能をつける時、mb_send_mail関数を使う時などで、実際にメールが届いた側としてメールの状況を確認できる(本文の表示崩れなど)。
  • 実際の宛先には送信せず、「MailHog」に送信する。「MailHog」にメールを送信するために「mhsendmail」が必要なので、両方インストール。「sendmail」でも可能らしいが未検証。

(1)http://localhost:8025で「MailHog」を開く。ここで受信したメール、メールヘッダーが確認できる。
(2)mb_send_mail関数で、メールを送信するファイルを作成(本書に手順があるので省略)

本書の書き方と変えた所

  • mb_send_mail関数のメールヘッダー($headers)は配列で渡した。PHP7.2以降から可能。これはメールヘッダーインジェクションの防止になる。
  • メールヘッダー($headers)の配列に'Content-Type'=>'text/plain; charset=UTF-8', 'Content-Transfer-Encoding'=>'8bit'を追記。mb_send_mail関数で送信した文字コードは日本語(ISO-2022-JP)だったが、「MailHog」では文字化けするので、UTF-8を指定した。

【参考】https://teratail.com/questions/318732

(3)そのファイルにアクセスする。または、PHPコンテナ内に入ってphp ファイル名で実行する。→(1)「MailHog」を見る。

  • Fromヘッダーの値の書き方
    ①差出人の名前で表示したい・・・差出人名<from@example.com>
    ②メールアドレスで表示する・・・from@example.com
    こんな感じで届きます↓
    image.png

②PHPDocの使い方

  • PHPDocumentor(以下PHPDoc)は、コードから自動で必要な情報を取り出し、仕様書として整形してくれる。
  • 整形したいファイルにあらかじめドキュメンテーションコメントを書く必要があるが、書き方は本書やドキュメントなどにあるので省略。

インストールの方法は3つ

  1. dockerイメージを使う。→僕はDockerなのでこの方法
  2. Phiveを使い、依存関係としてインストールする。
  3. PHARファイル(.phar)をダウンロードし、好みの場所に配置する。→本書はこの方法

※Composerを使ってもインストールできるが非推奨。PHPDoc側とこちら側の依存関係でコンフリクトが起こる可能性がある。

PHPDocのdockerイメージを使う

(1)このツールを使用すると、いくつかディレクトリが作成されるので、1つにまとまっていた方が綺麗だなー…と思い、webディレクトリにphpdocディレクトリを作った( (3)の図)。ここをカレントディレクトリとして作業する。
(2)カレントディレクトリで以下のコマンドを実行。エイリアス(別名)を作成。
alias phpdoc="docker run --rm -v $(pwd):/data phpdoc/phpdoc:3"

  • 自作したコマンド「phpdoc」だけでPHPDocコンテナの起動/マウント/削除を行う。「=」の前後にスペースを入れないこと!
  • このエイリアスはその場限りで、エディタを閉じると設定が消えるので注意。aliasと打つと、設定したエイリアス一覧を確認できる。すると、$(pwd)の部分が絶対パスに置き換わっている。

(3)カレントディレクトリに、「doc」「out」というディレクトリを作成する。
「doc」には、ドキュメンテーションコメントを書いたファイルを置こう。

selfphp
   :
   |___web
   |    |___phpdoc(カレントディレクトリ)
   |          |___doc             //ドキュメント化したいファイルはここに置く。
   |          |    |___ファイル1
   |          |    |___ファイル2
   |          |___out             //空ディレクトリ。作成されたドキュメントが自動でここに入る
   :

(4)カレントディレクトリでphpdoc -d doc -t -outを実行する。

  • -dは、ドキュメント化したいファイルが入っているディレクトリ。
  • -fでファイルを指定することもできる。
  • -tは、生成されたドキュメントを入れる場所(ディレクトリ)。Target Folderと呼ぶ。

【参考】
https://docs.phpdoc.org/3.0/guide/guides/running-phpdocumentor.html

(5)「out」下に作成された、index.htmlにアクセスする。すると自分で作ったファイルがドキュメント化されている。

以上となります。最後まで読んでいただき、ありがとうございました。

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?