CakePHP2系の環境構築手順

# はじめに
この記事では、CakePHP2系の環境構築手順を解説します。
以前、私はCakePHP2系の案件に参画しておりました。
案件参画前にプライベートで学習しようと思い、下記の手順で自身のPCにCakePHP2系の環境を構築しました。
記事投稿時点(2024年時点)では、CakePHPの最新バージョンは5系で、2系は既にサポート終了しております。
非常にレガシーな技術であるため、正直下記の情報は役に立たない可能性が高いと予想しておりますが、念のため備忘録として残しております。

# 各技術とバージョン

- PHP 5.6
- MySQL 5.7
- CakePHP 2.10
- MacOS

# ゴール設定

Dockerを用いてCakePHP 2系の環境構築を行い、ウェルカムページが正常に表示されている状態を目指す。
↓ エラーありのウェルカムページと、エラーなしのウェルカムページの比較
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/935364/5c6492b3-c2a0-226f-6f5c-739141407498.png" width="50%"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/935364/e2dd5f4b-46ac-9a3f-e957-327e997b61c0.png" width="50%">

# 環境構築手順

## 前提

ディレクトリ構成は次の通り。

```
プロジェクト名/
|-- Dockerfile
|-- docker-compose.yml
|-- src/
```

`src`ディレクトリの配下にCakePHPのプロジェクトを格納する。

## 準備

プロジェクト直下に`Dockerfile`, `docker-compose.yml`, `src`ディレクトリを作成する。

```docker
# php:5.6-apacheベースのイメージを使用
FROM php:5.6-apache

# 必要なPHP拡張をインストール
RUN docker-php-ext-install pdo pdo_mysql

# Apacheのmod_rewriteを有効化
RUN a2enmod rewrite

# .htaccessの使用を許可するためのApache設定変更
RUN sed -i 's/AllowOverride None/AllowOverride All/' /etc/apache2/apache2.conf

# アプリケーションのファイルをコンテナにコピー
COPY src/ /var/www/html/

# Apacheのドキュメントルートを変更
ENV APACHE_DOCUMENT_ROOT /var/www/html/src/webroot

# PHPのタイムゾーン設定
RUN echo "date.timezone=Asia/Tokyo" > /usr/local/etc/php/conf.d/timezone.ini

# DebianのaptリポジトリのURLをアーカイブ版に変更し、stretch-updatesを削除
RUN sed -i -e 's/deb.debian.org/archive.debian.org/g' \
           -e 's|security.debian.org|archive.debian.org/|g' \
           -e '/stretch-updates/d' /etc/apt/sources.list

# 必要なツールと拡張のインストール (zip, unzip, git)
RUN apt-get update && apt-get install -y \
    unzip \
    git \
    libzip-dev \
 && docker-php-ext-install zip

# Composerのインストール
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
```

```yaml
version: "3"

services:
  web:
    build:
      context: .
      dockerfile: Dockerfile
    volumes:
      - ./src:/var/www/html
    ports:
      - "8000:80"
    depends_on:
      - db
    environment:
      - DATABASE_URL=mysql://root:password@db/my_database

  db:
    image: mysql:5.7
    platform: linux/x86_64 # M1用に追加
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: my_database
    volumes:
      - db_data:/var/lib/mysql

volumes:
  db_data:
```

```
mkdir src
```

## Docker

1. `docker-compose up -d`
   `docker-compose.yml`に定義されたサービスをバックグラウンドで起動する。必要なイメージがローカルに存在しない場合、自動的にそのイメージをビルドする。
   <details><summary>docker-compose up -dで失敗する場合は、下記の手順を行う。</summary>

   1. Docker Desktopにて、関連するContainers, Images, Volumesを全て削除する。
   2. `src`ディレクトリを削除し、再度そのディレクトリを作成する。
      コマンドで行う場合は、`rm -r src`と`mkdir src`を実行する。
   3. `docker-compose build --no-cache`を実行する。
   4. `docker-compose up -d`を実行する。
   </details>
2. `docker ps`
   実行中のDockerコンテナの一覧を表示する。
   `プロジェクト名-web-1`コンテナの CONTAINER ID を確認する。
3. `docker exec -it {コンテナID} bash`
   `プロジェクト名-web-1`コンテナの中で bash シェルを開始する。

:::note warn
以降、実行するコマンドは全て`プロジェクト名-web-1`コンテナの中で実行すること。
:::

## CakePHP 2インストール

CakePHP 2をcomposerを用いてインストールする。
```
composer create-project --prefer-dist cakephp/cakephp:^2 .
```

## DebugKitインストール

1. `composer/installers`をインストール
   特定のタイプのパッケージのインストールパスをカスタマイズできる。
   ```
   composer require composer/installers
   ```
   下記のメッセージが表示されたら、`y`を入力し、Enterを押す。
   ```
   Do you trust "composer/installers" to execute code and wish to enable it now? (writes "allow-plugins" to composer.json) [y,n,d,?]
   ```

