I have a strange issue using the ASIHTTPRequest library when I attempt to upload images to a php script. I have implemented ASIHTTPRequest correctly, as in the php script does receive the POST data from the iphone simulator, but only for some of the images in my testing set. There are other images that don't pass through the POST.
All images were retrieved from Facebook, and are either jpg or png format. I have tested my code on both types of images, though it shouldn't matter because I use the PNGRepresentation method in my iphone application to convert the image to NSData. I have also tested size of an image, and this is not an issue (ranging from 600x600 to 1200x1200).
The images that break the ASIHTTPRequest don't seem special at all to me, and I am having trouble identifying the bug. Below is some of my implementation:
iPhone Implementation:
[RegisterRequest setData:profilePicturePNG withFileName:filename andContentType:#"image/png" forKey:#"profilePicture"];
[RegisterRequest addRequestHeader:#"Content-Type" value:#"image/png"];
[RegisterRequest setDelegate:self];
[RegisterRequest startAsynchronous];
PHP Implementation:
echo "Upload: " . $_FILES["profilePicture"]["name"] . "<br>";
echo "Type: " . $_FILES["profilePicture"]["type"] . "<br>";
echo "Size: " . ($_FILES["profilePicture"]["size"] / 1024) . " kB<br>";
echo "Temp file: " . $_FILES["profilePicture"]["tmp_name"] . "<br>";
In this test, the PHP implementation should echo the file properties. As I said earlier, for most images I do get an echo back. But there are some images where name and type don't go through and size is reported as 0kb.
Any suggestions? I would greatly appreciate it!
For your info, ASIHTTPRequest is being deprecated, but you can use AFNetworking here you can reference from this.
https://github.com/AFNetworking/AFNetworking and also this example
-(IBAction)uploadButtonClicked:(id)sender{
NSData *imageToUpload = UIImageJPEGRepresentation(mainImageView.image, 90);
AFHTTPClient *client= [AFHTTPClient clientWithBaseURL:[NSURL URLWithString:#"http://www.THESERVER.com"]];
NSMutableURLRequest *request = [client multipartFormRequestWithMethod:#"POST" path:#"/PROJECT/upload.php" parameters:nil constructingBodyWithBlock: ^(id <AFMultipartFormData>formData) {
[formData appendPartWithFileData: imageToUpload name:#"file" fileName:#"temp.jpeg" mimeType:#"image/jpeg"];
}];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSString *response = [operation responseString];
NSLog(#"response: [%#]",response);
[MBProgressHUD hideHUDForView:self.view animated:YES];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[MBProgressHUD hideHUDForView:self.view animated:YES];
if([operation.response statusCode] == 403){
NSLog(#"Upload Failed");
return;
}
NSLog(#"error: %#", [operation error]);
}];
[operation start];
}
I guess for image uploading you should not use ASIHTTPRequest
NSString *requestStr = [yourPHPSCriptURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
responseString = nil;
NSURL *requestUrl = [[NSURL alloc] initWithString:requestStr];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:requestUrl];
[request setPostFormat:ASIMultipartFormDataPostFormat];
[request addPostValue:#".png" forKey:image_content_type]; //Use this if you want//
[request setShouldAttemptPersistentConnection:YES];
[request setData:yourPhotoData withFileName:#"user_image_byte.png" andContentType:#"image/png" forKey:#"user_image_byte"];
[request startSynchronous];
I send my image as byte stream and later in asp.net I convert it back as a image. Hope this helps.
Related
In my iPhone app handling web service for storing and retrieving data.Now i am using the following code for web service handling.
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setPostValue:#"1" forKey:#"id"];
[request setTag:100];
[request setDelegate:self];
[request startAsynchronous];
By this code i got response in 'requestFinished' method.My problem is web service response is very delay(depends upon internet speed).How to make response from web service very fast?Please help me.
I think you want to send json objects by post method..delay is depend on your server(how fast it handle request and response back) but i suggest you to use progress bar and blocks to handle network request..
loadingHUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
loadingHUD.labelText = NSLocalizedString(#"Downloading", nil);
loadingHUD.mode=MBProgressHUDModeAnnularDeterminate;
NSString *documentDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES) lastObject];
// Add your filename to the directory to create your saved file location
NSString* destPath = [documentDirectory stringByAppendingPathComponent:[fileName stringByAppendingString:#".mov"]];
NSURL *url = [NSURL URLWithString:mainURL];
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
NSMutableURLRequest *request = [httpClient requestWithMethod:#"POST" path:postURL parameters:postRequest];
NSLog(#"postRequest: %#", postRequest);
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:destPath append:NO];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSLog(#"Successfully downloaded file to %#",[[NSString alloc] initWithData:operation.responseData encoding:NSASCIIStringEncoding]);
// Give alert that downloading successful.
NSLog(#"Successfully downloaded file to %#", destPath);
NSLog(#"response: %#", operation.responseString); // Give alert that downloading successful.
// [self.target parserDidDownloadItem:destPath];
loadingHUD.detailsLabelText = [NSString stringWithFormat:#"%# %i%%",#"Downloading",100];
[loadingHUD hide:TRUE];
[DBHelper savePurchaseId:fileName];
[self movieReceived];
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
// Give alert that downloading failed
NSLog(#"Error: %#", error);
// [self.target parserDidFailToDownloadItem:error];
[loadingHUD hide:TRUE];
}];
[operation setDownloadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite)
{
// Progress
progress = ((float)totalBytesWritten) / fileSize;
loadingHUD.progress = progress;
}];
[operation start];
}
We cant control the internet speed due to the different network provider or environment when the client is using your app.
But you can put your web-services to run in background without effecting your main function.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//code for webservices calling
dispatch_async(dispatch_get_main_queue(), ^{
//functions after your webservices done, for example reload the table or hide the loading bar.
});
});
I am downloading video file from response.
i want to display downloading progress bar of HUD-progress.
but how can i do that.
I am sending verify json to server and server verify that send back the video file bytes. i want to display how much percentage of downloading is done by using HUD-progreasse bar.
If i call [request setDidReceiveDataSelector:#selector(request:didReceiveBytes:)]; than it display how much bytes i got but it doesn't store the bytes into cache file ( it doesn't not store file into phone)
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[[NSURL alloc] initWithString:#"http://testing.io/dev.php/video/verifyReceipt"]];
[request setPostValue:resultAsString forKey:#"verify"];// sending json in post
[request setDidReceiveDataSelector:#selector(request:didReceiveBytes:)];
[request setDidFinishSelector:#selector(requestDone:)];
[request setTimeOutSeconds:120];
[request setDelegate:self];
[request setNumberOfTimesToRetryOnTimeout:2];
[request setDownloadProgressDelegate:self];
request.showAccurateProgress = YES;
[request startSynchronous];
}
-(void)request:(ASIHTTPRequest *)request didReceiveData:(NSData *)data
{
[videoData appendData:data];// appending data with global NSmutabledata
NSLog(#"data is %#",data);
}
- (void)requestDone:(ASIHTTPRequest *)request{
//[MBProgressHUD hideHUDForView:self.view animated:YES];
// SAVED Video PATH
// Get the Document directory
NSString *documentDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
// Add your filename to the directory to create your saved video location
NSString* movLocation = [documentDirectory stringByAppendingPathComponent:[fileName stringByAppendingString:#".mov"]];
if(request.responseStatusCode==200)
{
[videoData writeToFile:movLocation atomically:NO];
NSLog(#"in request done sucsessfully downlaod and store in database %d",request.responseStatusCode);
[DBHelper savePurchaseId:fileName];
[self movieReceived];
}
else{
NSLog(#"in request downlaod and store in database failed %#",request.responseHeaders);
}
}
-(void)requestFailed:(ASIHTTPRequest *)request
{
NSLog(#"%#",request.error);
}
fileUrl = string of URL to download a video.
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:[fileUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:destPath append:NO];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
// Give alert that downloading successful.
NSLog(#"Successfully downloaded file to %#", destPath);
/* To call delegate to response the result. */
[self.target parserDidDownloadItem:destPath];
HUD.detailsLabelText = [NSString stringWithFormat:#"%# %i%%",[JGlobals getLocalvalue:#"Downloading"],100];
[HUD hide:TRUE];
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
// Give alert that downloading failed
NSLog(#"Error: %#", error);
/* To call delegate to response the result. */
[self.target parserDidFailToDownloadItem:error];
[HUD hide:TRUE];
}];
[operation setDownloadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite)
{
// Progress
float totalProgress = (totalBytesWritten / (totalBytesExpectedToWrite * 1.0f) * 100);
HUD.detailsLabelText = [NSString stringWithFormat:#"Downloading %i%%", MIN((int)(totalProgress), 99)];
}];
[operation start];
I'm thinking of a method which might not be the right one, but it going to save you from writing a lot of code.
First set a normal UIProgressView instance as the download progress delegate like this
[request setDownloadProgressDelegate:uiprogreeViewInstance];
Now ASIHTTPRequest framework will take care of updating that progressview when the downloading will be taking place. ProgressView has a property named progress, which ranges from 0.0 to 1.0.
Now instantiate MBProgressHUD, add it as your subview where you want. Set the progress value of the MBProgressHUD instance to that of the UIProgressView. Hide the uiprogressview instance.
Brief backstory, our previous developer used ASIHTTPRequest to make POST requests and retrieve data from our webservice. For reasons unknown this portion of our app stopped working. Seemed like good enough time to future proof and go with AFNetworking. REST webservice runs on the CakePHP framework.
In short I am not receiving the request response string using AFNetworking.
I know the webservice works because I am able to successfully post data and receive the proper response using curl:
curl -d "data[Model][field0]=field0value&data[Model][field1]=field1value" https://example.com/api/class/function.plist
Per the previous developer's instructions I came up with the following.
#import "AFHTTPRequestOperation.h"
…
- (IBAction)loginButtonPressed {
NSURL *url = [NSURL URLWithString:#"https://example.com/api/class/function.plist"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setValue:[usernameTextField text] forHTTPHeaderField:#"data[User][email]"];
[request setValue:[passwordTextField text] forHTTPHeaderField:#"data[User][password]"];
AFHTTPRequestOperation *operation = [[[AFHTTPRequestOperation alloc] initWithRequest:request] autorelease];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"operation hasAcceptableStatusCode: %d", [operation.response statusCode]);
NSLog(#"response string: %# ", operation.responseString);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"error: %#", operation.responseString);
}];
[operation start];
}
output:
operation hasAcceptableStatusCode: 200
response string: a blank plist file
attempted solution 1:
AFNetworking Post Request
the proposed solution uses a function of AFHTTPRequestOperation called operationWithRequest. However, when I attempt to use said solution I get a warning "Class method '+operationWithRequest:completion:' not found (return type defaults to 'id'"
attempted solution 2: NSURLConnection. output: I'm able to print the success log messaged but not the response string.
*update - returns blank plist.
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
NSString *httpBodyData = #"data[User][email]=username#example.com&data[User][password]=awesomepassword";
[httpBodyData dataUsingEncoding:NSUTF8StringEncoding];
[req setHTTPMethod:#"POST"];
[req setHTTPBody:[NSData dataWithContentsOfFile:httpBodyData]];
NSHTTPURLResponse __autoreleasing *response;
NSError __autoreleasing *error;
[NSURLConnection sendSynchronousRequest:req returningResponse:&response error:&error];
// *update - returns blank plist
NSData *responseData = [NSURLConnection sendSynchronousRequest:req returningResponse:nil error:nil];
NSString *str = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSLog(#"responseData %#",str);
if (error == nil && response.statusCode == 200) {
// Process response
NSLog(#"success");//returns success code of 200 but blank
NSLog(#"resp %#", response );
} else {
// Process error
NSLog(#"error");
}
These are the essential (stripping out conditions I've made for my own use) lines that ended up satisfying my request to the web service. Thanks for the suggestions #8vius and #mattt !
- (IBAction)loginButtonPressed {
NSURL *baseURL = [NSURL URLWithString:#"https://www.example.com/api/class"];
//build normal NSMutableURLRequest objects
//make sure to setHTTPMethod to "POST".
//from https://github.com/AFNetworking/AFNetworking
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:baseURL];
[httpClient defaultValueForHeader:#"Accept"];
NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
[usernameTextField text], kUsernameField,
[passwordTextField text], kPasswordField,
nil];
NSMutableURLRequest *request = [httpClient requestWithMethod:#"POST"
path:#"https://www.example.com/api/class/function" parameters:params];
//Add your request object to an AFHTTPRequestOperation
AFHTTPRequestOperation *operation = [[[AFHTTPRequestOperation alloc]
initWithRequest:request] autorelease];
//"Why don't I get JSON / XML / Property List in my HTTP client callbacks?"
//see: https://github.com/AFNetworking/AFNetworking/wiki/AFNetworking-FAQ
//mattt's suggestion http://stackoverflow.com/a/9931815/1004227 -
//-still didn't prevent me from receiving plist data
//[httpClient registerHTTPOperationClass:
// [AFPropertyListParameterEncoding class]];
[httpClient registerHTTPOperationClass:[AFHTTPRequestOperation class]];
[operation setCompletionBlockWithSuccess:
^(AFHTTPRequestOperation *operation,
id responseObject) {
NSString *response = [operation responseString];
NSLog(#"response: [%#]",response);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"error: %#", [operation error]);
}];
//call start on your request operation
[operation start];
[httpClient release];
}
Use AFHTTPClient -postPath:parameters:success:failure:, passing your parameters (nested dictionaries/arrays are fine). If you're expecting a plist back, be sure to have the client register AFPropertyListRequestOperation.
In any case, setValue:forHTTPHeaderField: is not what you want here. HTTP headers are for specifying information about the request itself; data is part of the request body. AFHTTPClient automatically converts parameters into either a query string for GET requests or an HTTP body for POST, et al.
I want to upload images in server using ASIHTTPRequest library in my IPhone app.
For image upload, i am using ASIFormDataRequest to upload into server.
I have tried the below codes in my app but it couldn't working and image didn't uploaded in server.
NSURL *url = [NSURL URLWithString:#"http://www.anglerdemo.com/Appln/Aghaven_iphone/Uploadphoto.php"];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
request.requestMethod = #"POST";
NSString *fileName = #"iphone.jpg";
[request addPostValue:fileName forKey:#"name"];
// Upload an image
UIImage *img = [UIImage imageNamed:fileName];
NSData *imageData = UIImageJPEGRepresentation(img, 90);
NSLog(#"imageData ==> %#", imageData);
[request setData:imageData withFileName:fileName andContentType:#"image/jpeg" forKey:#"image"];
[request setDelegate:self];
[request startAsynchronous];
I have tried above codes in my app, request successfully executed and i got the alert message in "requestFinished" delegate method of ASIHTTPRequest. but image didn't uploaded in server.
- (void)requestFinished:(ASIHTTPRequest *)request
{
[[[[UIAlertView alloc]
initWithTitle:#"Message"
message:#"Success!!!"
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil]
autorelease]
show];
NSLog(#"success ==> ");
}
I have tried php file script for upload is below.
<?php
$uploaddir = 'upload_files/';
$file = basename($_FILES['image']['name']);
$uploadfile = $uploaddir . $file;
if(move_uploaded_file($_FILES['image']['tmp_name'], $uploadfile))
{
echo "Photo has been saved successfully!…;
}
else {
echo "Failed";
}
?>
Please help in this regards.
Thanks!!!
I think the first thing I would do is add
NSLog(#"%#", [request responseString]);
to requestFinished: just to be sure you see "Failed" being logged. This will prove the problem is with the attempt to call move_upload_file, which I would guess is where things go wrong.
If that's the case, I would be pretty sure that the user your webserver runs as doesn't have write permissions to the upload_files directory.
I'm using the ASIHTTPRequest package to send some data from the iPhone to my server and then when saved on server I recieve a response (a string) containing a url that I want to load in a webview. In theory this should be simple, but in reality I can't get this work at all. Seems to be some problems with encoding of the string I guess. If I NSLog out the response it seems to be totally fine, but it just refuses to load in the webview.
This is my request (been playing around with compression and encoding):
NSURL *url = [NSURL URLWithString:#"xxx"];
ASIFormDataRequest *request = [[[ASIFormDataRequest alloc] initWithURL:url] autorelease];
[request setFile:imageData forKey:#"photo"];
[request setDelegate:self];
[request setDidFinishSelector:#selector(requestDone:)];
[request setDidFailSelector:#selector(requestWentWrong:)];
[request setAllowCompressedResponse:NO];
[request setDefaultResponseEncoding:NSUTF8StringEncoding];//NSISOLatin1StringEncoding
[request start];
And this is my responder:
- (void)requestDone:(ASIHTTPRequest *)request{
NSString *response = [request.responseString];
NSLog(#"web content: %#", response);
[webView loadSite:response];
}
The NSLog seems fine, but site just won't load. Tried sending an NSString variable like NSString *temp = #"http://www.google.se"; to the loadSite function and that works fine, so the problem is not with the loading itself.
Would greatly appriciate any pointers or help in the obj-c jungle :)
/f
Try to do the following:
NSString *response = [[request responseString] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
It will trim all whitespaces and newlines.
so turns out that a response is automatically ended with a \n (new linebreak). this didn't show up when logging the variable, neither when writing it to a textfield but when converting it to a urlobject and logging that i found it. debugging once again pays off ;)
woups, my responder is of course:
- (void)requestDone:(ASIHTTPRequest *)request{
NSString *response = [request responseString];
NSLog(#"web content: %#", response);
[webView loadSite:response];
}