Wordpress でメディアのアップロードに失敗する際の備忘録

Wordpress で、メディアのアップロードに失敗する際に対応した備忘録を残しておく。

## 失敗する際に確認する設定

1. アップロードしたメディア (ファイル) が保存されるディレクトリの確認
  1. 保存されるディレクトリの存在
  2. 保存されるディレクトリのユーザー権限
2. PHP (php.ini) の設定
  1. file_uploads
  2. upload_tmp_dir
  3. upload_max_filesize
  4. max_file_uploads
3. Apache の設定
4. nginx の設定
5. サーバーと PHP のエラーログを確認する
6. Wordpress をデバッグモードにする

### 1. アップロードしたメディア (ファイル) が保存されるディレクトリの確認
#### 1.1. 保存されるディレクトリの存在

通常は、Wordpress の設定ファイル wp-config.php が存在するディレクトリ内にある wp-content 下の uploads ディレクトリが、アップロードしたメディアが保存されるディレクトリになる。

```shell-session
|--wp-config.php
|--wp-content
|  |-- uploads
```
もし、存在しなければ、削除されている可能性がある。
(このディレクトリは任意のディレクトリに変更できるので、その確認方法は後述する)

#### 1.2. 保存されるディレクトリのユーザー権限

アップロードされたファイルを保存するには、ディレクトリの所有者が WEB サーバになっている必要がある。
(もしくは WEB サーバーにディレクトリの操作権限が付与されている)

下記は WEB サーバーが Apache の場合

```shell-session
$ ls -l wp-content/ | grep uploads
drwxr-xr-x 14 apache apache     4096 Jan 18 14:59 uploads
```

PHP が php-fpm で動作している場合は、ディレクトリに php-fpm の実行ユーザーの権限が付与されている必要がある。

```shell-session
$ cat /etc/php-fpm.conf | egrep '(user|group) ='
user = nobody
group = nobody
```

php-fpm を実行するユーザーとグループを確認して、wp-content/uploads ディレクトリの所有者を確認する。

```shell-session
$ ls -l wp-content/ | grep uploads
drwxr-xr-x 14 nobody nobody     4096 Jan 18 14:59 uploads
```

ホスティングサーバーだと、ディレクトリの所有者を変更できない場合があるので、パーミッションを 757 (rwxr-xrwx) にする必要があるかも。
(セキュリティの観点から避けたい設定だけれど…)

### 2. PHP (php.ini) の設定

php.ini にはファイルのアップロードに関する設定があるので、それらを確認する。

|設定名|概要|
|:--|:--|
|file_uploads|HTTP ファイルアップロード を有効・無効を切り替える設定|
|upload_tmp_dir|ファイルアップロード時にファイル保存に用いるテンポラリディレクトリ|
|upload_max_filesize|アップロード可能なファイルの最大サイズ|
|max_file_uploads|同時にアップロード可能なファイルの最大数|

* **file_uploads**: 有効になっていれば、PHP はファイルのアップロード処理をする
* **upload_tmp_dir**: 未設定の場合は、OS 毎に設定されているテンポラリディレクトリを利用
* **upload_max_filesize**: サイズが大きいファイルをアップロードする場合、この制限に引っかかる場合がある
* **max_file_uploads**: 複数のファイルをいっせいにアップロードすると、この制限にひっかかる場合がある

