2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

PHP/Laravel/ Docker php-pmの画像投稿でハマった

Posted at

###背景
vue/phpを使って画像投稿するサイトを作っていました。

問題

ローカルでのビルトインサーバでは画像投稿できるが、
'''request->file実行時 Docker起動のビルトインサーバで画像投稿  validation:update```
と表示されて、画像投稿できない。

###結論
php-pmでは/private/var/にtmpファイル保存されていないことが原因だったので、php-fpmを使うことにしました。

前提

怪しいと思われるLaravel側でログ出力画像を投稿するstoreメソッドに
Logを仕込んで確認しました。

php-pm

Dockerfile
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側

Create.php
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側

js
<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>

###エラー確認

phpの画像投稿 ローカル起動時
[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

と表示されている。

laravellogs-error時
[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,                                                        
  )),                                                                           
)                                                                               
   
php-fpm下での画像投稿結果
[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-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を使用しましょう。

以上

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?