2. `composer.json`にインストールパスを追加
   `composer config`コマンドを使用して設定を追加する。
   ```
   composer config extra.installer-paths.app/Plugin/\{\$name\}/ type:cakephp-plugin
   ```
   このコマンドを実行すると、`composer.json`の`extra`セクションにインストールパスが追加される。

3. DebugKitをcomposerを用いてインストール
   ```
   composer require cakephp/debug_kit "2.*"
   ```

4. `bootstrap.php`を変更
   `app/Config/bootstrap.php`を開き、`CakePlugin::load('DebugKit');`のコメントアウトを外す。

   ```php
   /**
    * Plugins need to be loaded manually, you can either load them one by one or all of them in a single call
    * Uncomment one of the lines below, as you need. Make sure you read the documentation on CakePlugin to use more
    * advanced ways of loading plugins
    *
    * CakePlugin::loadAll(); // Loads all plugins at once
    */
   CakePlugin::load('DebugKit'); // Loads a single plugin named DebugKit
   ```

## `Security.salt`と`Security.cipherSeed`の変更
`Security.salt`と`Security.cipherSeed`に関して、CakePHPのデフォルトの値が設定されていると、セキュリティ上の理由で警告メッセージが表示される。そのメッセージを解消するためには、`app/Config/core.php`を変更する必要がある。

```php
/**
 * A random string used in security hashing methods.
 */
	Configure::write('Security.salt', 'random_string_here');

/**
 * A random numeric string (digits only) used to encrypt/decrypt strings.
 */
	Configure::write('Security.cipherSeed', 'random_number_here');
```

1. ランダムな文字列と数字列を生成
    ChatGPT を活用して、値を生成するのが手軽。
    <details><summary>ChatGPT用プロンプトと出力結果</summary>

    ### プロンプト
    ``````
    1. 半角英数字(大文字可)を用いて、40文字のランダムな文字列を作成してください。
    2. 半角数字を用いて、30文字のランダムな数字列を作成してください。
    
    下記のフォーマットで出力してください。
    
    # 1. 文字列
    ```
    // 生成した文字列
    ```
    
    # 2. 数字列
    ```
    // 生成した数字列
    ```
    ``````

    ### 出力結果
    ![image_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/935364/1add5c13-90ae-ce7f-fbd5-4f5e060893a6.png)
    </details>

2. 生成した値を`core.php`に反映
   ChatGPT で作成したランダムな文字列と数字列を`app/Config/core.php`の`Security.salt`と`Security.cipherSeed`に反映する。
   ※ 下記の文字列と数字列はあくまで例なので、実際に記載する値は各自作成してください。
   ```php
   /**
    * A random string used in security hashing methods.
    */
   	Configure::write('Security.salt', 'Hk8ZjE5p7rYlQmLXa2GwDfRtUoI1e0vSs6Cn3');

   /**
    * A random numeric string (digits only) used to encrypt/decrypt strings.
    */
   	Configure::write('Security.cipherSeed', '739264158027461935802746139580');
   ```

## `database.php`を作成、変更

CakePHP 2では、データベースの設定は`app/Config/database.php`に記述されるが、初期の状態では`app/Config/database.php.default`というファイルが提供されており、それを元に実際の設定を行う。

1. `database.php.default`をコピーし、`database.php`を作成
   下記のコマンドを実行する。

   ```
   cp app/Config/database.php.default app/Config/database.php
   ```

2. `$default`の配列の中身を変更
   `database.php`を開き、`$default`の配列の中身を変更する。
   ```php
   // 略

   class DATABASE_CONFIG {

   	public $default = array(
   		'datasource' => 'Database/Mysql',
   		'persistent' => false,
   		// ここから変更
   		'host' => 'db',
   		'login' => 'root',
   		'password' => 'password',
   		'database' => 'my_database',
   		// ここまで変更
   		'prefix' => '',
   		//'encoding' => 'utf8',
   	);

   	// 略
   }
   ```

# ブラウザで確認

