###背景
vue/phpを使って画像投稿するサイトを作っていました。
問題
ローカルでのビルトインサーバでは画像投稿できるが、
'''request->file実行時 Docker起動のビルトインサーバで画像投稿
validation:update```
と表示されて、画像投稿できない。
###結論
php-pmでは/private/var/
にtmpファイル保存されていないことが原因だったので、php-fpmを使うことにしました。
前提
怪しいと思われるLaravel側でログ出力画像を投稿するstoreメソッドに
Logを仕込んで確認しました。
php-pm
FROM phppm/nginx:2.0.3
RUN apk update && apk add --no-cache \
tzdata curl \
&& apk del tzdata \
&& rm -rf /var/cache/apk/*
COPY . /var/www
CMD ["--bootstrap=laravel","--static-directory=public/"]
Laravel側
public function store(Request $request)
{
Log::debug('API storeメソッドの実行');
Log::debug($request);
Log::debug(request());
$this->validate($request, [
'file' => 'required|image',
'gear_name' => 'required',
'gear_category' => 'required',
'maker_name' => 'required',
'content' => ['required', 'min:2'],
], [
'file.required' => '画像が選択されていません',
'file.image' => '画像ファイルではありません',
'gear_category.required' => '登録するギアのカテゴリを選択してください',
'gear_name.required' => '登録するギアの名前を入力してください',
'maker_name.required' => '登録するギアのメーカ名を入力してください',
'content.min' => 'ギアのお気に入りポイントを2文字以上入力してください',
'content.required' => 'ギアのお気に入りポイントを入力してください',
]);
Log::debug('$image = $request->file');
Log::debug($image = $request->file('file'));
Log::debug('=====');
if ($request->hasFile('file')) {
Log::debug('requstにfileがある時の処理');
Log::debug(request()->file);
$image = $request->file('file');
$image_url = Storage::disk('s3')->put('/myprefix', $image, 'public');
$gear = new Gear();
$gear->image_url = Storage::disk('s3')->url($image_url);
$gear->gear_name = $request->gear_name;
$gear->maker_name = $request->maker_name;
$gear->content = $request->content;
$gear->ref_url = self::replaceUrl($request->ref_url);
$gear->gear_category = $request->gear_category;
$gear->updated_at = date('Y/m/d H:i:s');
$gear->gear_category = $request->gear_category;
$gear->user_id = $request->user_id;
$gear->save();
return ['success' => '登録しました!'];
}
}
Vue側
<script>
//画像、コメント投稿用のvue側のaxios通信
uploadImage() {
let data = new FormData();
data.append("file", this.file);
data.append("maker_name", this.maker_name);
data.append("gear_name", this.gear_name);
data.append("gear_category", this.gear_category);
data.append("content", this.content);
//Vuexのstoreからauth_user情報を呼び出す
data.append("user_id", this.$store.state.auth_user.id);
console.log('dataの表示')
console.log(data);
for (let value of data.entries()) {
console.log(value);
}
NProgress.start();
axios.post("/api/gears", data)
// axios.post("/gears", data)
.then(response => {
setTimeout(()=>{
// this.getGears();
console.log('responseの表示')
console.log(response);
/***
responseは表示されない
***/
this.message = response.data.success;
this.confirmedImage = "";
this.maker_name = "";
this.gear_name = "";
this.gear_category = "";
this.content = "";
this.file = "";
// this.user_id = $route.params;
this.message = 'success'
//ファイルを選択のクリア
this.view = false;
this.is_post_success = true;
this.$nextTick(function () {
this.view = true;
});
NProgress.done();
},3000);
})
.catch(err => {
console.log('errorの表示')
console.log(err)
console.log(err.response)
/***
Error: Request failed with status code 422
at createError (app.js:699)
at settle (app.js:960)
at XMLHttpRequest.handleLoad (app.js:168)
{data: {…}, status: 422, statusText: "", headers: {…},
config: {…}, …}
config: {url: "/api/gears", method: "post", data:
FormData, headers: {…}, transformRequest: Array(1), …}
data: {message: "The given data was invalid.", errors: {…}}
headers: {access-control-allow-origin: "*", cache-control: "no- cache, private", content-length: "83", content-type:
"application/json", date: "Thu, 21 Jan 2021 10:50:37 GMT", …}
request: XMLHttpRequest {readyState: 4, timeout: 0,
withCredentials: false, upload: XMLHttpRequestUpload,
onreadystatechange: ƒ, …}
status: 422
statusText: ""
__proto__: Object
***/
this.message = err.response.data.errors;
this.is_post_success = false;
});
}
// ここまで
}
};
</script>
###エラー確認
[2021-01-22 19:04:39] production.DEBUG: API storeメソッドの実行
[2021-01-22 19:04:39] production.DEBUG: array (
'maker_name' => 'da',
'gear_name' => 'da',
'gear_category' => 'BackPack',
'content' => 'da',
'user_id' => '1',
'file' =>
Illuminate\Http\UploadedFile::__set_state(array(
'test' => false,
'originalName' => 'テスト.png',
'mimeType' => 'image/png',
'error' => 0,
'hashName' => NULL,
)),
)
[2021-01-22 19:04:39] production.DEBUG: requstにfileがある時の処理
[2021-01-22 19:04:39] production.DEBUG: /private/var/tmp/phpRMqJe0
requestでは/private/var/tmp/phpRM
と表示されている。
[2021-01-22 19:06:35] dev.DEBUG: index
[2021-01-22 19:06:42] dev.DEBUG: API store.....................
[2021-01-22 19:06:42] dev.DEBUG: array (
'maker_name' => 'da',
'gear_name' => 'da',
'gear_category' => 'BackPack',
'content' => 'daa',
'user_id' => '1',
'file' =>
Illuminate\Http\UploadedFile::__set_state(array(
'test' => false,
'originalName' => '..........png',
'mimeType' => 'image/png',
'error' => 2190,
'hashName' => NULL,
)),
)
[2021-01-23 20:47:52] production.DEBUG: array (
'maker_name' => 'ss',
'gear_name' => 'sss',
'gear_category' => 'Cutting',
'content' => 'ss',
'user_id' => '1',
'file' =>
Illuminate\Http\UploadedFile::__set_state(array(
'test' => false,
'originalName' => 'テスト.png',
'mimeType' => 'image/png',
'error' => 0,
'hashName' => NULL,
)),
)
[2021-01-23 20:47:52] production.DEBUG: $image = $request->file
[2021-01-23 20:47:52] production.DEBUG: /tmp/php4eELue
[2021-01-23 20:47:52] production.DEBUG: =====
[2021-01-23 20:47:52] production.DEBUG: requstにfileがある時の処理
[2021-01-23 20:47:52] production.DEBUG: /tmp/php4eELue
正常時では /tmp
ファイル以下に書き込まれています。
###推測
php7.3 ローカルではrequest()->file)
の返り値あり
php-pm Docker上では 返り値なし
php−fpm Docker上では request()->file)
の返り値あり。
でした。
以上から
php-pmでは/tmpディレクトリ以下にファイルが書き込み権限がない、そもそもディレクトリ自体がないと考えられました。
解決策
php-fpmでDockerfileを準備しました。
#php 7.3 fpmを仕様
FROM php:7.3-fpm
# 設定ファイルphp.iniをコピーする。
# Dockerfileにあるディレクトリをコピーして/var/wwwに保存
COPY ./docker/php/php.ini /usr/local/etc/php/
COPY ./ /var/www/
#必要なファイルを保存する。
RUN apt-get update \
&& apt-get install -y zlib1g-dev mariadb-client \
&& apt-get install -y libzip-dev \
&& docker-php-ext-install zip pdo_mysql
#作業ディレクトリを/var/wwwに設定する。
WORKDIR /var/www
### 結論
特別な理由がない限り仕様がわからないphp-pmは触らず、php-fpmを使用しましょう。
以上