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

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

ただいまの
回答率

90.53%

  • PHP

    20256questions

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

  • Java

    13745questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

  • Android

    6504questions

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

画像と文字列を同時に送りたい(PHP->Android)

解決済

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 756

takg

score 57

前提・実現したいこと

サーバ側PHPでDBからSELECTした画像及び文字列を、Android端末に渡したいと考えています。
画像単体の受け渡しには成功したのですが、同時に文字列も同時に受け渡すとなると方法が良く分からず困っております。
下記処理に、どのような加筆をすれば良いでしょうか?
宜しくお願いします。

    $sql = "SELECT image FROM xxx WHERE name = ?";
    if ($stmt = $mysqli->prepare($sql)) {
        global $searchWord;
        // 条件値をSQLにバインドする
        $stmt->bind_param("s", $searchWord);

        // 実行
        $stmt->execute();

        // 取得結果を変数にバインドする
        $stmt->bind_result($image);
        while ($stmt->fetch()) {
            header('Content-type: image/jpeg');
            echo $image;
        }
        $stmt->close();
    }
@非同期処理クラス
       //略

            URL url = new URL(mURL);
            HttpURLConnection connection = (HttpURLConnection)url.openConnection();

            // 接続
            connection.connect();

            //略

            //画像デコード
            InputStream inputStream = connection.getInputStream();
            Bitmap bitmap_result = BitmapFactory.decodeStream(inputStream);
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 3

checkベストアンサー

+1

サーバで画像をbese64にエンコードして、文字列と一緒にjson化して、クライアント側でbese64をデコードして画像を読むという方法はどうでしょうか。これならGET通信だけでいけます。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/03/04 12:57

    ご回答ありがとうございます。

    base64エンコードの場合、データ量が増えることによる支障が出ないか気になっています。
    別の方がmultipart/form-dataを用いた方法について言及されていたのですが、
    どちらの手法がより一般的なのでしょうか?

    キャンセル

  • 2017/03/04 13:19

    軽量の画像ならbese64にしてしまって送っても大丈夫かなと思います。
    割りと大きめの画像なら画像のurlのみをjsonに記載する方が一般的かと。github等の有名なapiだとそんな感じですね。

    キャンセル

  • 2017/03/04 16:52

    現在DBに画像を保存しているので、やはりbase64を使う方向で試してみようと思います。
    処理の重さが気になるようならサーバのフォルダに画像を配置して、
    仰るようなURLを渡す方法に移行しようと思います。

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

    キャンセル

+1

MessagePackを使用すればバイナリのまま送信できます。
サイト見ればわかりますが、様々な言語で実装されています。

サンプル

PHP側のMessagePackライブラリは、Msgpack for PHPが有名ですが、私のマシンだとインストールできない(pecl自体がそもそも不具合を起こしてる)ため、composerでインストールできるrybakit/msgpackを使用しています。
PHP側
PHPのMessagePackライブラリインストールはcomposerで行います。

$ composer require rybakit/msgpack
<?php
require_once "vendor/autoload.php";

use MessagePack\Packer;

$img1 = file_get_contents('1.jpg');
$img2 = file_get_contents('2.jpg');
$img3 = file_get_contents('3.jpg');

$data = [
  'text1' => 'ほげ',
  'text2' => 'ふが',
  'bool1' => true,
  'boo2' => false,
  'int1' => 3,
  'int2' => 1234567890,
  'float1' => 4.568,
  'float2' => 789.0123456,
  'array1' => ['ふが', 11],
  'array2' => ['ピヨ', true, false, 123, 456.789],
  '1.jpg' => $img1,
  '2.jpg' => $img2,
  '3.jpg' => $img3
];

$packer = new Packer();
$res = $packer ->packMap($data);
echo $res;
?>


Android側
AndroidのMessagePackライブラリのインストールはbandle.gradle(Module: app)のdependenciesにcompileの行を追加し、syncさせればインストールされます。
bandle.gradle(Module: app)

dependencies {
    compile 'org.msgpack:msgpack-core:0.8.12' //  この行を追加
}

activity_main.xml

<?xml version= "1.0" encoding= "utf-8" ?>
  <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.ritto.myapplication.MainActivity">

    <ScrollView
      android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true"
        android:clipToPadding="false"
        tools:ignore="UselessParent">

    <LinearLayout
      android:id="@+id/layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

      <Button
      android:id="@+id/button"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="HTTPデータ取得"
                tools:ignore="HardcodedText" />

      <TableLayout
      android:id="@+id/table"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:stretchColumns="0,1">

      </TableLayout>

    </LinearLayout >
  </ScrollView >
</RelativeLayout >


MainActivity.java

package com.example.xxx.myapplication; //張り付けた後自分のパッケージ名に修正する

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;