コンテナを起動した状態で[http://localhost:8000/](http://localhost:8000/)にアクセスし、下の画像のようにエラーが発生していなければOK。
![image_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/935364/15c2dd3c-abf5-7444-fd2b-13f8d299f3b1.png)

# 補足

## データベース接続

MySQLコンテナにアクセスするには、以下のコマンドを実行する。
```
docker-compose exec db mysql -uroot -ppassword my_database
```
root権限で接続すると、デフォルトでいくつかのデータベースがあることが確認できる。
```
mysql> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| my_database        |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.01 sec)
```
今回扱うのはmy_databaseなので、`USE my_database;`を実行すれば、アプリのデータを操作できるようになる。

## phpoffice/PhpSpreadsheetインストール手順

1. 概要
   Excelなどの様々なスプレッドシートファイル形式を読み書きできるPHPのライブラリ。
   [Welcome to PhpSpreadsheet's documentation - PhpSpreadsheet Documentation](https://phpspreadsheet.readthedocs.io/en/latest/)
   ```
   【一部抜粋】
   PhpSpreadsheet is a library written in pure PHP and offers a set of classes that allow you to read and write various spreadsheet file formats such as Excel and LibreOffice Calc.

   PhpSpreadsheetは純粋なPHPで書かれたライブラリで、ExcelやLibreOffice Calcのような様々な表計算ファイル形式を読み書きできるクラス群を提供します。
   ```

2. PHPとphpspreadsheetの互換性を確認
   `PHP 5.6`を使用している場合、phpspreadsheet は下記のバージョンで使用可能。
   ```
   phpspreadsheet: 1.8.2   php: ^5.6|^7.0
   phpspreadsheet: 1.8.1   php: ^5.6|^7.0
   phpspreadsheet: 1.8.0   php: ^5.6|^7.0
   phpspreadsheet: 1.7.0   php: ^5.6|^7.0
   phpspreadsheet: 1.6.0   php: ^5.6|^7.0
   phpspreadsheet: 1.5.2   php: ^5.6|^7.0
   phpspreadsheet: 1.5.1   php: ^5.6|^7.0
   phpspreadsheet: 1.5.0   php: ^5.6|^7.0
   phpspreadsheet: 1.4.1   php: ^5.6|^7.0
   phpspreadsheet: 1.4.0   php: ^5.6|^7.0
   phpspreadsheet: 1.3.1   php: ^5.6|^7.0
   phpspreadsheet: 1.3.0   php: ^5.6|^7.0
   phpspreadsheet: 1.2.1   php: ^5.6|^7.0
   phpspreadsheet: 1.2.0   php: ^5.6|^7.0
   phpspreadsheet: 1.1.0   php: ^5.6|^7.0
   phpspreadsheet: 1.0.0   php: ^5.6|^7.0
   ```
   これらの内容は、Packagistのphpspreadsheetページのrequiresのセクションで確認することができる。
   [phpoffice/phpspreadsheet - Packagist](https://packagist.org/packages/phpoffice/phpspreadsheet)
   最新バージョンを選択することが望ましいので、今回は1.8.2を使用する。
   ※phpspreadsheetのバージョンを選択せずにインストールした場合、最新バージョン(1.29.0)が自動で選択されてしまう。その場合、PHPは7.4以上または8.0以上が必要であるため、現環境ではエラーが発生してしまう。

3. GD拡張をインストール
   `phpspreadsheet 1.8.2`は`ext-gd`というPHPのGD拡張を必要としている。`Dockerfile`を編集する。
   ```docker
   # 修正前
   # 必要なツールと拡張のインストール (zip, unzip, git)
   RUN apt-get update && apt-get install -y \
       unzip \
       git \
       libzip-dev \
    && docker-php-ext-install zip
   ```

   ```docker
   # 修正後
   # 必要なツールと拡張のインストール (zip, unzip, git, libpng, libfreetype)
   RUN apt-get update && apt-get install -y \
       unzip \
       git \
       libzip-dev \
       libpng-dev \
       libfreetype6-dev \
       libjpeg62-turbo-dev \
    && docker-php-ext-install zip \
    && docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \
    && docker-php-ext-install gd
   ```

4. Dockerイメージとコンテナを再構築
   `Dockerfile`を編集したため、イメージとコンテナを再構築する必要がある。
   ```
   docker-compose down
   docker-compose build
   docker-compose up -d
   ```

5. `phpoffice/phpspreadsheet`をインストール
   `docker ps`でコンテナ IDを確認し、`プロジェクト名-web-1`コンテナの中でbashシェルを開始する。その後、composerを用いて`phpspreadsheet 1.8.2`をインストールする。
   ```
   docker ps
   docker exec -it {コンテナID} bash
   composer require phpoffice/phpspreadsheet:1.8.2
   ```

# さいごに
いかがでしたでしょうか？
全体を通して、手順が複雑だったかと思います。
もしわかりづらい点があれば、申し訳ありません。
最後まで読んでくださり、ありがとうございました！

# おまけ
私は下記の書籍を用いて、CakePHP2系のインプットを行っていました。
[CakePHP2 実践入門](https://amzn.asia/d/7ffopcG)
![IMG_0001.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/935364/9692fcdc-715a-8aba-8aff-0e3c251ae64f.jpeg)
10年以上前に発売された書籍です。
他にもCakePHP2系関連の書籍はいくつかありましたが、この書籍が最も信頼できそうだったので購入しました。
第1章〜第7章は基礎的な内容だったので、この部分に絞り読まさせていただきました。
第8章以降は応用的な内容だったので、もし深く学びたい場合は、目を通しておくと良いかもしれません。