質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.37%

ファイルを含むPOST値を受け取る方法

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 3,102

score 171

前提・実現したいこと

画面側(Nuxt.js)からサーバー側(CodeIgniter)にファイルとテキストボックスの値をPOSTしたいです。

最終的な環境はNuxt.jsとCodeIgniterが別々のサーバーで動きます。
今試しているのは開発環境で同じPC上で動いていますがポートが違います。

POSTする値にファイルが含まれるとサーバー側でテキストボックスの値も受け取れなくなる状態です。
どなたかご存知の方、アドバイス頂けたら幸いです。

発生している問題・エラーメッセージ

POST値にファイルが含まれるとサーバーで値を受け取れない
※下記該当のソースの「取得できるかの実験」のところでデバッグで確認しても値が取れていません。

該当のソースコード

(画面側)

<template>
    <div>
        <el-form ref="form" :model="form" label-width="120px">
            <el-form-item label="年月">
                <el-date-picker 
                    name="ym"
                    v-model="form.ym"
                    type="month"
                    placeholder="Pick a month">
                </el-date-picker>
            </el-form-item>
            <el-form-item label="ファイル">
                <input type="file" @change="selectedFile" name="uploadFile" />
            </el-form-item>
            <el-form-item>
                <div class="button-wrapper-mint" @click="upload">
                    保存
                </div>
            </el-form-item>
        </el-form>
    </div>
</template>
<script>
export default {
  data(){
    return {
        form: {
            ym: "",
            uploadFile: null,
        }
    }
  },
  methods:{ 
    selectedFile(e) {
        e.preventDefault();
        let files = e.target.files;
        this.form.uploadFile = files[0];
    },
    upload(){
        let config = {
            headers: {'content-type': 'multipart/form-data'}
        };
        let formData = new FormData();
        formData.append('ym', this.form.ym);
        formData.append('uploadFile', this.form.uploadFile);
        this.$axios.post(
            "http://~~~",
            formData,
            config
        ).then((response) =>{
            console.log(response);
        });
    }
  },
}
</script>

送信した時のForm Dataの中身(Chromeの開発者ツールから取得)
イメージ説明

(サーバー側)

 public function upload(){
    header('Access-Control-Allow-Origin: *');
    $method = $this->input->server('REQUEST_METHOD');
    if($method == "OPTIONS"){
      $this->output->set_content_type('application/json')->set_output(json_encode(array(
        "status" => "OK",
      )));
      return;
    }
    if($method != "POST"){
      return;
    }

    // 取得できるかの実験 ---------------------
    $ym= $this->input->get_post('ym', TRUE) ?: "";
    $_POST;
    $data = json_decode(file_get_contents("php://input"), TRUE);
    // -----------------------------------

    $config = array(
      'upload_path' => './upload',
      'overwrite' => TRUE,
      'allowed_types' => '*',
      'file_name' => date('YmdHis').".csv",
    );
    $this->load->library('upload', $config);

    if ( ! $this->upload->do_upload("uploadFile")) {
      $error = array('error' => $this->upload->display_errors());
      $this->output->set_content_type('application/json')->set_output(json_encode(array(
        "status" => "NG",
        "error" => $error // ☆<p>You did not select a file to upload.</p>
      )));
    } else {
      $this->output->set_content_type('application/json')->set_output(json_encode(array(
        "status" => "OK",
      )));
    }
  }


※デバッグで確認すると取得できるかの実験のところが3つとも空になります。
※☆の所の$errorには<p>You did not select a file to upload.</p>が入っていました。

試したこと

1. ソースを変えずに、画面でファイルを未選択で送信
⇒ ymの値は取得できた

2. axiosを使わずにformで送信 

<template>
    <div class="padding-box">
        <form method="POST" action="(URL)" enctype="multipart/form-data">
                <el-date-picker 
                    name="ym"
                    v-model="form.ym"
                    type="month"
                    placeholder="Pick a month">
                </el-date-picker>
                <input type="file" name="uploadFile" />
                <input type="submit" value="保存" />
        </form>
    </div>
</template>


⇒同じ状態(サーバー側でデータが取得できない)

3. 同じポートで動かしてみる
同じlocalhostでもポートが違うとCORSエラーが発生したので、Access-Control-Allow-Origin以外に設定がいるのか切り分けるため、Nuxt.jsをgenerateしたものをPHPを動かしているApacheで動かしてみましたが結果は同じでした。。。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

+1

multipartで送ってpostデータは$_POST(もしくはfilter_inputのINPUT_POST)で参照し
ファイルは$_FILESを参照してください

<?PHP
print_r($_POST);
print_r($_FILES);
?>
<form method="post" enctype="multipart/form-data">
<input type="text" name="hoge" value="123"><br>
<input type="file" name="fuga"><br>
<input type="submit" value="send">
</form>

fetch

<script>
window.addEventListener('DOMContentLoaded', ()=>{
  document.querySelector('form').addEventListener('submit',e=>{
    e.preventDefault();
    const url="send.php";
    const method = "POST";
    /*
    const headers = {'Content-Type': 'multipart/form-data'}; //うまく渡らない
    */
    const headers = {};
    const body=new FormData(e.target);
    fetch(url,{method, headers, body}).then(res=>res.text()).then(console.log);
  });
});
</script>
<form method="post" enctype="multipart/form-data">
<input type="text" name="hoge" value="123"><br>
<input type="file" name="fuga"><br>
<input type="submit" value="send">
</form>
  • send.php
<?PHP
print_r($_POST);
print_r($_FILES);
?>

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/09/17 16:38

    回答ありがとうございます。
    formの時はformに「enctype="multipart/form-data"」、axiosの時は「{headers: {'content-type': 'multipart/form-data'}}」をpostの第三引数に渡しているのでmultipartで送ったことになっているという認識です。。。他に何か必要でしょうか?

    キャンセル

  • 2019/09/17 17:07

    axiosの仕様がよくわからないのですが、fetchだとcontent-typeとか指定すると
    データ受け渡しがうまくいかないので、headersを省略してみては?

    キャンセル

  • 2019/09/17 21:17

    アドバイス頂いたことも含めて色々試してみても状況が変わらなかったのですが、ダメ元で同じプログラムを開発環境ではないパソコンに入れて動かしてみたらアップロードできてしまいました。
    開発環境と動いた環境のリクエストヘッダーを比べてみたら、開発環境だけ「Sec-Fetch-Mode:cors」「Sec-Fetch-Site: same-origin」と出ていました。
    これが何かは調べている最中ですが、そもそもソースの問題じゃないのかもしれません。
    アドバイス頂いたのにすみません。。。

    キャンセル

check解決した方法

0

原因はphp.iniのpost_max_sizeでした。
画面上にエラー等が出る設定にしているので疑いもしませんでしたが、レスポンスjsonだから画面がない・・・。

プログラムを別のサーバーで動かしたら正常に動いたことから、プログラムが原因じゃないかもしれないと疑い始めて、片っ端から設定ファイル的なものを見比べていて発見しました。
質問に散々ソースを載せたのにすみません。。。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.37%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る