在PHP/Laravel/Docker中使用php-pm进行图片上传遇到的问题
背景
我使用Vue/PHP开发了一个图片上传的网站。
请提出问题。
在本地内置服务器中,可以进行图片上传,但是在执行request->file时,在Docker启动的内置服务器中进行图片上传,会显示validation:update,并且无法进行图片上传。
结论
由于在php-pm中未将tmp文件保存在/private/var/目录下,所以我们决定使用php-fpm。
前提 – premise
我在Laravel的store方法中添加了Log来确认并上传了一个被认为是可疑的日志输出图像。
php-pm 可以将 PHP 应用程序作为持久运行的进程执行,而不是每个请求都重新启动。
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側可以表示为”Vue方面”或”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
请求为/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文件夹中。
猜测
在本地环境中,request()->file()函数会有返回值,而在Docker中使用php-pm时,该函数没有返回值。而在Docker中使用php-fpm时,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。
以上