ASIFormDataRequest uploads blank image - objective-c

After searching here for a simple image upload with ASIFormDataRequest i finally got it working(sort of) but with a unexpected error.
My image is uploaded to my server but it is blank, 0 bytes in size.
Here is my code:
-(IBAction)uploadImage:(id)sender
{
NSData *data = UIImageJPEGRepresentation(self.imageView.image,0.6f);
NSString *file = [NSTemporaryDirectory() stringByAppendingPathComponent:#"upload.png"];
[data writeToFile:file atomically:YES];
NSString *strURL = #"http://domain.com/upload.php";
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:strURL]];
UIImage *image1=[UIImage imageNamed:file];
NSData *imageData1=UIImageJPEGRepresentation(image1, 1.0);
[request setData:imageData1 withFileName:file andContentType:#"image/jpeg" forKey:#"avatar"];
[request setRequestMethod:#"POST"];
//[request appendPostData:body];
[request setDelegate:self];
[request setTimeOutSeconds:13.0];
request.shouldAttemptPersistentConnection = NO;
[request setDidFinishSelector:#selector(uploadRequestFinished:)];
[request setDidFailSelector:#selector(uploadRequestFailed:)];
[request startAsynchronous];
}
- (void)uploadRequestFinished:(ASIHTTPRequest *)request
{
NSLog(#" Error - Statistics file upload ok: \"%#\"",[request responseString]);
}
- (void)uploadRequestFailed:(ASIHTTPRequest *)request{
NSLog(#" Error - Statistics file upload failed: \"%#\"",[[request error] localizedDescription]);
}
My PHP code:
<?php
$target = "./";
$target = $target . basename( $_FILES['avatar']['name']) ;
$ok=1;
if(move_uploaded_file($_FILES['avatar']['tmp_name'], $target))
{
echo "The file ok";
}
else {
echo "Sorry, there was a problem uploading your file.";
}
?>
At first i thought it was a folder permision thing but i tested it with a simple html form upload(with the same php file,unedited) and the file was uploaded in full size.
I know that such a method of uploading a file is dangerous,but for the moment it is the only thing i got.
Any ideas why my file it's not getting uploaded?
Thanks.

Ok,i followed your advise and actually used AFNetwork
Here is my code for helping out others.
NSData *imageToUpload = UIImageJPEGRepresentation(_imageView.image, 0.5f);
AFHTTPClient *client= [AFHTTPClient clientWithBaseURL:[NSURL URLWithString:#"http://domain.com"]];
NSMutableURLRequest *request = [client multipartFormRequestWithMethod:#"POST" path:#"upload.php" parameters:nil constructingBodyWithBlock: ^(id <AFMultipartFormData>formData) {
[formData appendPartWithFileData: imageToUpload name:#"avatar" fileName:fullFilename 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) {
if([operation.response statusCode] == 403){
NSLog(#"Upload Failed");
return;
}
NSLog(#"error: %#", [operation error]);
}];
[operation start];

Related

Objective-C Trying to download PDF that is from a short url

I have been trying to get this to work without having it load on the web view first and getting the absoluteString from that so I can download the URL. I have tried many shortURL solutions and they never fully load the URL. They always give me the URL that is not the final url and does not that the PDF url. Any help would be amazing. I am trying to download the PDF when the app first opens or when it checks for updates, but at the time it just gets the short url and I have to wait till the web view is called to get the full url to be able to download the PDF a head of time.
You download the PDF, just like you would download any other file.
Take a look at NSURLDownload
- (void)startDownloadingURL:sender
{
// Create the request.
NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.apple.com/index.html"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
// Create the download with the request and start loading the data.
NSURLDownload *theDownload = [[NSURLDownload alloc] initWithRequest:theRequest delegate:self];
if (!theDownload) {
// Inform the user that the download failed.
}
}
- (void)download:(NSURLDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename
{
NSString *destinationFilename;
NSString *homeDirectory = NSHomeDirectory();
destinationFilename = [[homeDirectory stringByAppendingPathComponent:#"Desktop"]
stringByAppendingPathComponent:filename];
[download setDestination:destinationFilename allowOverwrite:NO];
}
- (void)download:(NSURLDownload *)download didFailWithError:(NSError *)error
{
// Dispose of any references to the download object
// that your app might keep.
...
// Inform the user.
NSLog(#"Download failed! Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
}
- (void)downloadDidFinish:(NSURLDownload *)download
{
// Dispose of any references to the download object
// that your app might keep.
...
// Do something with the data.
NSLog(#"%#",#"downloadDidFinish");
}
Please check AppleDocs about handling redirect request.
try using afnetworking to download pdf file in to the server
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"https://letuscsolutions.files.wordpress.com/2015/07/five-point-someone-chetan-bhagat_ebook.pdf"]];
[request setTimeoutInterval:120];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
NSString *pdfName = #"2.zip";
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [[paths objectAtIndex:0] stringByAppendingPathComponent:pdfName];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:path append:NO];
[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
};
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"Download = %f", (float)totalBytesRead / totalBytesExpectedToRead);
NSLog(#"total bytesread%f",(float)totalBytesRead );
NSLog(#"total bytesexpected%lld",totalBytesExpectedToRead );
});
}];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Successfully downloaded file to %#", path);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
[operation start];
This is a method to open a pdf file from an URL with the UIDocumentInteractionController:
- (void)openURL:(NSURL*)fileURL{
//Request the data from the URL
NSURLSession *session = [NSURLSession sharedSession];
[[session dataTaskWithURL:fileURL completionHandler:^(NSData *data, NSURLResponse *response,NSError *error){
if(!error){
//Save the document in a temporary file
NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[response suggestedFilename]];
[data writeToFile:filePath atomically:YES];
//Open it with the Document Interaction Controller
_docController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:filePath]];
_docController.delegate = self;
_docController.UTI = #"com.adobe.pdf";
[_docController presentOpenInMenuFromRect:CGRectZero inView:self.view animated:YES];
}
}] resume];
}
And myViewController.h:
#interface myViewController : UIViewController <UIDocumentInteractionControllerDelegate>
#property UIDocumentInteractionController *docController;

AFNetworking 2 - Image upload - Request failed: unsupported media type (415)

I know this question was answered multiple times, but I tried all the answers with no luck. I don't think that I do something fundamentally wrong but something goes definitely wrong here.
I use the following code to upload PNG files to tinypng.com. As far as I can see the upload itself works, but I receive the error message: Request failed: unsupported media type (415)
The images I use are loaded as JPEG, then resized and transformed to PNG format. The saved files are fine. Now I want send them to the TinyPNG API before I save them to disc.
If anyone has an idea whats wrong or has experience with that service, please let me know.
Thanks in advance!
Detailed error message
Error Domain=com.alamofire.error.serialization.response Code=-1011 "Request failed: unsupported media type (415)"
UserInfo=0x6000000e4900 {
com.alamofire.serialization.response.error.response=<NSHTTPURLResponse: 0x600000220200> { URL: https://api.tinypng.com/shrink }
{
status code: 415, headers {
Connection = "keep-alive";
"Content-Length" = 77;
"Content-Type" = "application/json; charset=utf-8";
Date = "Tue, 16 Dec 2014 20:24:16 GMT";
Server = "Apache/2";
"Strict-Transport-Security" = "max-age=31536000";
"X-Powered-By" = "Voormedia (voormedia.com/jobs)";
}
},
NSErrorFailingURLKey=https://api.tinypng.com/shrink,
com.alamofire.serialization.response.error.data=<7b226572 726f7222 3a224261 64536967 6e617475
7265222c 226d6573 73616765 223a2244 6f657320 6e6f7420 61707065 61722074 6f206265 20612050
4e47206f 72204a50 45472066 696c6522 7d>,
NSLocalizedDescription=Request failed: unsupported media type (415)
}
The code I use
-(void) uploadImage:(NSImage *)image {
AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:[NSURL URLWithString:TINY_PNG_URL]];
CGImageRef cgRef = [image CGImageForProposedRect:NULL
context:nil
hints:nil];
NSBitmapImageRep *newRep = [[NSBitmapImageRep alloc] initWithCGImage:cgRef];
[newRep setSize:[image size]]; // if you want the same resolution
NSData *imageData = [newRep representationUsingType:NSPNGFileType properties:nil];
NSDictionary *parameters = #{#"username": USERNAME, #"password" : PASSWORD};
AFHTTPRequestOperation *operation = [manager POST:#"" parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
//append image
[formData appendPartWithFileData:imageData
name:#"filename"
fileName:#"photo.png"
mimeType:#"image/png"];
} success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Success: %# ***** %#", operation.responseString, responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %# ***** %#", operation.responseString, error);
}];
[operation start];
}
With the support of Mattijs from TinyPNG I've got it working! Thanks Mattijs!
The problem was, that the TinyPNG API expects the request body to only be the image data, which isn't the case with the multipart form data body I used in my original code.
My working solution is:
-(void) uploadImage:(NSImage *)image {
NSData *imageData = [self PNGRepresentationOfImage:image];
NSURL *url = [NSURL URLWithString:TINY_PNG_URL];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:imageData];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"image/png" forHTTPHeaderField:#"Content-Type"];
NSString *authStr = [NSString stringWithFormat:#"%#:%#", USERNAME, PASSWORD];
NSData *authData = [authStr dataUsingEncoding:NSASCIIStringEncoding];
NSString *authValue = [NSString stringWithFormat:#"Basic %#", [authData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed]];
[request setValue:authValue forHTTPHeaderField:#"Authorization"];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id result) {
NSLog(#"Success: %# ***** %#", operation.responseString, result);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %# ***** %#", operation.responseString, error);
}];
[operation start];
}

Upload PowerPoint via AFNetworking gets corrupt

I receive a successfully response when uploading a PowerPoint via the below code. It does get upload but the file is corrupt. When opening the corrupt file on the server via PowerPoint I get this message:
"PowerPoint found a problem with content in filename.pptx. PowerPoint can attempt to repair the presentation."
- (void)updateDocument:(NSString *) path parameters:(FileUploadParameters*)para success:(void (^)(void))success failure:(void (^)(NSError *error))failure
{
_postData = nil;
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:[ConfigurationUtil objectForKey:#"baseURL"]]];
_postData = [NSMutableData dataWithContentsOfFile:[path stringByStandardizingPath]];
_postData = [NSMutableData dataWithContentsOfFile:[path stringByStandardizingPath] options:NSDataReadingMapped error:nil];
NSMutableURLRequest *request = [httpClient multipartFormRequestWithMethod:HTTP_METHOD_POST
path:[self getQueryString:path parameter:para]
parameters:nil
constructingBodyWithBlock: ^(id <AFMultipartFormData>formData)
{
[formData appendPartWithFileData:_postData
name:[[path lastPathComponent] stringByDeletingPathExtension]
fileName:[[path lastPathComponent] stringByDeletingPathExtension] mimeType:#"application/powerpoint"];
}];
[request addValue:[NSString stringWithFormat:#"WRAP access_token=%#",[Tenant loadSharedTenantInstance].authToken] forHTTPHeaderField:#"Authorization"];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
if (success)
success();
}
failure:^(AFHTTPRequestOperation* operation, NSError* error)
{
if (failure)
failure(error);
}
];
[operation start];
}
Your AFNetworking code looks fine. I don't think that's the culprit.
You can use the cmp command line tool to compare the two files (the original and the upload) byte-for-byte and see if there's a difference. I think there won't be.
More likely: it's a misleading error message, and it's actually a permissions issue on the computer with Powerpoint installed, as outlined in this Microsoft Knowledge Base article.
The below code corrects the problem. It appears that appendPartWithFileData was causing the issue. It changes the filesize and that seemed to register the file as corrupt.
_postData = nil;
_postData = [NSMutableData dataWithContentsOfFile:[path stringByStandardizingPath]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]init];
NSString *queryString =[self getQueryString:path parameter:nil];
[request setURL:[NSURL URLWithString:queryString]];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:_postData];
[request addValue:[NSString stringWithFormat:#"WRAP access_token=%#",[Tenant loadSharedTenantInstance].authToken] forHTTPHeaderField:#"Authorization"];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
if (success)
success();
}
failure:^(AFHTTPRequestOperation* operation, NSError* error)
{
if (failure)
failure(error);
}
];
[operation start];

NSURL directory files

I have for example : www.example.com/ url.
Inside that URL there are few directories for example www.example.com/dir1/ and inside that there are images when clicked I get www.example.com/dir1/image1.jpg.
My problem is that I need to get all files inside www.example.com/dir1/ , so all images that are inside that directory on web. Based on that names I can get final url (like www.example.com/dir1/image1.jpg) but I need to get all the names of images and dunno how.
Thanks.
If you are seeing the apache directory listing you can parse that html and get all your .jpg files.
http://www.raywenderlich.com/14172/how-to-parse-html-on-ios is a tutorial on how to parse HTML
If this is on your server, you need some mechanism to retrieve the names of the files.
For example, if PHP, this is a script that returns a JSON response of all of the JPG/PNG files:
<?php
header('Content-type: application/json');
$files = scandir('.');
$images = array();
foreach ($files as $file)
{
switch(strtolower(substr(strrchr($file,'.'),1)))
{
case 'png':
case 'jpeg':
case 'jpg': $images[] = $file;
}
}
echo json_encode($images);
?>
You can then use NSURLConnection (or AFNetworking or whatever) to retrieve this and convert the JSON to a NSArray.
For example, using AFNetworking:
NSURL *url = [NSURL URLWithString:#"http://yourwebserver.com/some/path/images.php"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
if ([responseObject isKindOfClass:[NSArray class]])
[self doSomethingWithImageNames:responseObject];
else
NSLog(#"expected array, received: %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"AFHTTPRequestOperation error: %#", error);
}];
[op start];
Or NSURLConnection:
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (connectionError) {
NSLog(#"sendAsynchronousRequest error: %#", connectionError);
return;
}
NSError *jsonError = nil;
NSArray *imageNames = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
if (jsonError) {
NSLog(#"JSONObjectWithData error: %#", jsonError);
return;
}
[self doSomethingWithImageNames:imageNames];
}];
If you have to rely upon the HTML response, while you generally shouldn't use regular expressions, in this limited use case, you can probably get away with it. In my case, my web server reports links to the files using filename syntax, so I can grab those href tags with something like:
AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:request];
op.responseSerializer = [AFHTTPResponseSerializer serializer];
[op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
if (![responseObject isKindOfClass:[NSData class]]) {
NSLog(#"Was expecting `NSData` and got %#", responseObject);
return;
}
NSString *string = [[NSString alloc] initWithData:(NSData *)responseObject encoding:NSUTF8StringEncoding];
NSError *error = nil;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"<a\\s[\\s\\S]*?href\\s*?=\\s*?['\"](.*?)['\"][\\s\\S]*?>"
options:NSRegularExpressionCaseInsensitive
error:&error];
NSMutableArray *results = [NSMutableArray array];
[regex enumerateMatchesInString:string
options:0
range:NSMakeRange(0, [string length])
usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
[results addObject:[string substringWithRange:[result rangeAtIndex:1]]];
}];
[self doSomethingWithImageNames:results];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"AFHTTPRequestOperation error: %#", error);
}];
[op start];

