remi で入る PHP アップグレード

# 自己紹介

乙井です。はじめまして。（仙水忍風）
Gakken LEAPという EdTech の会社でよろずやエンジニアをやっております。
本稿では remi リポジトリで入れる PHP アップグレードを紹介します。

# 目次

- [自己紹介](#自己紹介)
- [目次](#目次)
  - [前書き](#前書き)
  - [前提条件](#前提条件)
  - [コマンド羅列（忙しい人向け）](#コマンド羅列忙しい人向け)
  - [コマンド補足](#コマンド補足)
  - [説明付き手順](#説明付き手順)
  - [トラブルシューティング](#トラブルシューティング)
    - [違うリポジトリで入ってしまった場合](#違うリポジトリで入ってしまった場合)
    - [既存モジュールが残っている場合](#既存モジュールが残っている場合)
    - [`php -v` で古い PHP バージョンが表示されてしまう場合](#php--v-で古い-php-バージョンが表示されてしまう場合)
    - [モジュールの導入が失敗する場合](#モジュールの導入が失敗する場合)
    - [何度やっても古いバージョンや違うリポジトリで PHP が入ってしまう場合](#何度やっても古いバージョンや違うリポジトリで-php-が入ってしまう場合)
    - [なにがなんだか分からない場合](#なにがなんだか分からない場合)
  - [remi とは](#remi-とは)
  - [★エンジニア募集！★](#エンジニア募集)

## 前書き

PHP 初学者のみなさん。PHP のアップグレードがしたい、と思っていろいろググりますよね。
出てきたコマンドをなんとなくぺちぺち叩くじゃないですか。
いろいろやってるうちになんとなく目的のバージョンの PHP とモジュールが入ったり入らなかったりラジバンダリして、気付いたらなんかいろんなものがごちゃまぜに入ってること、ありますよね。まああるんですわ。

remi で入れたと思ったはずなのによく見たら Amazon Linux の amzn-core で入ってるというパターンが恐らく一番多いと思うんですが、
いろいろ入ってると環境が汚れますよね。
よくないじゃないですかそういうのって。後で保守する人が苦しむので。

ということで、キレイに remi だけで PHP を入れる手順を模索したので、拙筆ながら公開します。

断片的な情報は結構出てくるものの意外と一通り流れがまとまった記事は少ない気がしたので、なるべく体系性や再利用性を意識して書いてみました。

なお、そもそも remi ってなんなんだよという方は [remi とは](#remi-とは) を読んでみてください。

## 前提条件

- 更新前 PHP バージョン : 7.4.30
- 更新先 PHP バージョン : 8.2
- OS : Amazon Linux 2

## コマンド羅列（忙しい人向け）

意味を理解して自己防衛できる人向けです。

```Bash
sudo yum install https://rpms.remirepo.net/enterprise/remi-release-7.rpm

sudo yum-config-manager --enable remi-php82

sudo yum remove php-*

sudo yum clean metadata

sudo yum install zlib-devel libxml2-devel libtool gcc-c++ openssl-devel krb5-devel

sudo yum-config-manager --disable *amzn2-core*

sudo yum --enablerepo=remi-php82 install php php-cli php-fpm php-pdo php-mbstring php-mysqlnd php-xml php-gd php-common php-devel php-curl php-pear php-bcmath php-json

sudo yum --enablerepo=remi-php82 install php-opcache

sudo yum-config-manager --enable *amzn2-core*
```

確認

```Bash
php -v
which php
sudo yum list installed | grep php
```

## コマンド補足

- `remi-release` は執筆時の最新は 9 ですが、Amazon Linux 2 には 7 までしか入らなかったので 7 を入れています。
- PHP は執筆時の最新は 8.3 ですが、Amazon Linux 2 には 8.2 までしか入らなかったので 8.2 を入れています。
- いくつかの PHP のモジュールを入れる際に必要になるため、事前に `amzn2-core` からも一部モジュールを追加しています。 なお、各モジュールは適宜必要に応じて取捨選択や追加して下さい。

## 説明付き手順

まず remi リポジトリを環境内へダウンロード・インストールします。

```Bash
sudo yum install https://rpms.remirepo.net/enterprise/remi-release-7.rpm
```

続いて入れたい PHP バージョンの remi リポジトリを有効にします。

```Bash
sudo yum-config-manager --enable remi-php82
```

有効になっているかどうかの確認は下記コマンドで。

```Bash
yum repolist all
```

下記のように対象リポジトリが `enabled` になっていればOK。

```Bash
remi-php82         Remi's PHP 8.2 RPM repository for Enterprise Linux 7 - x86_64    enabled: 304+48
```

あとで新しく入れた PHP と競合しないように既存の PHP モジュールを削除、念の為メタデータも削除。

```Bash
sudo yum remove php-*
sudo yum clean metadata
```

一部 PHP モジュールを入れる際に必要となる予備モジュールを追加（この辺は環境によると思うので適宜判断して下さい）。

```Bash
sudo yum install zlib-devel libxml2-devel libtool gcc-c++ openssl-devel krb5-devel
```

`amzn2-core` リポジトリを一時的に無効化。（remi ではなく `amzn2-core` から PHP がインストールされてしまうのを防ぐ為。順番を間違えると予備モジュールが入らなくなるので注意。）

```Bash
sudo yum-config-manager --disable *amzn2-core*
```

PHP と必要モジュールの導入（`php-opcache` のみ別出しにして後から追加実行しているのは同時に入れようとするとモジュール不足でこけるため）。
`--enablerepo={リポジトリ名}` を付けることで、指定したリポジトリからのインストールを強制します。

```Bash
sudo yum --enablerepo=remi-php82 install php php-cli php-fpm php-pdo php-mbstring php-mysqlnd php-xml php-gd php-common php-devel php-curl php-pear php-bcmath php-json

sudo yum --enablerepo=remi-php82 install php-opcache
```

`amzn2-core` リポジトリの再度有効化（これを忘れずしておかないと後々どこかで困る）。

```Bash
sudo yum-config-manager --enable *amzn2-core*
```

目的の PHP がインストールされたことの確認。

```Bash
php -v
which php
sudo yum list installed | grep php
```

下記のような感じで導入元リポジトリが `@remi-php82` など remi で入っていれば成功（ここが `amzn2-core` だったりすると remi での導入としては失敗）。

```Bash
$ php -v
PHP 8.2.18 (cli) (built: Apr  9 2024 18:46:23) (NTS gcc x86_64)
Copyright (c) The PHP Group
Zend Engine v4.2.18, Copyright (c) Zend Technologies

$ which php
/usr/bin/php

$ sudo yum list installed | grep php
php.x86_64                            8.2.18-1.el7.remi              @remi-php82
php-bcmath.x86_64                     8.2.18-1.el7.remi              @remi-php82
php-cli.x86_64                        8.2.18-1.el7.remi              @remi-php82
php-common.x86_64                     8.2.18-1.el7.remi              @remi-php82
php-devel.x86_64                      8.2.18-1.el7.remi              @remi-php82
php-fpm.x86_64                        8.2.18-1.el7.remi              @remi-php82
php-gd.x86_64                         8.2.18-1.el7.remi              @remi-php82
php-mbstring.x86_64                   8.2.18-1.el7.remi              @remi-php82
php-mysqlnd.x86_64                    8.2.18-1.el7.remi              @remi-php82
php-pdo.x86_64                        8.2.18-1.el7.remi              @remi-php82
php-pear.noarch                       1:1.10.15-2.el7.remi           @remi-php82
php-process.x86_64                    8.2.18-1.el7.remi              @remi-php82
php-sodium.x86_64                     8.2.18-1.el7.remi              @remi-php82
php-xml.x86_64                        8.2.18-1.el7.remi              @remi-php82
```

ここで想定外の結果になったりした場合は、再度コマンドの意味を咀嚼しつつ、メッセージと対話しながら[説明付き手順](#説明付き手順)を遡っていってください。
また、下記にいくつかよくある例も書き出してみました。こちらも参考になれば幸いです。

## トラブルシューティング

### 違うリポジトリで入ってしまった場合

- 再度 `sudo yum remove php-*` で現在入っている PHP モジュールを一括削除し、他に有効になっているリポジトリがないかを `yum repolist all | grep "php" | grep "enabled"` などで確認します。想定外のものが enabled になっていれば、それを指定して `sudo yum-config-manager --disable {リポジトリ名}` で無効化します（※1）。無効化できたら、対象の remi リポジトリが `enabled` になっていることを再度確認して（※2）モジュールのインストールを実行します。
- 怪しいリポジトリは、`amzn2-core` 以外にも `amzn2extra-php` や `remi-safe` などで躓きがちです。
  - （※1：間に . などが入っていてうまく指定できない場合は、他に類似のリポジトリ名がないことを確認して後ろに * を付けるなどします。）
  - （※2：入れたい remi リポジトリが `disabled` になっている場合は再度 `sudo yum-config-manager --disable {リポジトリ名}` で有効化します。）

### 既存モジュールが残っている場合

- 前の人達の遺産でこういうのがたまにあったりします。`remi-safe` あたりが割と残りがちです。基本的には[前項](#違うリポジトリで入ってしまった場合)とやる事は同じですが、中には時々必要なモジュールで `remi-safe` など別リポジトリから入れる必要があるものもあったりするため、今入っているモジュールをどこかにメモを取りながら削除と入れ直しをしていきます。
- `php-common` などが `remi-safe` などで入っている場合は明らかな競合なので削除して下さい。この際、他の依存モジュールも一緒に削除されるケースが多いので、目的のリポジトリから入れ直して下さい。

### `php -v` で古い PHP バージョンが表示されてしまう場合

- パスの問題の可能性が考えられます。よくあるのが、新しいバージョンの PHP がパスが通っているディレクトリとは異なる場所に入っていて認識されないケースです。
  - `which php` で表示されるパスが現在有効な PHP のディレクトリなので、そこにある PHP のタイムスタンプが古ければ、新しい PHP（※）をそこに持ってきてやるか、新しい PHP がある方のディレクトリのパスを通して古い方を削除するなどで解決する場合があります。
    - （※：remi リポジトリで入れると、PHP 本体は通常 `/etc/opt/remi/` や `/opt/remi/` 辺りに入ります。ここで /usr/bin/php からシンボリックリンクが張られている事が多いのですが、何らかの原因でこれがうまくいってない場合は、`/usr/bin/` などパスの通っている場所で `ln -s /etc/opt/remi/ php` などで手動でシンボリックリンクを張ってやると動くようになる場合があります。）

### モジュールの導入が失敗する場合

- `sudo yum --enablerepo={リポジトリ名} install {モジュール名}` がうまくいかない場合はやや難航しますが、メモを取りつつエラーと対話して粘ってみてください。
  1. yum が古い場合
     1. `sudo yum update` を試してみてください。yum が古いことが原因でモジュールがなく `No package {モジュール名} available.` エラーになるケースもあります。
  2. 依存関係の都合で入らない場合
     - 依存関係の都合で、他のモジュールを先にインストールしないと入らない場合があります。`php-opcache` でやった時のように、エラーになったモジュールだけ後に切り出し、先に他のモジュールをインストールするとうまく入る場合があります。
  3. 指定したモジュールがそのリポジトリに存在しない場合
     - ない場合は仕方がないので、どうしても必要な場合はそのモジュールだけ別のリポジトリ（たとえば `remi-safe` など）から入れてくる方法も検討してみて下さい。ただし依存関係で問題が生じるリスクは頭に置いておき、問題が生じたら入れ直しも検討して下さい。
     - また、ものによっては PHP のバージョンアップに伴って廃止されたり、他のモジュールに統合になったりしているものもあるので、アプリケーションの動作も見ながら必要なモジュールの見直しをしてみるのも一つの手です。モジュール名で Web 検索するとより具体的な情報が得られます。

### 何度やっても古いバージョンや違うリポジトリで PHP が入ってしまう場合

- 一部古いモジュールが残っている事が原因で、そのモジュールに釣られて意図と違うものが依存関係で入ってしまう可能性もあります。`sudo yum list installed | grep php` で残存するモジュールがないかを確認し、ある場合は `sudo yum remove {モジュール名}` で削除してみてください。（念のためモジュール名はメモに控えておいて、あとで入れ直すことをおすすめします。詳細や注意点は「[既存モジュールが残っている場合](#既存モジュールが残っている場合)」や「[モジュールの導入が失敗する場合](#モジュールの導入が失敗する場合)」もご参照ください。）

### なにがなんだか分からない場合

- 最近は Chat-GPT がだいぶなんでも教えてくれます。便利になりましたね。

## remi とは

PHP とその周辺モジュールを詰め込んだパッケージです。
そもそも PHP の導入方法には主に3種類あります。

1. [PHP の公式サイト](https://www.php.net/manual/ja/install.unix.php)からソースをダウンロードしてきてビルドする
2. サードパーティ製のリポジトリからインストールする
3. OS に元々用意されているリポジトリからインストールする
   - 今回想定の Amazon Linux 2 環境の場合は `amzn2-core` がそれです。

remi リポジトリとは、 2. のサードパーティ製のリポジトリの一種です。
なぜ remi という名前なのかというと、[公式サイト](https://rpms.remirepo.net/) に「Remi's RPM repository」と書いてあるように、Remi Collet さんという人が提供しているリポジトリだからです。
最新の PHP を使いたい人にはいろいろ便利なモジュールが入っていて、導入も手軽で扱いやすいのですが、バージョンを固定して PHP を使い続けたい人や、古いバージョンの PHP を使いたい人には不向きという側面もあります。なぜかというと、remi リポジトリは古いバージョンのモジュールをどんどん提供元から削除していってしまうためです。
たとえば、検証の為に PHP 5 系にダウングレードしたいよ、という時には remi にはもうありません。
裏を返せば、常に最新のバージョンを便利に使いたい人にはとても便利なリポジトリです。

1\. の公式からソースを落としてきてビルドする方法は、実は少々手間がかかったりします。そこで、サードパーティのリポジトリを使うと導入や保守が楽だったりして、多くの人が remi や OS のリポジトリで PHP を使っていたりします。

また、OS 標準のリポジトリも扱いやすくて良かったりするのですが、提供されている PHP のバージョンが少し古かったりして、最新のものが利用できない場合があります。そういった時に、remi だとより新しいバージョンの PHP が使えるケースもあったりして、OS 標準のものではなく選択的に remi で PHP を入れたりする事もあります。
このあたりはケースバイケースだったりもするので、現場のお作法や、前任者のやってきた方法や、その時に求められている条件などで適切な方法を選ぶとよいです。
ちなみに私は個人的に最新状態の気持ちよさと手軽さが好きなので、プライベートの開発では remi を積極的に使っていたりします。
[目次へ戻る](#目次)

## ★エンジニア募集！★

Gakken LEAP では教育をアップデートしていきたいエンジニアを絶賛大募集しています！！
ぜひお気軽にカジュアル面談へお越しください！！
<https://gakken-leap.co.jp/recruit/>