Laravel のサーバー移行手順 ( PHP8) 

#はじめに
レンタルサーバーから、AWSEC2の移行する際に、苦戦したため、手順を記載します。
移行前は、apacheでPHP7、移行先はnginxでPHP8となっています。

#前提条件
- VPC,サブネット,EC2,RDSは構築済み
- 移行前
    - レンタルサーバー
    - PHP7.1
    - apache2.4
    - Laravel 5.5
    - phpmyadmin

- 移行後
    - AWS EC2 AmazonLinux2
    - `PHP8.0`
    - `nginx`
    - `Laravel6以上` (PHP8に対して、laravel6以上が対応しているため)
    - RDS MYSQL
    - adminer（phpmyadminでもよい）
        - EC2 + RDS + Nginx + PHP8 + Adminer　の構築は↓が参考になります。(wordpressのところは省きましょう)
           
https://qiita.com/holdout0521/items/342afcee0736a7165e7d

#流れ
1. DBを移行
1. ディレクトリを移行
1. composerとlaravelをインストール
1. composer.jsonを修正
1. .envファイルを修正
1. nginx.conf修正
1. パーミッション変更
1. エラー集


#DBを移行
移行元のレンタルサーバーのDB管理ツールはphpmyadminが使われていましたので、SQLファイルとしてエクスポートします。
移行先のEC2には、DB管理ツールのadminerが入っていましたので、sqlファイルをインポートするだけです。

adminer導入手順はこちら記事が参考になります。

ダウンロードしたadminerファイル1つを、nginx.confの`root`で設定しているルートディレクトリ配下に設置するだけです。


https://qiita.com/holdout0521/items/d559ed8ab24aaaafd876#adminer%E3%82%92ec2%E3%81%AB%E8%A8%AD%E7%BD%AE

#ディレクトリを移行
レンタルサーバーのルートディレクトリ配下すべてをEC2サーバーに移します。
ただし、ルートディレクトリ直下の`composer.lock`と`vendorディレクトリ`は入れないでください。

###composer.lockとは
>composer.json を元にインストールされたパッケージなどが具体的に記述されています。
この lock ファイルを利用すれば、同じ環境を作ることができます。

###composer.jsonとは
>composer.json には、必要とするライブラリの種類と、必要なバージョンの条件が書かれているファイルです。

新しいサーバーには、composer.json を元に、コマンド`composer install`でLaravelのバージョンやライブラリをインストールします。
しかし、composer.lockも新しいサーバーにある場合、composer.lockをもとにインストールされてしまいますので、移行しないようにしましょう。

|コマンド|	composer.lock	|動作|
|---|---|---|
| composer install | なし | composer.json を元にインストールされ、composer.lock が作成されます|
| composer install | あり | composer.lock を元にインストール|
| composer update | あり |composer.json を元にアップデートされ、composer.lock が更新されます|


`vendorディレクトリ`は、Composer の依存内容をおくところです。
vendor、はサーバにインストールされているPHPのバージョンやPHP拡張によって、中身が変わる可能性があるからです。なので、そのサーバ上でvendor以下を構築する作業（composer install）をしないとまともにLaravelが動かない可能性があります。


#composerとlaravelをインストール

composerインストール方法はこちらの記事が参考になります

https://qiita.com/miriwo/items/b25f9d4d74b7103f6ff6

laravelのインストールとパスを通します。

```terminal
$ composer global require "laravel/installer" --prefer-dist
$ export PATH=$HOME/.composer/vendor/bin:$PATH 
$ source ~/.bash_profile
```

https://qiita.com/m24/items/970d9c575647f8f6ff33#%E5%AF%BE%E5%87%A6%E6%B3%95


#composer.jsonを修正

移行前は、PHP7,Laravel5.5
移行先は、PHP8,Laravel6とします。
移行前のcomposer.jsonを修正して、移行先に置きます。