詳細は [PHP: POST メソッドによるアップロード - Manual](https://www.php.net/manual/ja/features.file-upload.post-method.php) を参照。

念のため、upload_tmp_dir で指定されているディレクトリの操作権限も確認しておく。

### 3. Apache の設定

これは、ユーザーがサーバーにデータを送信する場合のサイズに上限を設けるための設定になる。サーバーのセキュリティ向上を高めるために設定されていることがあるので、確認。

```shell-session
$ grep -lr LimitRequestBody /etc/httpd/
```

未設定ならば、何も表示されない。設定されている場合は、サーバーの管理者権限が必要なので、サーバーの設定ができる人に相談しよう。

### 4. nginx の設定

上記の Apache の設定と同じ。

```shell-session
$ cat /etc/nginx/conf/nginx.conf | grep max_body
    client_max_body_size         8m;
```

### 5. サーバーと PHP のエラーログを確認する

エラーログを閲覧できる権限があれば、何かしらエラーが発生していないか確認をする。

### 6. Wordpress をデバッグモードにする

```shell-session
$ cat wp-config.php | grep WP_DEBUG
define('WP_DEBUG', false);
```
WP_DEBUG 変数を true に変更して、ファイルアップロード時にエラーが表示、もしくは PHP のエラーログにアップロード処理に関連するエラーが出力されないか確認をする。

---

ここまででファイルのアップロードに制限がかかる設定に問題がなければ、ファイルのアップロードは問題なく成功するはず。

## それでもアップロードが成功しなかったので

だったのだが、それでもファイルのアップロードができないので、調査を継続する。

### tcpdump を使う (要管理者権限)

そもそもファイルアップロードのリクエストがサーバーに到達しているのか確認をするために、tcpdump を使って、WEB サーバーに POST メソッドのリクエストを監視する。

```shell-session
$ sudo tcpdump -s 0 -A 'tcp dst port 80 and (tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x504f5354)'
```

### PHP のアップロードディレクトリを監視する

ファイルアップロード時に upload_tmp_dir で設定されたディレクトリに、何かしら変化があるか確認をする。

```shell-session
$ inotifywait -m --format '%T %w%f (%e)' --timefmt '%F %T' /tmp/ &

2019-03-22 12:24:52 /tmp/phpTNlBvE (CREATE)
2019-03-22 12:24:52 /tmp/phpTNlBvE (OPEN)
2019-03-22 12:24:52 /tmp/phpTNlBvE (MODIFY)
2019-03-22 12:24:52 /tmp/phpTNlBvE (MODIFY)
2019-03-22 12:24:52 /tmp/phpTNlBvE (CLOSE_WRITE,CLOSE)
2019-03-22 12:25:05 /tmp/sh-thd-1553203289 (CREATE)
2019-03-22 12:25:05 /tmp/sh-thd-1553203289 (OPEN)
2019-03-22 12:25:05 /tmp/sh-thd-1553203289 (MODIFY)
2019-03-22 12:25:05 /tmp/sh-thd-1553203289 (OPEN)
2019-03-22 12:25:05 /tmp/sh-thd-1553203289 (CLOSE_WRITE,CLOSE)
2019-03-22 12:25:05 /tmp/sh-thd-1553203289 (DELETE)
2019-03-22 12:25:05 /tmp/sh-thd-1553203289 (CLOSE_NOWRITE,CLOSE)
```

ファイルアップロード時に、テンポラリディレクトリでファイルの保存、サムネイルの作成らしき操作が起きていることを確認。

### 最終的には Wordpress の仕様ががががが

いちど初心に帰って、Wordpress の設定を確認してみることにする。すると、設定 > メディア に見慣れない設定項目が。

![2019-03-22_11h00_10.png](https://qiita-image-store.s3.amazonaws.com/0/248967/24604084-45c0-29c1-053b-e1de255bfbdf.png)

他の Wordpress の設定画面と比較してみたが、上図の設定項目がない。そして、設定には存在しないパスが指定されていた。

> 今回、画像をアップロードできなかった原因は、Wordpress をリニューアルした際に、旧コンテンツの設定 (Wordpress 3.6 以前) をそのまま引き継いだこと、新コンテンツの Wordpress は異なるディレクトリで運用していたため、存在しないディレクトリにメディアを保存しようとして失敗したことになる。
上図で絶対パスで指定されていた保存場所を相対パス「wp-content/uploads」に変更したら、上図の設定項目は非表示になり、メディアの保存ができるようになった。
(アップロードするディレクトリが存在しない場合、PHP のエラーログに何も出力されないのは、エラーログのレベルの設定の問題か？)

絶対パスで設定されているアップロードディレクトリを、相対パス `wp-content/uploads` に変更。そして、メディアをアップロードしてみて、保存されれば、問題解決。
 (絶対パスから相対パスに変更を反映させると、上記の設定項目は管理画面から消える)

この設定項目は Wordpress 3.5 系まであったようで、3.6 移行 (2013年 8月リリース) 以降は通常は非表示になる隠し設定になったらしい。
 (リリースノートには明記されていない [Version 3.6 - WordPress Codex 日本語版](http://wpdocs.osdn.jp/Version_3.6))

#### 隠し設定項目の表示方法

表示されなくなった項目は、管理画面の URL に /wp-admin/options.php とアクセスすれば、表示できる。例えば、管理画面の URL が https://www.example.com/wp-admin/ ならば、隠し項目の設定は https://www.example.com/wp-admin/options.php で表示される。

![2019-03-22_12h30_26.png](https://qiita-image-store.s3.amazonaws.com/0/248967/78f02e85-7616-8bc5-8f66-a010c3749e31.png)

非表示になった設定は、非表示になった理由があるのだろうから、これらの項目を変更せずに運用できる別の方法を検討する方がよいだろう。