Trying to login to a website in iOS app, no JSON response

I'm trying to login to a website and get a response using JSON using this code:
#try {
if([[txtUsername text] isEqualToString:#""] || [[txtPassword text] isEqualToString:#""] ) {
[self alertStatus:#"Please enter both Username and Password" :#"Login Failed!"];
} else {
NSString *post =[[NSString alloc] initWithFormat:#"username=%#&password=%#",[txtUsername text],[txtPassword text]];
NSLog(#"PostData: %#",post);
NSURL *url=[NSURL URLWithString:#"https://yedion.afeka.ac.il/yedion/fireflyweb.aspx?prgname=login"];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:url];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
[NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:[url host]];
NSError *error = [[NSError alloc] init];
NSHTTPURLResponse *response = nil;
NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSLog(#"Response code: %d", [response statusCode]);
if ([response statusCode] >=200 && [response statusCode] <300)
{
NSString *responseData = [[NSString alloc]initWithData:urlData encoding:NSUTF8StringEncoding];
NSLog(#"Response ==> %#", responseData);
SBJsonParser *jsonParser = [SBJsonParser new];
NSDictionary *jsonData = (NSDictionary *) [jsonParser objectWithString:responseData error:nil];
NSLog(#"%#",jsonData);
NSInteger success = [(NSNumber *) [jsonData objectForKey:#"success"] integerValue];
NSLog(#"%d",success);
if(success == 1)
{
NSLog(#"Login SUCCESS");
[self alertStatus:#"Logged in Successfully." :#"Login Success!"];
} else {
NSString *error_msg = (NSString *) [jsonData objectForKey:#"error_message"];
[self alertStatus:error_msg :#"Login Failed!"];
}
} else {
if (error) NSLog(#"Error: %#", error);
[self alertStatus:#"Connection Failed" :#"Login Failed!"];
}
}
}
#catch (NSException * e) {
NSLog(#"Exception: %#", e);
[self alertStatus:#"Login Failed." :#"Login Failed!"];
}
In the log I can see there is no JSON response so I can't know if the login was successful or not.
Is there any other way to login to this website and get a response wether or not it was successful?
Thanks!
The code seems ok to me but do check the web service and also check that you give correct keywords for json if the key given to the objectForKey and your key in web service are different you will never get a json response.
Use Get method and try
[ request setHTTPMethod:#"GET" ];