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

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

ただいまの
回答率

87.59%

Ajaxでテキストデータと画像データを送信したいが画像のみ送信されない

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 2,084

score 27

実現したいこと

現在簡易的なCMSを想定したジェネレータのようなものを作成しており、
ジェネレータからサーバー内に画像をアップロードする処理を作成しております。

▼基本的な動作の流れ

  1. inputタグ(type="text")にURLを記載
  2. inputタグ(type="file")でアップロードしたいファイルを指定(※1枚~複数枚)
  3. ボタンをクリックしてAjaxからPHPにデータを送信
  4. PHP側でデータを受け取る
  5. 「1」で入力された階層に行きフォルダがあればそのフォルダ内に画像をアップロード
  6. 「1」で入力された階層に行きフォルダがなければフォルダを作成したあとそのフォルダに画像をアップロード

発生している問題

今回発生しているものは、基本的な動作の流れの③にあたる部分です。

送信したいデータは①のURLとなるテキストデータと、②の画像ファイルです。
この①のテキストデータはきちんとPHPに受け渡しができており、この①のデータを元に⑤と⑥のフォルダ判別ができています。

しかし、画像データを送信することができていないためフォルダは作成できても画像がアップロードできません。

問題のコード

以下コードで実際に動かすと、PHP側から「ajaxから送信されてきたデータが空っぽだよ」が返ってきます。
※フォルダの作成もこの時点ではできていません。

しかしjs内の以下
var formdata = new FormData($('#img').get(0));
'formdata': formdata
processData: false,
contentType: false,
をコメントアウトして実行すると、フォルダの作成は実行されました。

なのでおそらくはPHP側の問題ではなくjs側の問題だとは思うのですが、原因がわからず困惑しています。

<input type="text" name="url" id="url" >
<input type="file" id="img" name="img" multiple="multiple" accept="image/*">
<div id="file_select_uploaed">アップロードボタン</div>
$('#file_select_uploaed').click(function () {
    var uploadPass = $('#url').val(); // URL文字列を取得
    var formdata = new FormData($('#img').get(0)); // FormData オブジェクトを作成

    //サーバーに送る画像と作成する階層を指定
    var data = {
        'imgPass': uploadPass,
        'formdata': formdata
    };

    $.ajax({
        url: 'form.php',
        type: 'POST',
        data: data,
        processData: false,
        contentType: false,
        success: function (data) {
            alert(data);
        },
        error: function (data) {
            alert("ajaxエラー");
        }
    });
});
<?php
if (!empty($_POST)) {

    /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ここに今回とは関係ない別の処理があります
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */

    //==========画像フォルダの作成と画像の書き出し
    if(!empty($_POST['imgPass'])){

        $imgPass = $_POST['imgPass']; //作成したいディレクトリ(のパス)
        $imgData = $_FILES['formdata']['name']; //サーバーに送りたい画像の本来のファイル名

        //URLをフルパスから相対パスに置換
        $imgPass = str_replace('https://hogehoge/hugahuga/', '../../aaa/bbb/', $imgPass);

        //「$imgPass」で指定されたディレクトリが存在するか確認
        if(file_exists($imgPass)){ //ディレクトリが存在したときの処理
            //file_existsでフォルダの中にファイルが存在しているか判定
            if(file_exists($imgPass.$imgData)) {
                echo '作成しようとしたファイルは既に存在します。'; // ファイルはすでにあると通知
            } else {
                if (move_uploaded_file($imgPass, $imgPass)) {
                    echo $imgData . "をアップロードしました。";
                } else {
                    echo "ファイルをアップロードできません。";
                }
            }

        }else{ //ディレクトリが存在しないときの処理(「$imgPass」で指定されたディレクトリを作成する)
            if(mkdir($imgPass, 0777)){
                //作成したディレクトリのパーミッションを確実に変更
                chmod($imgPass, 0777);

                // file_existsでフォルダの中にファイルが存在しているか判定
                if(file_exists($imgPass.$imgData)) {
                    echo '作成しようとしたファイルは既に存在します。'; // ファイルはすでにあると通知
                } else {
                    if (move_uploaded_file($imgData, $imgPass)) {
                        echo $imgData . "をアップロードしました。";
                    } else {
                        echo "ファイルをアップロードできません。";
                    }
                }
            }else{
                //ディレクトリの作成に失敗した時の処理
                echo "ディレクトリの作成に失敗しました";
            }
        }
    }
} else {
    echo 'ajaxから送信されてきたデータが空っぽだよ';
}
?>

