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

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

ただいまの
回答率

90.50%

  • PHP

    20367questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

  • Android

    6527questions

    Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

  • MySQL

    5858questions

    MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Base64エンコードされた画像ファイルをMySQLでMEDIUMBLOBにUPDATEしたい

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,199

takg

score 70

前提・実現したいこと

初心者です。
android端末から、外部サーバのDBに画像を保存しようとしています。

android上でbitmapをBase64のStringにエンコードしJSONに詰め、
外部サーバ上のPHPで受け取った後にバイナリに変換、
MySQLで、TABLEに既に存在する行のMEDIUMBLOB型カラムをUPDATEしたいと考えていますがうまくゆきません。
$mysqli->affected_rows
でクエリの結果を確認してみると、-1が返されます。

MySQLのMEDIUMBLOB型カラムにはバイナリを投げればよいとの認識なのですが、以下のコードではそれが実現できていないのでしょうか?

宜しくお願いします。

該当のソースコード

(PHP)
//androidからPOSTされたJSONを受け取る
$json_string = file_get_contents('php://input');

//連想配列型にデコード
$obj = json_decode($json_string,true);
//Base64型にエンコードされた画像データを取り出す
$img = $obj['strBase64'];
//バイナリデータに戻す
$fileData = base64_decode($img);

//略

//画像の投稿
$mysqli->query("UPDATE xxx SET image = $fileData  WHERE name = 'xxx'");

//略

試したこと

MySQLでのバイナリデータ登録には16進法記述への変換が必要、との記述を見つけたので、
$hexFileData = bin2hex($fileData);
のようにして変換した値をクエリに使用してみましたが、こちらもうまくゆきませんでした。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 3

checkベストアンサー

+2

$mysqli->query("UPDATE xxx SET image = $fileData  WHERE name = 'xxx'");

文字列リテラルとして扱うのなら$fileDataの値を直接SQL文の中に書いてもだめですね。SQL文の中の文字列リテラルの書きかたはMySQLマニュアル「文字列リテラル」を参照。正しく文字列リテラルにするには''で囲んだだけではだめなのがわかります。

MySQLでのバイナリデータ登録には16進法記述への変換が必要、との記述を見つけたので、

これは、SQL文の中でバイナリ文字列を直接記述する場合は16進数リテラルを使うこともできる、というものです。詳細はMySQLマニュアル「16 進数リテラル」参照。文字列リテラルにするにはbin2hex()の結果をそのままSQL文の中に書いてもだめなのがわかります。


上のようにデータを直接SQL文の中に埋め込む方法は、難しいし間違いも起きやすいので、プリペアド・ステートメントを使うことを勧めます。次のようなコードでできます。

$stmt = $mysqli->prepare("UPDATE xxx SET image = ? WHERE name = 'xxx'");
$stmt->bind_param("b", $fileData);
$stmt->execute();

ここでは、SQL文を準備 (prepare) し、そのパラメータ (SQL文中で?で表される) にデータをバインドしてから、文を実行しています。データが文字列になるようにエスケープしたりする必要はありません。PHPマニュアル MySQLiのprepareも参照。

しかしこれだと、バインドするデータのサイズが大きくなると動作しません (具体的には、MySQLのmax_allowed_packet設定パラメータの値より大きいサイズのデータは扱えません)。データサイズが大きくなるおそれがあるのなら、データをパケットサイズで分割して送るようにします。下記のようにします。

$stmt = $mysqli->prepare("UPDATE xxx SET image = ? WHERE name = 'xxx'");
$null = NULL;
$stmt->bind_param("b", $null);
$stmt->send_long_data(0, $fileData);
$stmt->execute();

