My android app needs to fetch some info from a php server that hosts a MySQL database. It works fine so far. The server encodes the info into JSON and sends it and then I can parse it well.
But now I need to also fetch an image together with each row of info I get from the DB. The info I'm getting has a field where it specifies the path where the correspondent image is located in the filesystem.
So, once I get the paths of the images, how do I read them so that I can send them together with the info rows obtained? Can I JSON encode the images together with the info? Or should I read them one by one with readfile once I have the info in the android app? If it can be done with JSON, how do you parse the data of the image afterwards? Can you provide an example?
One way to get an image in textform would be to use base64. I have used it with several webservices and there is decoders for Android out there, actually. There is one in the source code since API level 8. http://developer.android.com/reference/android/util/Base64.html but since I want to target other levels I include it myself.
One easy way would then be to save the image in a database instead as a file.
This is what I did to fetch the images together with the data. I post it so that if it can help someone.
This is the part of the PHP script that sends the data in the server side:
$i=0;
//$sql contains the result from the query of the data
while($row=mysql_fetch_array($sql)){
$output[]=$row;
//Here we fetch the image from the files table
$query = "SELECT path, type FROM FILES WHERE poi_id = '" . mysql_real_escape_string(trim($output[$i][0])) . "'";
$r = mysql_query($query);
$img = mysql_fetch_array($r);
$bin = base64_encode_image($img[0]);
//Let's append the image and the type to the data output.
$output[$i]['img'] = $bin;
$output[$i]['type'] = $img[1];
$i++;
}
//This method sends the response to the Android app
//You can just use echo(json_encode($output));
RestUtils::sendResponse(200, json_encode($output), 'application/json');
And then in the Android app, after parsing the JSON, you can save the base64 string as an image to the file system like this:
public void createImage(String image, String name){
try{
byte[] imageAsBytes = Base64.decode(image.getBytes(), Base64.DEFAULT);
Bitmap img_bitmap = BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length);
FileOutputStream fos = openFileOutput(name, Context.MODE_WORLD_READABLE);
img_bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.flush();
fos.close();
}
catch(Exception e){
e.printStackTrace();
}
}
for downloading image from path
public void DownloadImageFromPath(String path){
InputStream in =null;
Bitmap bmp=null;
ImageView iv = (ImageView)findViewById(R.id.img1);
int responseCode = -1;
try{
URL url = new URL(path);//"http://192.xx.xx.xx/mypath/img1.jpg
HttpURLConnection con = (HttpURLConnection)url.openConnection();
con.setDoInput(true);
con.connect();
responseCode = con.getResponseCode();
if(responseCode == HttpURLConnection.HTTP_OK)
{
//download
in = con.getInputStream();
bmp = BitmapFactory.decodeStream(in);
in.close();
iv.setImageBitmap(bmp);
}
}
catch(Exception ex){
Log.e("Exception",ex.toString());
}
}
Related
Is there any way of providing a file download from a JSF backing bean action method?
I have tried a lot of things. Main problem is that I cannot figure how to get the OutputStream of the response in order to write the file content to. I know how to do it with a Servlet, but this cannot be invoked from a JSF form and requires a new request.
How can I get the OutputStream of the response from the current FacesContext?
Introduction
You can get everything through ExternalContext. In JSF 1.x, you can get the raw HttpServletResponse object by ExternalContext#getResponse(). In JSF 2.x, you can use the bunch of new delegate methods like ExternalContext#getResponseOutputStream() without the need to grab the HttpServletResponse from under the JSF hoods.
On the response, you should set the Content-Type header so that the client knows which application to associate with the provided file. And, you should set the Content-Length header so that the client can calculate the download progress, otherwise it will be unknown. And, you should set the Content-Disposition header to attachment if you want a Save As dialog, otherwise the client will attempt to display it inline. Finally just write the file content to the response output stream.
Most important part is to call FacesContext#responseComplete() to inform JSF that it should not perform navigation and rendering after you've written the file to the response, otherwise the end of the response will be polluted with the HTML content of the page, or in older JSF versions, you will get an IllegalStateException with a message like getoutputstream() has already been called for this response when the JSF implementation calls getWriter() to render HTML.
Turn off ajax / don't use remote command!
You only need to make sure that the action method is not called by an ajax request, but that it is called by a normal request as you fire with <h:commandLink> and <h:commandButton>. Ajax requests and remote commands are handled by JavaScript which in turn has, due to security reasons, no facilities to force a Save As dialogue with the content of the ajax response.
In case you're using e.g. PrimeFaces <p:commandXxx>, then you need to make sure that you explicitly turn off ajax via ajax="false" attribute. In case you're using ICEfaces, then you need to nest a <f:ajax disabled="true" /> in the command component.
Generic JSF 2.x example
public void download() throws IOException {
FacesContext fc = FacesContext.getCurrentInstance();
ExternalContext ec = fc.getExternalContext();
ec.responseReset(); // Some JSF component library or some Filter might have set some headers in the buffer beforehand. We want to get rid of them, else it may collide.
ec.setResponseContentType(contentType); // Check http://www.iana.org/assignments/media-types for all types. Use if necessary ExternalContext#getMimeType() for auto-detection based on filename.
ec.setResponseContentLength(contentLength); // Set it with the file size. This header is optional. It will work if it's omitted, but the download progress will be unknown.
ec.setResponseHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\""); // The Save As popup magic is done here. You can give it any file name you want, this only won't work in MSIE, it will use current request URL as file name instead.
OutputStream output = ec.getResponseOutputStream();
// Now you can write the InputStream of the file to the above OutputStream the usual way.
// ...
fc.responseComplete(); // Important! Otherwise JSF will attempt to render the response which obviously will fail since it's already written with a file and closed.
}
Generic JSF 1.x example
public void download() throws IOException {
FacesContext fc = FacesContext.getCurrentInstance();
HttpServletResponse response = (HttpServletResponse) fc.getExternalContext().getResponse();
response.reset(); // Some JSF component library or some Filter might have set some headers in the buffer beforehand. We want to get rid of them, else it may collide.
response.setContentType(contentType); // Check http://www.iana.org/assignments/media-types for all types. Use if necessary ServletContext#getMimeType() for auto-detection based on filename.
response.setContentLength(contentLength); // Set it with the file size. This header is optional. It will work if it's omitted, but the download progress will be unknown.
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\""); // The Save As popup magic is done here. You can give it any file name you want, this only won't work in MSIE, it will use current request URL as file name instead.
OutputStream output = response.getOutputStream();
// Now you can write the InputStream of the file to the above OutputStream the usual way.
// ...
fc.responseComplete(); // Important! Otherwise JSF will attempt to render the response which obviously will fail since it's already written with a file and closed.
}
Common static file example
In case you need to stream a static file from the local disk file system, substitute the code as below:
File file = new File("/path/to/file.ext");
String fileName = file.getName();
String contentType = ec.getMimeType(fileName); // JSF 1.x: ((ServletContext) ec.getContext()).getMimeType(fileName);
int contentLength = (int) file.length();
// ...
Files.copy(file.toPath(), output);
Common dynamic file example
In case you need to stream a dynamically generated file, such as PDF or XLS, then simply provide output there where the API being used expects an OutputStream.
E.g. iText PDF:
String fileName = "dynamic.pdf";
String contentType = "application/pdf";
// ...
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, output);
document.open();
// Build PDF content here.
document.close();
E.g. Apache POI HSSF:
String fileName = "dynamic.xls";
String contentType = "application/vnd.ms-excel";
// ...
HSSFWorkbook workbook = new HSSFWorkbook();
// Build XLS content here.
workbook.write(output);
workbook.close();
Note that you cannot set the content length here. So you need to remove the line to set response content length. This is technically no problem, the only disadvantage is that the enduser will be presented an unknown download progress. In case this is important, then you really need to write to a local (temporary) file first and then provide it as shown in previous chapter.
Utility method
If you're using JSF utility library OmniFaces, then you can use one of the three convenient Faces#sendFile() methods taking either a File, or an InputStream, or a byte[], and specifying whether the file should be downloaded as an attachment (true) or inline (false).
public void download() throws IOException {
Faces.sendFile(file, true);
}
Yes, this code is complete as-is. You don't need to invoke responseComplete() and so on yourself. This method also properly deals with IE-specific headers and UTF-8 filenames. You can find source code here.
public void download() throws IOException
{
File file = new File("file.txt");
FacesContext facesContext = FacesContext.getCurrentInstance();
HttpServletResponse response =
(HttpServletResponse) facesContext.getExternalContext().getResponse();
response.reset();
response.setHeader("Content-Type", "application/octet-stream");
response.setHeader("Content-Disposition", "attachment;filename=file.txt");
OutputStream responseOutputStream = response.getOutputStream();
InputStream fileInputStream = new FileInputStream(file);
byte[] bytesBuffer = new byte[2048];
int bytesRead;
while ((bytesRead = fileInputStream.read(bytesBuffer)) > 0)
{
responseOutputStream.write(bytesBuffer, 0, bytesRead);
}
responseOutputStream.flush();
fileInputStream.close();
responseOutputStream.close();
facesContext.responseComplete();
}
This is what worked for me:
public void downloadFile(String filename) throws IOException {
final FacesContext fc = FacesContext.getCurrentInstance();
final ExternalContext externalContext = fc.getExternalContext();
final File file = new File(filename);
externalContext.responseReset();
externalContext.setResponseContentType(ContentType.APPLICATION_OCTET_STREAM.getMimeType());
externalContext.setResponseContentLength(Long.valueOf(file.lastModified()).intValue());
externalContext.setResponseHeader("Content-Disposition", "attachment;filename=" + file.getName());
final HttpServletResponse response = (HttpServletResponse) externalContext.getResponse();
FileInputStream input = new FileInputStream(file);
byte[] buffer = new byte[1024];
final ServletOutputStream out = response.getOutputStream();
while ((input.read(buffer)) != -1) {
out.write(buffer);
}
out.flush();
fc.responseComplete();
}
This is my solution, an extension of BalusC's answer
public static void download(
ByteArrayOutputStream baos,
String downloadFileName,
String contentType
) {
FacesContext context = FacesContext.getCurrentInstance();
ExternalContext externalContext = context.getExternalContext();
externalContext.responseReset();
HttpServletResponse response = (HttpServletResponse) externalContext.getResponse();
response.reset();
response.setContentType(contentType);
response.setHeader("Expires", "0");
response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
response.setHeader("Pragma", "public");
Integer size = baos.size();
response.setHeader("Content-Length", size.toString());
response.setHeader(
"Content-Disposition",
"attachment; filename=\"" + downloadFileName + "\""
);
try {
try (OutputStream responseOs = response.getOutputStream()) {
baos.writeTo(responseOs);
}
}
catch (IOException e) {
throw new IOUncheckedException(e);
}
context.responseComplete();
}
here is the complete code snippet http://bharatonjava.wordpress.com/2013/02/01/downloading-file-in-jsf-2/
#ManagedBean(name = "formBean")
#SessionScoped
public class FormBean implements Serializable
{
private static final long serialVersionUID = 1L;
/**
* Download file.
*/
public void downloadFile() throws IOException
{
File file = new File("C:\\docs\\instructions.txt");
InputStream fis = new FileInputStream(file);
byte[] buf = new byte[1024];
int offset = 0;
int numRead = 0;
while ((offset < buf.length) && ((numRead = fis.read(buf, offset, buf.length -offset)) >= 0))
{
offset += numRead;
}
fis.close();
HttpServletResponse response =
(HttpServletResponse) FacesContext.getCurrentInstance()
.getExternalContext().getResponse();
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment;filename=instructions.txt");
response.getOutputStream().write(buf);
response.getOutputStream().flush();
response.getOutputStream().close();
FacesContext.getCurrentInstance().responseComplete();
}
}
You may change the file reading logic in case you want file to get generated at runtime.
I'm developing a Universal App for Windows Phone 8.1 but I'm using a PHP Page to get recognize some patterns from an Image that I uploaded to my service.
I have discovered that after I uploaded X image to Azure, I cannot use it. I'm using WebMatrix to develop my PHP Page and when I refresh it, it doesn't show me the images that I uploaded however when I try to publish something and I select the option: "Delete files on the remote server that are not on my computer." I can see my images. This is an example of my PHP code:
$uploaddir = getcwd();
$uploadfile = $uploaddir . "/" . basename($_FILES['userfile']['name']);
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
chmod($uploadfile, 0755);
$Test = new Display($_FILES['userfile']['name']);
echo '{"result": "' . $Test->getNumber($_REQUEST['color'], false) . '"}';
//unlink($uploadfile);
} else {
echo '{"result": "-1"}';
}
I'd like to know what could be my bug because I don't understand why I can access from the URL, too to the bit I cannot use it, maybe it's how I assigned the permissions but with or without the chmod, it doesn't change at all. I have even tried other hostings and the problem is the same when I enter the File Manager, there are only my PHP files and it doesn't allow me to manage the image.
This is my Windows Phone code to upload the Image if it's necessary:
byte[] ConvertBitmapToByteArray()
{
WriteableBitmap bmp = bitmap;
using (Stream stream = bmp.PixelBuffer.AsStream())
{
MemoryStream memoryStream = new MemoryStream();
stream.CopyTo(memoryStream);
return memoryStream.ToArray();
}
}
public async Task<string> Upload()
{
try
{
using (var client = new HttpClient())
{
using (var content =
new MultipartFormDataContent())
{
byte[] data = ConvertBitmapToByteArray();
using (var stream = new InMemoryRandomAccessStream())
{
// encoder *outputs* to stream
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.BmpEncoderId, stream);
// encoder's input is the bitmap's pixel data
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight,
(uint)bitmap.PixelWidth, (uint)bitmap.PixelHeight, 96, 96, data);
await encoder.FlushAsync();
content.Add(new StreamContent(stream.AsStream()), "userfile", fileNewImage);
using (
var message =
await client.PostAsync("http://xplace.com/uploadtest.php", content))
{
var input = await message.Content.ReadAsStringAsync();
return input;
}
}
}
}
}
catch (Exception ex)
{
return null;
}
}
Thanks for your worthy knowledge and experience.
Create a blob storage account, and add a public container. In your action to save the file, store the file in you blob storage container. Then you can access the image as you would with any other image.
Here is a tutorial on Azure: http://azure.microsoft.com/en-us/documentation/articles/storage-dotnet-how-to-use-blobs/
Also, you cannot create folders in a container, but you could use a naming convention on the blobrefname to create the idea of a container. Also, you can attach a domain to the cloud service if you want the URL to have a certain look.
READ YOUR QUESTION AGAIN - And it looks like it's more on the client side.
Here is what I usually do to attach a file to a MultipartFormDataContent:
MultipartFormDataContent content = new MultipartFormDataContent();
FileInfo info = new FileInfo(currFileLoc);
string contentMediaType = null;
//This is a Dictionary<string, string> that takes in the file
//extension, and returns the media type (e.g. "image/jpeg")
GlobalVariables.ApprovedMediaTypes.TryGetValue(
info.Extension.ToLower()
, out contentMediaType);
//If the dictionary doesn't return a result
//then it's not a supported file type
if (contentMediaType == null)
throw new Exception(
String.Format("The file \"{0}\" is an unsupported file type."
, info.Name));
ByteArrayContent currFile = new ByteArrayContent(File.ReadAllByte(currFileLoc));
currFile.Headers.ContentType = new MediaTypeWithQualityHeaderValue(contentMediaType);
content.Add(currFile, currFileLoc, currFileLoc);
The I make my call. Maybe you found another option with blob storage. Finally, if you load large files, you may want to look into uploading in chunks.
I'm writing an app that deals with sales data. The data is outputted to a private webpage, which my app can access and read. However, my app does not always receive all of the data that it's supposed to. (If I open the webpage in a desktop browser, the data is always complete) I suspect that this may be due to a race condition in which the app tries to read the data on the webpage before the webpage has loaded completely. Here is the code that reads the data from the webpage:
try {
URL url = new URL(myurl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(120000 /* milliseconds, or 2 minutes */);
conn.setConnectTimeout(120000 /* milliseconds, or 2 minutes */);
conn.setRequestMethod("GET");
conn.setDoInput(true);
// Starts the query
conn.connect();
int response = conn.getResponseCode();
Log.d(DEBUG_TAG, "The response is: " + response);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
is = conn.getInputStream();
// Convert the InputStream into a string
String contentAsString = readIt(is, len);
return contentAsString;
// Makes sure that the InputStream is closed after the app is
// finished using it.
} finally {
if (is != null) {
is.close();
}
}
As you can see, I added a Thread.sleep() to give the page time to load, and this has helped, but has not solved the issue completely.
What can I do to make sure that the app waits until the webpage has loaded completely before trying to read data from it?
Edit: Here is my readit function:
public String readIt(InputStream stream, int len) throws IOException, UnsupportedEncodingException {
Reader reader = null;
reader = new InputStreamReader(stream, "UTF-8");
char[] buffer = new char[len];
reader.read(buffer);
return new String(buffer);
}
Edit 2: I have edited readIt to loop until a certain character sequence is found in the buffer. This works, but if the data doesn't load quickly enough, then the app will crash because Android thinks that there's an infinite loop. Here is the edited code:
public String readIt(InputStream stream, int len) throws IOException, UnsupportedEncodingException {
boolean xyz = false;
Reader reader = null;
char[] buffer = null;
while (xyz == false){
reader = new InputStreamReader(stream, "UTF-8");
buffer = new char[len];
reader.read(buffer);
String test = new String(buffer);
System.out.println(test);
if (test.contains("###")){
xyz = true;
}
}
return new String(buffer);
}
Well, here's what I found that worked. The issue was that the reader would read from the stream even if the stream wasn't fully loaded. It would also read 1000000 characters from the stream, even if there weren't that many characters to be read. This caused the reader to read whatever was available, and then fill in the rest of the 1000000 characters with UTF-8 unknown symbols (�). The code that you see here loops on the stream, each time reading whatever has loaded since the last loop, and discarding the � characters. It does require that whatever you are reading not contain any non-UTF-8 characters, because it splits the string on the first � that it finds, but if you are reading in UTF-8, you should make sure of that anyway. It also requires that you place an uncommon sequence of characters at the end of your data to mark the end.
// This converts the data stream into a String that can be manipulated.
public String readIt(InputStream stream, int len) throws IOException, UnsupportedEncodingException {
boolean isDone = false; // Boolean to keep track of whether the data is loaded or not.
Reader reader = new InputStreamReader(stream, "UTF-8"); // Input stream reader
char[] buffer = null; // Character array to hold the data from the stream
String readDump = null; // String to hold data converted from the character array, which will most likely contain junk characters.
String splitDump [] = null; // String array that holds the valid data and junk from readDump after they've been separated.
String dataHolder = ""; // Output string that holds the valid data
// While the final characters have not been read (###)
while (isDone == false){
buffer = new char[len];
reader.read(buffer); // Read data from the stream
readDump = new String(buffer); // Turn it into a string
splitDump = readDump.split("[\\x00\\x08\\x0B\\x0C\\x0E-\\x1F]", 2); //Split the string into valid data and junk.
dataHolder += splitDump[0]; // Add the valid data to the output string
System.out.println(dataHolder); //Debug
if (dataHolder.contains("###")){
// If the output string has the final characters in it, then we are done.
isDone = true;
}
}
return dataHolder;
}
I have a url site.com/test.php which has the following code
<?php
$num1 = $_REQUEST['num1'] ;
$num2 = $_REQUEST['num2'] ;
$tot = $num1 + $num2 ;
?>
From an android application using POST/GET num1 and num2 parameters are passed to www.site.com/test.php
How can I make the response in such a way that the android application will be able to get the response from this request.
I tried this
header('Content-Type: application/json');
echo json_encode($response);
but all it does is echo it in the web view and im not able to get the response.Is there someway I can get the response as standard json response,which is not displayed but get it as soon as I hit the url as a response ?
** UPDATE **
#Override
public boolean shouldOverrideUrlLoading (WebView view, String url) {
if(flag) {
URL aURL = new URL(url);
URLConnection conn = aURL.openConnection();
conn.connect();
InputStream is = conn.getInputStream();
// read inputstream to get the json..
...
...
return true;
}
return false
}
#override
public void onPageFinished (WebView view, String url) {
if (url contains "form.html") {
flag = true;
}
}
this is the java code I got from SO , which Im planning to use in the android appication
Seems to be a problem in the handling of the response, not the generation of the JSON. Are you clicking a link to the JSON on a page that is has "form.html" in it? Because that is what seems to be assumed in the code you posted.
It seems to be better to just overload the shouldOverrideUrlLoading and check if the url matches your json page. Something like this:
#Override
public boolean shouldOverrideUrlLoading (WebView view, String url) {
if(url.toLowerCase().contains("www.site.com/test.php")) {
URL aURL = new URL(url);
URLConnection conn = aURL.openConnection();
conn.connect();
InputStream is = conn.getInputStream();
// read inputstream to get the json..
...
...
return true;
}
return false;
}
It might be a good idea to start an activity and load the JSON in that activity using, for example, an AsyncTask (network operations aren't allowed on the UI thread in the latest android APIs), instead of doing URL.openConnection immediately.
I'm using a restful webservice developed in php. The webservice will send data images. For images it will send the image name and we will prepare the url of the image on fly to download it. But now there is a requirement to download video files. We can follow the same way like downloading images (ex: image name = "myimage1.jpeg" url=www.xyz.com/images/myimage1.jpeg", we will read this directly and create file locally), but want to know is there any way from php to send the data like binary string from php and convert it into movie file at Android end.
(Can we send images as json data from php webservice. Please give some code)
Note: How to send Images/Videos files from restful webservice as json data
Of course you could send video-Data in JSON, but since JSON is essentially a String-Format with several reserved Characters you will have to encode the video-data.
You could use any scheme you like - but BASE64 is a widely accepted Standard so I would use it.
Just create a JSON-String object and fill it with the BASE-64 encoded Video Data.
But beware of Buffer-Overflows!!! Because many JSON-Implementations will usually not expect giant Data-Elements in JSON it may be advisable to break the Data-Stream into several smaller Chunks and deliver them one at a time... Of course you could also just stream the JSON-Data itself, but as far as I know most JSON Stacks operate serially, since you can only parse a valid JSON-String if it is complete.
So the best thing performance wise (if you REALLY WANT to pack the video Data into JSON, which is clearly not what JSON was ever intended for, and there should be better solutions for almost all setups) should be to BASE64 Encode the Video in a Stream, so you can read Chunks of it into Memory, pack them into JSON-Strings and send these to the Server, which can use these Chunks to stream the Video to a file or play it, or reconstruct it in memory...
#BSON was mentioned before - it could be advisable to use it, since the JSON-Data will be compressed. But it doesn't change the fact you have to encode your Video-Data in an unfavorable format, which will bloat up the transmitted data and will cost its fair share of performance on BOTH ENDS!
But I can imagine Scenarios where using JSON for video transmission could be advisable. If you have a high number of small videos (small jingles, or video fragments, which the user can select and collate) then a solid easy to handle data structure to administrate these videos could be well worth the extra transfer cost...
As ChriZzZ stated, it's inadvisable (and not really natively supported) in JSON.
However, you may consider using BSON (Binary JSON). Specifically for a PHP implementation, the site provides a link to Mongo, so you may want to check that out. Unfortunately, I have no code to provide.
This may be helpful to you:
PHP Code (video.php)
<?php
if(isset($_GET['name']))
{
$video_name = $_GET['name'];
$path = "/path/to/videos/folder/$video_name"; //ex: video.mp4
$size=filesize($path);
$fm=#fopen($path,'rb');
if(!$fm) {
// You can also redirect here
header ("HTTP/1.0 404 Not Found");
die();
}
$begin=0;
$end=$size;
if(isset($_SERVER['HTTP_RANGE'])) {
if(preg_match('/bytes=\h*(\d+)-(\d*)[\D.*]?/i', $_SERVER['HTTP_RANGE'], $matches)) {
$begin=intval($matches[0]);
if(!empty($matches[1])) {
$end=intval($matches[1]);
}
}
}
if($begin>0||$end<$size)
header('HTTP/1.0 206 Partial Content');
else
header('HTTP/1.0 200 OK');
header("Content-Type: video/mp4");
header('Accept-Ranges: bytes');
header('Content-Length:'.($end-$begin));
header("Content-Disposition: inline;");
header("Content-Range: bytes $begin-$end/$size");
header("Content-Transfer-Encoding: binary\n");
header('Connection: close');
$cur=$begin;
fseek($fm,$begin,0);
while(!feof($fm)&&$cur<$end&&(connection_status()==0))
{ print fread($fm,min(1024*16,$end-$cur));
$cur+=1024*16;
usleep(1000);
}
die();
}else{
echo "Please provide a Video name (name=)";
}
?>
Java Code (Download and Save video to SDCARD):
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Environment;
import android.util.Log;
public class VideoSaveSDCARD extends Activity{
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ProgressBack PB = new ProgressBack();
PB.execute("");
}
class ProgressBack extends AsyncTask<String,String,String> {
ProgressDialog PD;
#Override
protected void onPreExecute() {
PD= ProgressDialog.show(LoginPage.this,null, "Please Wait ...", true);
PD.setCancelable(true);
}
#Override
protected void doInBackground(String... arg0) {
DownloadFile("http://yourserver/video.php?name=video.mp4","video.mp4");
}
protected void onPostExecute(Boolean result) {
PD.dismiss();
}
}
public void DownloadFile(String fileURL, String fileName) {
try {
String RootDir = Environment.getExternalStorageDirectory()
+ File.separator + "Video";
File RootFile = new File(RootDir);
RootFile.mkdir();
// File root = Environment.getExternalStorageDirectory();
URL u = new URL(fileURL);
HttpURLConnection c = (HttpURLConnection) u.openConnection();
c.setRequestMethod("GET");
c.setDoOutput(true);
c.connect();
FileOutputStream f = new FileOutputStream(new File(RootFile,
fileName));
InputStream in = c.getInputStream();
byte[] buffer = new byte[1024];
int len1 = 0;
while ((len1 = in.read(buffer)) > 0) {
f.write(buffer, 0, len1);
}
f.close();
} catch (Exception e) {
Log.d("Error....", e.toString());
}
}
}
Sending binary data in JSON from PHP is very simple:
$data = file_get_contents($filename);
echo json_encode(array('filecontent' => $data));
At least in theory this would work. The reason why it does not work in practice is that $data is limited in size (must fit into the memory limit), and that JSON is not meant to transfer megabytes of data.
The encoding is inefficient. Either you use the bytes natively, then you will experience escape sequences for any non-printable character, making these bytes getting six times as big (the unicode escape sequence uses a backslash, the letter "u" and four hex numbers). Or you use base64 encoding, which will blow up EVERY byte by about 33%. Not counting the overhead for the most basic JSON wrapping.
Offering a native stream of bytes with an appropriate header seems to be the better idea. You could directly feed that stream into the video codec for replay, without having to parse JSON, decode base64 and reassemble everything back into a video data stream.
Here is the info according to the PHP official documentation.
Hopefully it will work for the video file.
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(serverURL);
MultipartEntity postEntity = new MultipartEntity();
File file = new File("file path to be put here");
postEntity.addPart("fileupload", new FileBody(file, "video/mp4"));
postEntity.addPart("loginKey", new StringBody(""+loginKey));
postEntity.addPart("message", new StringBody(message));
postEntity.addPart("token", new StringBody(token));
post.setEntity(postEntity);
response = client.execute(post);
try this it works for you.
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(URL);//
FileBody filebodyVideo = new FileBody(file);
StringBody title = new StringBody("Filename: " + filename);
MultipartEntity reqEntity = new MultipartEntity();
reqEntity.addPart("videoFile", filebodyVideo);
httppost.setEntity(reqEntity);
HttpResponse response = httpclient.execute( httppost );
Why not you are receiving the file path of video in your webservice rather than whole video audio file in webservice, as in case of receiving the whole file the limit may exceded and you will be receiving invalid JSON response from PHP. So its safer to retrieve the file path of video on server rather than the video itself in response.
Another way is that you to use a webview and put a download link as in php in case of video file to download .
You can encode any binary file into base64 and then output a JSON string like this:
<?php
$fgc = file_get_contents('yourfile.gif'); //can be any binary
$bindata = base64_encode($fgc);
$arr = array('name'=>'yourfile.gif','mime'=>'image/gif','data'=>$bindata);
echo json_encode($arr);
?>
for video, use your preferable mime type...
at the Android side, decode the data and use the mime type so select proper view etc'...
import java.io.File;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
import javax.ws.rs.core.Response.Status;
#Path("/file")
public class DownloadVideoREST {
private static final String VIDEO_FILE = "E:\\xyz.flv";
#GET
#Path("/video")
#Produces("video/flv")
public Response getVideoFile() {
File file = new File(VIDEO_FILE);
ResponseBuilder response = Response.ok((Object) file);
response.header("Content-Disposition", "attachment; filename=\"abc.flv\"");
return response.build();
}
#GET
#Path("/{fileName}/video")
#Produces("video/flv")
public Response getFileInVideoFormat(#PathParam("fileName") String fileName)
{
System.out.println("File requested is : " + fileName);
if(fileName == null || fileName.isEmpty())
{
ResponseBuilder response = Response.status(Status.BAD_REQUEST);
return response.build();
}
File file = new File("c:/abc.flv");
ResponseBuilder response = Response.ok((Object) file);
response.header("Content-Disposition", "attachment; filename=abc.flv");
return response.build();
}
}