```json:composer.json.移行前
 {
        "require": {
            "php": ">=7.0.0",
            "fideloper/proxy": "~3.3",
            "laravel/framework": "5.5.*",
            "laravel/tinker": "~1.0"
        },
        "require-dev": {
            "fzaninotto/faker": "~1.4",
            "phpunit/phpunit": "~6.0",
        },
```


```json:composer.json.移行後
    {
        "require": {
            "php": ">=7.0.0|^8.0",  
            "fideloper/proxy": "^4.0",
            "laravel/framework": "^6.0",
            "laravel/tinker": "^1.0"
        },
        "require-dev": {
            "fakerphp/faker":"^1.9.1",
            "phpunit/phpunit": "^9.3",
        },
```
修正が必要な箇所のみ記載しています。

###PHP8の影響
LaravelでPHP8を使用するには、以下のcomposer.jsonファイル3つをバージョンアップする必要があります。
ちなみに、PHP8では、`fzaninotto/faker`は使用できないため、`fakerphp/faker`を使用します。

```
php:^8.0
fakerphp/faker:^1.9.1
phpunit/phpunit:^9.3
```
詳細↓

https://blog.laravel.com/laravel-php-8-support



ただし、移行元でPHP7を使用していたため、影響が出ないよう`"php": ">=7.0.0|^8.0"`としています。
3つのバージョンを挙げない場合、
PHP8から`getClass()`メソッドが非推奨になっており、警告出て、`php artsan`コマンドが実行できなくなるため必ず記載しましょう。
>PHP 8では、ReflectionParameterクラスの次のメソッドは非推奨になりました。
ReflectionParameter::getClass()
ReflectionParameter::isArray()
ReflectionParameter::isCallable()

以下のようなエラーが出ます。

```terminal
Deprecated: Method ReflectionParameter::getClass() is deprecated in /Users/.../Sites/.../vendor/laravel/framework/src/Illuminate/Container/Container.php on line 871

Deprecated: Method ReflectionParameter::getClass() is deprecated in /Users/.../Sites/.../vendor/laravel/framework/src/Illuminate/Container/Container.php on line 945

Deprecated: Method ReflectionParameter::getClass() is deprecated in /Users/.../Sites/.../vendor/laravel/framework/src/Illuminate/Container/Container.php on line 871

Deprecated: Method ReflectionParameter::getClass() is deprecated in /Users/.../Sites/.../vendor/laravel/framework/src/Illuminate/Container/Container.php on line 945
```

###laravel6
laravelを5系から6系にアップデートする際、composer.jsonで以下の3つをアップデートする必要があります。

```
"fideloper/proxy": "^4.0",
"laravel/framework": "^6.0",
"laravel/tinker": "^1.0"
```

https://into-the-program.com/laravel-upgrade-5-to-8/


composer.jsonのバージョン表記についてはこちらの記事が参考になります。

https://access-jp.co.jp/blogs/development/256

#.envファイルを修正
下記の箇所を変更します。

```env:.env
APP_URL=http://IPアドレス ←サーバーのIPにする

DB_CONNECTION=mysql
DB_HOST=←RDSのエンドポイント（auroraの場合、ライターインスタンス)
DB_DATABASE=データベース名
DB_USERNAME=RDS作成時のユーザ名
DB_PASSWORD=設定したパスワード
```

#nginx.conf修正
以下のように記載しましょう。
nginxの`root`や`servername`の箇所は、各々変えましょう。

```conf:nginx.conf
    server {
        listen       80;
        listen       [::]:80;
        server_name  _;
        root         /usr/share/nginx/html;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / {
              try_files $uri $uri/ /index.php?q=$uri&$args;
        }
        error_page 404 /404.html;
        location = /404.html {
        }

        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
        }
```

#パーミッション変更

composer installして、composer.jsonを元に、ライブラリ等がインストールされます。

```
$ composer install
```

最後に、所有者と権限を変えます。
ルートディレクトリは、`/usr/share/nginx/html/laravel6`とします。
ec2-userユーザーでSFTP接続をして開発するため、`nginx:ec2-user`としています。
本番時は、権限を狭めましょう。