画像を送信しようとすると、PHP側から「ajaxから送信されてきたデータが空っぽだよ」が返ってくるということは
そもそもデータが空?ということになると思うのですが、
画像を送らずURLのテキストのみを送れば動くものが、なぜ画像のデータが含まれると空と判定されるのか理由がわからず…。

そもそもこのjsでは画像が取得できていないのでしょうか?

何卒宜しくお願い致します。


▼参考にしたサイト
jQuery Ajaxでファイルを送りたい!
コピペで使う!画像アップロード付きAjax(JQuery)フォームサンプル
jQueryを使ってajaxでファイル送信
PHPの入力値確認ではなぜisset関数ではなくempty関数を使うのか

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • miyabi_takatsuk

    2019/05/28 23:47 編集

    全然全く自信がないので、こちらで・・・。
    (調査も併せてさせていただきます)
    なんとなくですが、送信側のAjaxの、dataType指定や、MIMETypeの指定、enctype属性など、
    そこら辺の指定が足りないせいな気がします。
    特に参考記事二つ目の、dataTypeが、htmlとなっているのが非常に疑問です。
    画像やドキュメントファイルの送信の場合、
    そのdataTypeやMIMETypeといった、
    送信側のデータ型設定は重要だったりします。
    (サーバーサイド側で、正しく送信してないものはデータとして認識すらしてくれない場合がある)
    そこあたりを、みて、再度調査いただくと、もしかしたら答えが見つかるかも。
    ひとまず、こちらでも記載のソースコード使ってやってみますね。

    キャンセル

回答 1

checkベストアンサー

+1

原因がわかりましたので、回答させていただきます。
mimetypeなどが原因ではありませんでしたすみません。

原因は、送信側の書き方で、FormDataクラスの初期化の対象となる要素が間違っているです。
現在、input要素をFormDataの引数にいれておりますが、
FormDataの引数にいれて有効になるのは、form要素です。

よって、正しくは下記になります。

<!-- form要素で囲みます。actionはつけてません。(ajax送信するので) -->
<form id="formParent" name="formParent">
<!-- PHP側で受け取るために、name値に、最終的に適用する引数名を入れている -->
<input type="text" name="imgPass" id="imgPass">
<input type="file" id="formdata" name="formdata" multiple="multiple" accept="image/*">
<div id="file_select_uploaed">アップロードボタン</div>
</form>

<script>
$('#file_select_uploaed').click(function () {
  // FormDataの中にinputも含まれるため、下記は使わない。
  //var uploadPass = $('#url').val(); // URL文字列を取得
  // form要素でなければいけない。
  var formdata = new FormData(document.forms.formParent);


  //サーバーに送る画像と作成する階層を指定
  // これも、form > inputの中にデータが階層づけられているので、いらない
  /*
  var data = {
    'imgPass': uploadPass,
    'formdata': formdata
  };
  */

  $.ajax({
    url: 'form.php',
    type: 'POST',
    data: formdata,
    processData: false,
    contentType: false,
    success: function (data) {
      alert(data);
    },
    error: function (data) {
      alert("ajaxエラー");
    }
  });
});
</script>

そもそも、FormDataクラスは、form要素(中のinputとかも全部含んだ)をJS上で扱えるようにするクラスみたいですね。

ただし、この状態で、データの送信はうまくいきましたが、アップロードはうまくいかなかったので、
この先は、php側の修正になるかと思います。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/05/29 10:35

    いいですね、自分で調べて答えを見つけることによって、先に進みやすくなります。
    エンジニアの技術力は、調査力と比例しているように最近思います。
    頑張ってください〜

    キャンセル

  • 2019/05/29 10:58

    ↓以下記事を参考に修正して、無事理想とする動きになりました!
    https://qiita.com/yasumodev/items/cffb735f46ffd489a4db

    一部記述の仕方が間違っている場所もあり諸々なおすことで達成できました。

    いろいろご教示いただき大変感謝しております。
    ありがとうございました。ベストアンサーとさせていただきます!

    キャンセル

  • 2019/05/29 11:01

    BAありがとうございます!
    解決できてよかったですね!
    実は私自身、大変に勉強になりましたので、むしろこちらこそ感謝です。
    ありがとうございます。

    キャンセル

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

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

関連した質問

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