import org.msgpack.core.MessagePack;
import org.msgpack.value.ArrayValue;
import org.msgpack.value.ExtensionValue;
import org.msgpack.value.FloatValue;
import org.msgpack.value.ImmutableValue;
import org.msgpack.value.IntegerValue;
import org.msgpack.value.Value;
import org.msgpack.value.ValueType;
import java.math.BigInteger;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;

public class MainActivity extends AppCompatActivity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  Button btn = (Button) findViewById(R.id.button);
  final TableLayout table = (TableLayout) findViewById(R.id.table);
  final Handler handler = new Handler();

  btn.setOnClickListener(new View.OnClickListener() {
          @Override
  public void onClick(View v) {
    table.removeAllViews();
    new Thread(new Runnable() {
                  @Override
    public void run() {
      try {
        URL url = new URL("http://10.0.2.2/msgpack_test.php");
        HttpURLConnection con = (HttpURLConnection) url.openConnection();
        final ImmutableValue iv = MessagePack.newDefaultUnpacker(con.getInputStream()).unpackValue();

        handler.post(new Runnable() {
                              @Override
        public void run() {
          for (Map.Entry < Value, Value > kv : iv.asMapValue().entrySet()) {
            kv.getValue().getValueType();
            Value key = kv.getKey();
            Value val = kv.getValue();

            TableRow row = new TableRow(MainActivity.this);
            table.addView(row);
            TextView keyView = new TextView(MainActivity.this);
            keyView.setText(key.toString());
            row.addView(keyView);
            View valView;
            if (val.getValueType() == ValueType.BINARY) {
              valView = new ImageView(MainActivity.this);
              ((ImageView) valView).setLayoutParams(new TableRow.LayoutParams(200, 200));
            } else {
              valView = new TextView(MainActivity.this);
            }

            row.addView(valView);

            switch (val.getValueType()) {
              case NIL:
                keyView.setText(key.toString() + " [Null]");
                ((TextView) valView).setText(val.toString());
                break;
              case BOOLEAN:
                boolean b = val.asBooleanValue().getBoolean();
                keyView.setText(key.toString() + " [Boolean]");
                ((TextView) valView).setText(b ? "true" : "false");
                break;
              case INTEGER:
                IntegerValue intVal = val.asIntegerValue();
                if (intVal.isInIntRange()) {
                  int i = intVal.toInt();
                  keyView.setText(key.toString() + " [int]");
                  ((TextView) valView).setText(String.valueOf(i));
                } else if (intVal.isInLongRange()) {
                  long l = intVal.toLong();
                  keyView.setText(key.toString() + " [long]");
                  ((TextView) valView).setText(String.valueOf(l));
                } else {
                  BigInteger i = intVal.toBigInteger();
                  keyView.setText(key.toString() + " [BigInteger]");
                  ((TextView) valView).setText(String.valueOf(i));
                }
                break;
              case FLOAT:
                FloatValue fv = val.asFloatValue();
                //float f = fv.toFloat();   // use as float
                double d = fv.toDouble(); // use as double
                keyView.setText(key.toString() + " [float/double]");
                ((TextView) valView).setText(String.valueOf(d));
                break;
              case STRING:
                String s = val.asStringValue().asString();
                keyView.setText(key.toString() + " [String]");
                ((TextView) valView).setText(s);
                break;
              case BINARY:
                byte[] mb = val.asBinaryValue().asByteArray();
                // Binaryは画像前提
                Bitmap bmp = BitmapFactory.decodeByteArray(mb, 0, mb.length);
                keyView.setText(key.toString() + " [Bitmap]");
                ((ImageView) valView).setImageBitmap(bmp);
                break;
              case ARRAY:
                ArrayValue a = val.asArrayValue();
                keyView.setText(key.toString() + " [Array]");
                StringBuilder sb = new StringBuilder();
                sb.append("[");
                String spl = "";
                for (Value e : a) {
                  sb.append(spl + e);
                  spl = ", ";
                }
                sb.append("]");
                ((TextView) valView).setText(sb.toString());
                break;
              case EXTENSION:
                ExtensionValue ev = val.asExtensionValue();
                byte extType = ev.getType();
                byte[] extValue = ev.getData();
                keyView.setText(key.toString() + " [Extension(" + String.valueOf(extType) + ")]");
                ((TextView) valView).setText(String.valueOf(extValue));
                break;
            }
          }
        }
      });
    } catch (Exception ex) {
      System.out.println(ex);
    }
  }
}).start();
          }
      });
  }
}

イメージ説明

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

0

データやヘッダーをmultipart/form-dataに準拠するように修正する必要があります。
おそらく今のコードに加筆するというのは難しいです。一度multipart/form-dataについて調べて、実装したあとに再度質問した方がいいですよ。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/03/04 16:46

    ありがとうございます。
    仰る手法について調べてみます。

    キャンセル

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

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

関連した質問

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

  • PHP

    20256questions

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

  • Java

    13745questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

  • Android

    6504questions

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