【发布时间】:2018-09-07 08:48:30
【问题描述】:
我目前正在处理一个处理图片并将它们上传到数据库的 Android 应用程序。 该应用程序首先使用设备的摄像头,然后将生成的位图发送到 AsyncTask,该任务将调用 PHP API 以将图像作为 mediumBLOB 和附加数据(int 和 String)更新数据库。
AsyncTask 将 Bitmap 编码为字符串,并将所有需要的数据作为 POST 请求发送到 PHP 页面。
然后 PHP 页面收集数据,将字符串转换为 BLOB 图像,并在 mysqli 请求中使用它们在数据库表中插入新行。
更新:感谢您的反馈。我更改了 PHP 代码,以使用绑定变量。 虽然,当我将图像设置为参数时,请求会创建一个带有空 BLOB 的新表行。 我知道通常的方法是将图像存储在其他地方并在数据库中使用它们的名称/网址;但在我的情况下,使用 BLOB 是一项要求。
这是 AsyncTask 的 Android 代码:
public class DBTaskImageSending extends AsyncTask<String, Void, Void>
{
static final String TAG = "asyncSend";
private final String PARAMETER_PLACE = "location";
private final String PARAMETER_IMAGE = "image";
private final String PARAMETER_COMMENT = "comment";
private final String PARAMETER_OWNER = "owner";
Context mCContext;
UploadActivity mUAMain;
//The PHP page address :
String mURLAdress;
//Data to send to the PHP page :
String mComment;
int mID_Photographer;
int mID_Event;
String mImage; //The image in its final conversion before sending it.
public DBTaskImageSending(String url, UploadActivity ua, Context c, Bitmap img, String comment, int place, int owner)
{
this.mURLAdress = url;
this.mCContext = c;
this.mUAMain = ua;
this.mComment = comment;
this.mID_Event = place;
this.mID_Photographer = owner;
this.mImage = conv_Image_String(img);
}
@Override
protected void onPreExecute()
{
super.onPreExecute();
Log.i(TAG, "Request sent to "+mURLAdress);
}
@Override
protected void onPostExecute(Void result)
{
Log.i(TAG,"__________________________________________________");
super.onPostExecute(result);
}
@Override
protected Void doInBackground(String... strings)
{
try
{
sendImage(mURLAdress);
Log.i(TAG, "Object sent !");
}
catch (IOException ioe)
{
Log.i(TAG, "Sending failed.");
}
return null;
}
public void sendImage(String url) throws IOException
{
//Loading the POST data :
String mSCryptedData = URLEncoder.encode(PARAMETER_PLACE, "UTF-8")
+ "=" + URLEncoder.encode(Integer.toString(mID_Event), "UTF-8");
//----- owner ID :
mSCryptedData += "&" + URLEncoder.encode(PARAMETER_OWNER, "UTF-8")
+ "=" + URLEncoder.encode(Integer.toString(mID_Photographer), "UTF-8");
//----- Image comments :
mSCryptedData += "&" + URLEncoder.encode(PARAMETER_COMMENT, "UTF-8")
+ "=" + URLEncoder.encode(mComment, "UTF-8");
//----- the image itself :
mSCryptedData += "&" + URLEncoder.encode(PARAMETER_IMAGE, "UTF-8")
+ "=" + URLEncoder.encode(mImage,"UTF-8");//*/
ContentValues mCV = new ContentValues();
mCV.put(PARAMETER_PLACE,mID_Event);
mCV.put(PARAMETER_OWNER,mID_Photographer);
mCV.put(PARAMETER_COMMENT,mComment);
mCV.put(PARAMETER_IMAGE,mImage);
try {
//Eestablishing connection :
final HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
conn.setReadTimeout(5000); // milliseconds
conn.setConnectTimeout(5000); // milliseconds
//Setting up and sending the data :
conn.setDoOutput(true);
OutputStreamWriter mOSW = new OutputStreamWriter(conn.getOutputStream());
mOSW.write(mSDataCryptee);
mOSW.flush();
//Gathering the server's response:
readResponse(conn.getInputStream());
}
catch (Exception e)
{
Log.i(TAG,e.getCause().toString());
}
}
private void readResponse(InputStream pISBuilder) throws IOException
{
Log.i(TAG,"readR : Entering...");
BufferedReader mBR = new BufferedReader(new InputStreamReader(pISBuilder));
String ligne;
Log.i(TAG,"readR : Starting to read");
//Gathering the PHP response :
while ((ligne = mBR.readLine()) != null)
{
Log.i(TAG,ligne);
}
}
//* Function to convert the Bitmap to String :
private String conv_Image_String(Bitmap imgOrigin)
{
if (imgOrigin != null)
{
//The image is first converted to byte[] (or Blob), before being encoded to String.
ByteArrayOutputStream mBOS = new ByteArrayOutputStream();
imgOrigin.compress(Bitmap.CompressFormat.PNG,10, mBOS);
byte[] mBytImg = mBOS.toByteArray();
String mStrImg = Base64.encodeToString(mBytImg, Base64.DEFAULT);
return mStrImg;
}
else
{
return null;
}
}//*/
}
我重新制作了PHP代码,所以这是新版本:
<?php
if ((isset($_POST['location']) AND isset($_POST['owner'])) AND (isset($_POST['comment']) AND isset($_POST['image']))) {
$location = $_POST['location'];
$comment = $_POST['comment'];
$owner = $_POST['owner'];
$image = base64_decode($_POST['image']);
$image_b = imagecreatefromstring($image);
//*
if ($image_b == false) {
echo "error_image";
}
else {
$image_temp = imagegd($image_b, 'tmp');
$image_f = fopen('tmp',"r");
$image_blob = fread($image_f,filesize('tmp'));
sendData ($location,$comment,$owner,$image_blob);
}
}
else {
echo "error_parameters";
}
function sendData($p_location,$p_comment,$p_owner,$p_image){
$conn = mysqli_connect("localhost", "****", "****", "**DBName**", "3306");
if (!$conn) {
die('Could not connect to MySQL: ' . mysqli_connect_error());
}
else {
mysqli_query($conn, 'SET NAMES \'utf8\'');
$sqli = "INSERT INTO bar_a_image_test.Photo(
ID_Localisation_Photo,
ID_Photographe,
Date_Photo,
Ecartee,
Commentaire_Photo,
Image_Photo)
VALUES
( ? , ? , NULL, 0, ?, ? )";
if ($stmt = $conn->prepare($sqli));
{
$stmt->bind_param("iisb",$p_location, $p_owner, $p_comment, $p_image);
$stmt->execute();
}
$conn->close();
}
}
?>
现在的新问题是查询加载了数据库中的所有数据,除了图像。它只是在新行中记录一个空的 BLOB。 我正在寻找一种有效地将图像(编码为字符串)转换为 BLOB 的方法。 正如我之前提到的,我必须使用 BLOB,尽管外部存储更频繁。
【问题讨论】:
-
您的查询以一种可怕的方式实现,并且容易出现 XSS 错误。切勿对 SQL 查询使用字符串连接或插值,而是使用绑定变量。
-
通常的做法是将图片保存在文件中,文件名保存在DB中。
-
诚实的意见是这不是最好的方法,我建议使用像 Firebase 这样的东西。 Firebase 是免费的,实际上可以让您进行实时更新。另外,他们为您处理所有安全问题。如果您不是安全专家,最好不要尝试重新发明轮子。
-
@ZackMatthews 如果您认为 firebase 是免费的,那么您只有非常小的应用程序。
-
@GabeSechan 感谢您的反馈。我用 bind_param 更新了代码。虽然图像仍未加载,但 SQLi 查询可以正常工作。