I am trying to create a image upload module Using Imgur API
I have just got Client ID and Client Secret after registration. When it comes to the implementation and testing, it fails and gives the following response in the logcat
The Logcat response
{"data":{"error":"We're really sorry, but
anonymous uploading in your country has
been disabled. Please <a href=\"\/register\">register
for an account<\/a> and try uploading again.","request":"\/3\/upload.json","method":"POST"}
,"success":false,"status":400}
The below is my code
public String uploadToImgur(File uploadFile) {
DefaultHttpClient defaulthttpclient;
HttpPost httppost;
MultipartEntity multipartentity;
String path = uploadFile.getAbsolutePath().toString();
String s;
defaulthttpclient = new DefaultHttpClient();
String targetURL = "https://api.imgur.com/3/upload.json";
String apikey = "client_secret";
httppost = new HttpPost(targetURL);
httppost.setHeader("User-Agent", USER_AGENT);
httppost.addHeader("Authorization", "Client-ID {client)_id}");
multipartentity = new MultipartEntity();
s = path.substring(1 + path.lastIndexOf("."));
if (s.lastIndexOf("jpg") >= 0)
{
s = "jpeg";
}
try
{
multipartentity.addPart("image", new FileBody(new File(path), (new StringBuilder("image/")).append(s).toString()));
multipartentity.addPart("key", new StringBody(apikey));
httppost.setEntity(multipartentity);
String s1 = EntityUtils.toString(defaulthttpclient.execute(httppost).getEntity());
Log.d("outpur" , s1);
if (s1.lastIndexOf("<original>") >= 0 && s1.indexOf("</original>") >= 0)
{
return (new StringBuilder("[img]")).append(s1.substring(10 + s1.lastIndexOf("<original>"), s1.indexOf("</original>"))).append("[/img]").toString();
}
}
catch (Exception exception)
{
return "ERRor";
}
return "Error";
}
Would you please tell me what is the better way to enhance the upload module ?
Registration and sending client id is not good enough for non anonymous uploads. The documentation tells you to use oAuth and get a token that needs to be passed for such requests.
Authentication
The API requires each client to use OAuth 2 authentication. This means you'll have to register your application, and generate an access_code if you'd like to log in as a user.
For public read-only and anonymous resources, such as getting image info, looking up user comments, etc. all you need to do is send an authorization header with your client_id in your requests. This also works if you'd like to upload images anonymously (without the image being tied to an account), or if you'd like to create an anonymous album. This lets us know which application is accessing the API.
Authorization: Client-ID YOUR_CLIENT_ID
For accessing a user's account, please visit the OAuth2 section of the docs
Related
I would like the users of my Android app to be able to send zip files to my server using http. The use case I am imagining looks like this:
The user sends a zip file and a String containing a password using a HttpClient and HttpPost (as described here) to my server.
By logging in to www.example.com/my_app with existing password, users can download the files that the people have sent to my server under the given password.
I don't understand how to do the second step. What code do I need to write on my website to receive files that the Android users have been sending? I have a shared server under my hosting plan and a simple website.
You first need to modify the upload code(Since file upload is treated as multipart data).
Here is the modified upload code--
String url = "http://localhost/upload.php";
File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath(),
"file.txt");
try {
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(url);
Part[] parts = new Part[1];
parts[0] = new FilePart("fileToUpload", file);
MultipartEntity reqEntity = new MultipartEntity(parts);
reqEntity.setContentType("binary/octet-stream");
reqEntity.setChunked(true); // Send in multiple parts if needed
httppost.setEntity(reqEntity);
HttpResponse response = httpclient.execute(httppost);
} catch (Exception e) {
e.printStackTrace();
}
Here I have used the fileToUpload as the parameter key for uploaded file. On server code you can use the same key for your $_FILES["fileToUpload"].
Here is the simplest PHP code to accept the uploaded data from above android code--
<?php
$target_dir = "/Users/chauhan/Desktop/uploads/";
$target_file = $target_dir . basename("abc.txt");
move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file);
?>
Background:
I've got a C# website that requires OAuth Google log-in to access it's pages.
I also have an Android App where I want to access this Web API's pages (with HttpGet-requests and use the returned JSON). I did indeed make an OAuth Google log-in in my Android App, but I need to somehow use that to log-in on the Web API.
I used to have a POST on my C# website that required an AntiForgeryToken to log-in. Because these AntiForgeryTokens only exists very very short (Session-based and changes whenever another page is opened, even the same page in the same browser), I was forced to find a different way. (Because I tried to send a HttpPost in my Android App to log-in with an AntiForgeryToken that I received as a response in the last HttpGet-request, but this token just keeps changing non-stop and caused a no-match in my HttpPost response..)
Current:
Instead I made a new POST-method in my C# web project that doesn't require this [ValidateAntiForgeryToken]. I've also made a System.Web.Security.Role for the Web API pages, and in my API Controllers I've added [Authorize(Role = "web_api")].
When I tested this on my browser:
I removed all Cookies I have in my FireFox browser
I start a Private (Incognito) Window
And used the plug-in RESTClient to make the following POST:
URL: http://localhost:54408/Account/ApiLogin
Headers: Content-Type: application/x-www-form-urlencoded
Body: provider=Google&returnUrl=/Cart/Bestellen
It works with the following response:
When I try to go to this same POST on my Android app however (using the AsyncTask POST-method at the bottom of this page), I get an Error 400 (OAuth2 Error)!!1 in my response.
So, my question: How could I use this new POST that doesn't require any AntiForgeryToken to log-in with an OAuth Google Log-in on my Android App.
Or should I use a completely different approach to log-in with an OAuth Google account on my C# Web API, from within my Android app? (Could I send the OAuth user data from the separate Google log-in in the Android app itself through a different POST? Can I produce this GoogleAccountsLocal_session cookie that is somehow created after the POST-request myself in my Android App to use and put in the HttpClient? So I can get the same response as with the RESTClient POST-request above; if this is indeed the needed cookie to make it work?)
TL;DR: How to log-in to an OAuth2 Google secured C# Web API from within an Android App (so I can send the Web API HttpGet-requests and get JSON returned), without using AntiForgeryTokens whatsoever?
Thanks in advance for the responses.
Android POST class:
public class TaskPostAPI extends AsyncTask<String, Void, String>
{
#Override
protected String doInBackground(String... urls){
String response = "";
for(String url : urls){
InputStream content = null;
BufferedReader buffer = null;
try{
// Get the baseUrl from the given url
URL u = new URL(url);
String baseUrl = u.getProtocol() + "://" + u.getHost();
HttpPost post = new HttpPost(url);
// Add the default Content-type to the Header
post.addHeader("Content-type", "application/x-www-form-urlencoded");
// POST-request requires provider and returnUrl
List<NameValuePair> nvPairs = new ArrayList<NameValuePair>(2);
nvPairs.add(new BasicNameValuePair("provider", "Google"));
nvPairs.add(new BasicNameValuePair("returnUrl", baseUrl));
post.setEntity(new UrlEncodedFormEntity(nvPairs));
// Send the POST-request
HttpResponse execute = MainActivity.HttpClient.execute(post);
// Get the response of the POST-request
content = execute.getEntity().getContent();
buffer = new BufferedReader(new InputStreamReader(content));
String s = "";
while((s = buffer.readLine()) != null)
response += s;
}
catch(Exception ex){
ex.printStackTrace();
}
finally{
try{
if(content != null)
content.close();
if(buffer != null)
buffer.close();
}
catch(IOException ex){
ex.printStackTrace();
}
}
}
return response;
}
}
I am using google books API KEY for android to load book data via my android application. But I am getting error listed below.
However,
- The query works if I delete certificates from my API CONSOLE (e.g. make API KEY acceptable for all Applications). Though my {SHA1};{package name} information that I put is correct.
- This works if I use API KEY for browser instead.
Hence, what I can understand, I can't send KEY as a part of url in httpclient method. May be I need to send via header or something. But I can't find how.
Anybody can help please?
CODE:
String link = "https://www.googleapis.com/books/v1/volumes?key=MY_KEY&q="+query+"&projection=full&langRestrict=en&maxResults=1";
HttpGet get = new HttpGet(link);
HttpParams httpParameters = new BasicHttpParams();
int timeoutConnection = 10000;
HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
HttpConnectionParams.setSoTimeout(httpParameters, timeoutConnection);
HttpClient httpclient = new DefaultHttpClient(httpParameters);
HttpResponse response = httpclient.execute(get);
HttpEntity entity = response.getEntity();
Query:
https://www.googleapis.com/books/v1/volumes?key=MY_API_KEY&q=intitle:'The+Old+Man+And+The+Sea'+inauthor:'Ernest+Hemingway'&projection=full&langRestrict=en&maxResults=1
Result:
{
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "accessNotConfigured",
"message": "Access Not Configured"
}
],
"code": 403,
"message": "Access Not Configured"
}
}
For whom it may concern ... I send my API key in header, and it is now working.. I am not sure whether this is the proper way to it though ...
String link = "https://www.googleapis.com/books/v1/volumes?q="+params;
InputStream is = null;
try
{
int timeoutConnection = 10000;
URL url = new URL(link);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setConnectTimeout(timeoutConnection);
con.setReadTimeout(timeoutConnection);
con.setRequestProperty("key", "API_KEY");
if(con.getResponseCode() != HttpURLConnection.HTTP_OK){
publishProgress("Error conneting.");
}
is=con.getInputStream();
}
Supplying the key in the header is the same as not supplying a key at all. Check your developer api console and you will see no successful queries with that api key. So in short the API key in header does not solve the problem. If you don't want to play by google's rules just do the query without the key at all.
You can achieve the same result of the accepted answer using HttpGet:
String API_KEY = "..."; // Google Books API Public key
String ISBN = "...";
String bookSearchString = "https://www.googleapis.com/books/v1/volumes?q=isbn:" + ISBN;
HttpClient bookClient = new DefaultHttpClient();
try
{
//get the data
HttpGet bookGet = new HttpGet(bookSearchURL);
bookGet.addHeader("key", API_KEY);
HttpResponse bookResponse = bookClient.execute(bookGet);
StatusLine bookSearchStatus = bookResponse.getStatusLine();
if (bookSearchStatus.getStatusCode() == 200)
{
//we have a result
HttpEntity bookEntity = bookResponse.getEntity();
...
}
} catch (Exception e)
{
e.printStackTrace();
}
Note that using Google API key without restrictions is insecure way to do!
Obviously if you’re being charged for access to the API data then you don’t want someone to decompile your APK, find your API key, and then start using it in their own apps.
How to hide your API Key in Android?
But It's not enough. You can store your API key somewhere, so someone can find it too.
To secure Google cloud API key for your android app, you must restrict it to use from your app only. See here for more.
After restrict key, you must include your android app package name and SHA-1 certificate fingerprint in the header of each request you are sending to Google. How to do?
That's all you need ! :D
I'm currently working on an app that requires images to be passed to and from an App engine back-end. Originally I planned on sending the images (they are only small - max 100kb - average 20kb) directly through the endpoint however when sending the data as a byte array through the endpoint I receive a JSON error (from the rest API) stating that the data has an invalid character. Is there a way around this?
My second attempt was to use use the BlobService and return an upload URL to the client using the below code:
BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
UploadOptions uploadOptions = UploadOptions.Builder.withGoogleStorageBucketName("bucketname").maxUploadSizeBytes(1048576);
String url = blobstoreService.createUploadUrl("/uploaded", uploadOptions);
Then using a HTTP post on the android device to upload the image:
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(url);
MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
entity.addPart("data", new ByteArrayBody(data,"image/png","img.png"));
httppost.setEntity(entity);
String res = EntityUtils.toString( httpclient.execute(httppost).getEntity(), "UTF-8");
This seems to work and the image is uploaded. However, I have no idea how to get the blobkey of this uploaded image. Does anyone know? Also, the result from the HTTP post is a 404 error - because the "/uploaded" page does not exist I'm guessing?
Thirdly, when manually typing in the blobkey and using it to return and image serving url with this code:
private String getImage(){
return getThumbUrl(new BlobKey("encoded_gs_key:ZGNpbWcxMy93czZwZ2lUeXdpY0xvZ2xtZGpHZ2dn"));
}
private String getThumbUrl(BlobKey blobkey){
ServingUrlOptions options = ServingUrlOptions.Builder.withBlobKey(blobkey);
try {
return ImagesServiceFactory.getImagesService().getServingUrl(options);
} catch(IllegalArgumentException e) {
e.printStackTrace();
return null;
} catch(ImagesServiceFailureException e) {
e.printStackTrace();
return null;
}
}
I receive the URL of the image however the image colors are all messed up. I am uploading indexed pngs... I'm not sure if the ImageService can handle them correctly. If it cant, how do I go about serving the image directly i.e. not through the ImageService but through BlobstoreService.serve()?
Here is an image of the resultant picture from the ImageService URL: http://i.imgur.com/EhfkJ9j.png
Cheers,
Ben
About the blob key, when you create the upload url you pass a paramenter with the name of your appengine page that gets called after upload. You need to implement that page ("uploaded") https://developers.google.com/appengine/docs/java/blobstore/#Java_Uploading_a_blob
I am working on an android application that needs to print to a printer. I decided on using the Google Cloud Print, as it seemed easy to set up. Initially, I followed the steps found here for integrating into Android. This works, as in it will print to my desired printer. However, this process is a bit involved for the user. In my case, the process is as follows:
The user selects the print button that I have displayed next to some information.
A Dialog is shown with a preview of what will be printed. There is a button in the ActionBar that says "Print". This begins the process.
A new Activity is displayed showing a list of printers that are connected to that users Google Account. The user must select one.
A new page is shown giving a description of the print job.
The user has to select "Print" in the upper right hand corner.
The print job is started and the printer prints out the picture.
Unfortunately, my client does not want this process. They want the user to click "Print" in step two, and then have the picture printed (steps 1, 2 and 6). Thus, I cannot use Intent provided by Google, I must use the actual API. This requires me to get a Google Auth token, get the desired printer, and submit a print job that way. I do the following:
Use the Google Play Services to retrieve an OAuth token for the users Gmail account.
Get a list of printers using the /search API call.
Submit a print job using the /submit API call.
I have the first two finished. I am just having trouble with the actual printing of the picture. Instead of printing the picture, the byte data of the picture is being printed (Base64 encoded). Here is some code as to how I am sending up the request:
ContentResolver contentResolver = context.getContentResolver();
try {
InputStream is = contentResolver.openInputStream(uri);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int n = is.read(buffer);
while (n >= 0) {
baos.write(buffer, 0, n);
n = is.read(buffer);
}
is.close();
baos.flush();
content = Base64.encodeToString(baos.toByteArray(), Base64.DEFAULT);
} catch (FileNotFoundException e) {
Log.d(TAG, "File not found: " + uri.toString(), e);
} catch (IOException e) {
e.printStackTrace();
}
This code retrieves the picture (the variable "uri" is the URI of that file), and turns it into a Base64 encoded string. This is the same method used in the PrintDialogActivity that is provided on the Google Cloud Print page (linked to above). The following is how I send that up:
URL: http://www.google.com/cloudprint/submit?access_token=[AUTH_TOKEN_GOES_HERE]&cookies=false&printerid=[PRINTER_ID_HERE]
HTTP Method: POST
POST Parameters: [printerId=PRINTER_ID_HERE, title=TestPrint, contentType=image/jpeg, capabilities={"capabilities":[{}]}, content=[Base64 Encoded data string is placed here]]
As far as I can tell, this is how it is supposed to be. I am getting a response of {"success":true} when printing. But, as I said above, it prints out the actual Base64 data string. Any help would be appreciated.
EDIT: Using what powerje said below, I managed to fix this. Rather than using the code above, I used the following:
public void submitPrintJobWithFile(String printerId, String title, String token, String filePath, String contentType){
File file = new File(filePath);
// Method that gets the correct headers
List<Header> headers = getHeaders(contentType, token);
// Method that gets the correct post parameters
String url = CLOUDPRINT_URL + PATH_SUBMIT;
List<NameValuePair> postParams = getParams(title, contentType);
String params = "access_token=" + token + "&cookies=false" + "&printerid=" + printerId;
url += params;
response = sendMultipartData(url, file, postParams, headers);
}
private String sendMultipartData(String url, File file, List<NameValuePair> fields, List<Header> headers){
HttpPost post = new HttpPost(url);
MultipartEntity entity = new MultipartEntity();
for(NameValuePair pair : fields){
String name = pair.getName();
String value = pair.getValue();
try{
entity.addPart(name, new StringBody(value));
}catch (UnsupportedEncodingException e){
Log.d(TAG, "Error turning pair (name=" + name + ", value=" + value + ") into StringBody.");
}
entity.addPart("content", new FileBody(file));
post.setEntity(entity);
// Finish HttpClient request here...
}
It looks like you need to use multipart encoding, example here:
http://blog.tacticalnuclearstrike.com/2010/01/using-multipartentity-in-android-applications/
FTA:
The files needed are apache-mime4j, httpclient, httpcore and httpmime. All are opensource projects built by the Apache foundation.
Download the 4 files and add them to your project then you should be able to use the following code to post strings and files to pages.
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://www.tumblr.com/api/write");
try {
MultipartEntity entity = new MultipartEntity();
entity.addPart("type", new StringBody("photo"));
entity.addPart("data", new FileBody(image));
httppost.setEntity(entity);
HttpResponse response = httpclient.execute(httppost);
} catch (ClientProtocolException e) {
} catch (IOException e) {
}
The image variable in this case is a File that contains an image captured by the camera on the phone.
Looking at the Python Sample Code SubmitJob method it seems that only the PDF typs needs to be encoded in Base64.
Answering the question with a bit of an update. As of October 2013, in 4.4 and the support library, there are built in methods to handle printing. See the following documentation for how to do it properly:
PrintHelper - The support Library class to help with printing Bitmaps.
DevBytes: Android 4.4 Printing API - An Android Developers video detailing the APIs
Printing Content - An Android Training guide on how to use these APIs.