NULLをいったん$null変数に入れているのは、bind_param()の第2引数が参照渡しであるためです。bind_param()の行とその前の行は、BLOBデータではこうするものだと思っておいてください。send_long_data()で実際のデータを送信してから、文を実行しています。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/02/28 10:37

    ご丁寧にありがとうございます。

    prepared statementの存在は認識しておりましたが、
    エスケープの回避というメリットがあることは存じ上げませんでした。
    MySQLリファレンスのソースも添えて頂き、大変勉強になりました。
    ご教示頂いた方法を試してみようと思います。

    また、データサイズが大きいケースの対処法も添えて頂き、助かりました。
    おそらくその点も考慮に入れる必要がありそうです。

    素朴な疑問なのですが、
    >正しく文字列リテラルにするには'…'で囲んだだけではだめなのがわかります。
    というご指摘は、MySQLリファレンスを読む限りでは特殊文字のエスケープに関するものだと思うのですが、
    $fileData = $mysql_real_escape_string($fileData);
    $mysqli->query("UPDATE xxx SET image = '$fileData' WHERE name = 'xxx'");
    等の手段を採るならば、一応は正しくクエリが実行されることになるのでしょうか?
    (もちろんこの方法を使うつもりはありません。)


    キャンセル

  • 2017/02/28 11:09

    おっしゃる通り、エスケープの話です。そんなような感じのコードで動くと思います。
    が、そのコードの方法だと、プログラム中に現れるすべての文字列パラメータをエスケープするよう気をつけておかなければなりません。万一どこかでエスケープを忘れると「SQLインジェクション」を起こせるようになってしまいます。

    プリペアド・ステートメントを勧める理由は、BLOBを簡単に扱えるからだけでなく、SQLインジェクションを回避したコードを確実に書けるという点も大変重要だと思います。

    キャンセル

  • 2017/02/28 14:45

    確かに、POSTされたすべての変数をエスケープするのは危険で不毛ですね。
    良く分かりました。

    御陰様でクエリ実行周りの知識が整理されました。
    ご助言ありがとうございました。

    キャンセル

  • 2017/03/02 17:12

    もう1点、プリペアド・ステートメントに関してお伺いしても宜しいでしょうか?
    何度も申し訳ありません。

    以前の件に関しましては、ikedas様の方法でUPDATEに成功致しました。
    ご教授頂いたプリペアド・ステートメントを用いて、過去に書いたクエリ実行コードを改変しているのですが、SELECT文に関する部分で、

    $mysqli->query("SELECT * FROM xxx WHERE name = 'yyy'");
    だとうまくゆくのに、

    $stmt = $mysqli->prepare("SELECT * FROM xxx WHERE name = ?");
    $stmt->bind_param("s", $searchWord);
    $searchWord = "yyy";
    $stmt->execute();
    だとうまくゆかない($mysqli->affected_rowsが-1を返す)
    という状況に陥り、原因が分からず困っております。

    何か問題点等ございましたら、お教え願えないでしょうか?

    キャンセル

  • 2017/03/02 17:25

    「$searchWord = "yyy";」を書く順番がおかしくないですか。
    エラーの詳細を、$mysqli->errorや$stmt->errorで確認するようにして下さい。

    キャンセル

  • 2017/03/03 12:22

    mysqli->errno,mysqli->error,stmt->error,mysqli->sqlstate
    のどれを試しても、エラーは返されず、ただ
    $mysqli->affected_rowsが-1を返してくる状況です。

    >「$searchWord = "yyy";」を書く順番がおかしくないですか。
    このご指摘について、具体的にどういった点が間違っているとお考えかお伺いしてもよろしいでしょうか?
    お手間お掛けし申し訳ありません。

    キャンセル

  • 2017/03/03 12:54

    あ、そうか。おかしくないですね。
    PHPマニュアルのmysqli_stmt::$affected_rowsの説明を読んで下さい。

    キャンセル

0

JSONではなく、バイナリーでPOSTすればいいのではないでしょうか?(multipart)

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/02/28 10:14

    恥ずかしながらmultipartを用いたPOSTの手法を存じ上げませんでした。
    この方が汎用性が高く、またBase64エンコードに伴うデータ量増加という点からも
    良いように思われました。
    仰るように、バイナリによるPOSTを検討してみようと思います。

    ご助言ありがとうございました。

    キャンセル

0

単純に、クオートしてないからでは?

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/02/28 10:21

    仰る通り、引用符をつけるとクエリは成功致しました。
    引用符が必要になるのはVARCHAR型のみとの誤った認識がありました。

    その場合、別の方に指摘頂いた(おそらくエスケープシーケンス関連の)問題が生じるようですので、
    prepared statementを利用する方向で探ってみようと思います。

    ご助言ありがとうございました。

    キャンセル

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

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

関連した質問

  • 解決済

    phpのページングについて

    // result.php require( 'config.php' ); require( 'lib.php' ); // if ( $_GET['page'] == ''

  • 解決済

    画面遷移なしで編集したいのですが、書き方が全くわかりません。。

    「編集」と「削除」を画面遷移なしで実行したいのですが、ajaxが分からず困っています。どうすれば、意図した結果が得られるでしょうか?>< PHPとMySQLを使っています。 PH

  • 受付中

    ●mysqlがphpmyadminでは動くのに、phpでは動かない。

    var_dumpした文字列をphpmyadminのsqlで実行するとDBに入るのですが、 localのphp上で動かすとDBに入らなくて困ってます。 ご教授頂けます

  • 解決済

    サイトない検索

    今回、サイト内「鈴木 スポーツ」検索ワードで検索すると検索データが出るようなプログラムを作りたいです。 DBから参照すること。 テーブル'topic','user','

  • 解決済

    登録フォームに内容を記述してもDBに反映されない

    前提・実現したいこと こんちわ。システム開発の勉強を独学でしてます。 現在、登録内容を記述してボタンを押すとDBに反映されるように練習してます。 しかし、下記内容で困ってます

  • 解決済

    複数の変数のupdateについて

    各店舗(id)のリーダー(leaders)に、なる(value=2)ならない(value=3)をupdateしたいのですが以下のコードを実行してもカラムの値が変わることはありません

  • 受付中

    PHP データベース接続について

    PHPでデータベースを接続しようとしてもなかなかうまく接続できません。 なので、どのようにコードを書けば接続できるのでしょうか? 初めたてであまりよくわかっていないです...

  • 受付中

    PHP SQL文からの取得について

    PHPの勉強のため、簡易的なショッピングサイトを作っています。 カテゴリ検索をしたいのでDB内にデータを入れ、それを表示させリンクにしています。 そしてそのリンクから飛んだ時にその

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

  • PHP

    20367questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

  • Android

    6527questions

    Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

  • MySQL

    5858questions

    MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。