```
$ sudo find /usr/share/nginx/html/laravel6 -type d -exec chmod 775 {} +
$ sudo find /usr/share/nginx/html/laravel6 -type f -exec chmod 664 {} +
$ sudo chown -R nginx:ec2-user /usr/share/nginx/html/laravel6
$ sudo chown -R nginx:ec2-user /var/log/nginx
$ sudo chown -R nginx:ec2-user /var/log/php-fpm
```
以下の記事の権限が良いかもしれません。

https://qiita.com/engulisyu/items/ad819d06ea0cd31411df

では、アクセスすると、サーバー移行が完了していると思います。
エラーが出た場合は、以下のコマンドでログを確認しましょう。

```
$ sudo cat /usr/share/nginx/html/laravel6/storage/logs/laravel.log
$ sudo cat /var/log/nginx/error.log
```

#エラー集
私が遭遇したエラーの一部を紹介します。

##bootstrap/cacheのディレクトリがない。権限がない。
作成し、nginxの権限を加えましょう。

```
laravel.ERROR: 
The /usr/share/nginx/html/laravel/bootstrap/cache
 directory must be present and writable. 
{"exception":"[object] (Exception(code: 0): 
The /usr/share/nginx/html/laravel6/bootstrap/cache 
directory must be present and writable. 
at /usr/share/nginx/html/laravel6/vendor/laravel/framework/src/Illuminate/Foundation/
```

##TrustProxies.phpファイルを修正


```
laravel.ERROR: Symfony\Component\HttpFoundation\Request::setTrustedProxies(): Argument #2 ($trustedHeaderSet) must be of type int, array given, called in /usr/share/nginx/html/laravel6/vendor/fideloper/proxy/src/TrustProxies.php on line 54 {"exception":"[object] (Symfony\\Component\\Debug\\Exception\\FatalThrowableError(code: 0): Symfony\\Component\\HttpFoundation\\Request::setTrustedProxies(): Argument #2 ($trustedHeaderSet) must be of type int, array given, called in /usr/share/nginx/html/laravel6/vendor/fideloper/proxy/src/TrustProxies.php on line 54 at /usr/share/nginx/html/laravel6/vendor/symfony/http-foundation/Request.php:574)
```

`App\Http\Middleware\TrustProxies`を書き換えるようにする必要があります

↓以下の記事の`Trusted Proxies`の箇所に書いています。

https://readouble.com/laravel/5.8/ja/requests.html#configuring-trusted-proxies

https://qiita.com/mozukuzuku/items/8e65ae24a70bf7ff2f92


```php:app/Http/Middleware/TrustProxies.php
protected $proxies;

protected $headers = [
    Request::HEADER_FORWARDED => 'FORWARDED',
    Request::HEADER_X_FORWARDED_FOR => 'X_FORWARDED_FOR',
    Request::HEADER_X_FORWARDED_HOST => 'X_FORWARDED_HOST',
    Request::HEADER_X_FORWARDED_PORT => 'X_FORWARDED_PORT',
    Request::HEADER_X_FORWARDED_PROTO => 'X_FORWARDED_PROTO',
    ];
```
↓以下のように修正します。

```php:app/Http/Middleware/TrustProxies.php
protected $proxies = '*';

protected $headers = Request::HEADER_X_FORWARDED_ALL;
```

##php artisanコマンド実行時

`Call to undefined function str_slug()`というエラーが出ました。

以下の記事が参考になりました。



https://tech.arms-soft.co.jp/entry/2019/09/11/090000

##ログファイルの権限不足

```
PHP Fatal error: Uncaught UnexpectedValueException: The stream or file "/usr/share/nginx/html/laravel6/storage/logs/laravel.log" could not be opened in append mode: Failed to open stream: Permission denied in /usr/share/nginx/html/larave6/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php:146
```

ログファイルの権限がないようです。nginxの権限を与えましょう

```
$ sudo chown nginx:ec2-user /usr/share/nginx/html/larave6/storage/logs/laravel.log
```