Feb 23

Using AFNetworking with PHP to post to your own webserver (Example included)

Hello all,

I thought I’d start adding some bits of knowledge on here to help fellow developers. Every now and then I hit a hurdle that takes longer than expected to jump over, today it was with AFNetworking, an amazing little class for iOS/Mac development for doing network communications. I just have been a bit rusty on my php (7 years since last used), so it took me a little head banging to figure this out. It was extremely simple, but I had to go through a few herrings to get there.

I wanted a way for my beta testers to send me reports via the application, including autogenerated debug data.

#1) Have testers take screen shots and upload them. (Not user friendly, and lots of extra work for me to recreate the scenarios).
#2) Use a NSData of all the information I needed and upload it to my webserver. (ideal, just haven’t done that yet)

A little digging pointed me to AFNetworking, .

This looked great. Very easy to integrate, and seemingly easy to get up and running. But a couple caveats. Now like I said my php knowledge is long retired, I love the language, I just haven’t used it in years. So this would take a little head scratching. But the basics of what we’re doing is this.

#1 Install AFNetworking in your project (follow instructions from code, very simple, copy files, #include header, done).
#2 Create NSData to send (in this example a simple image)
#3 Package the data up in a JSON request with AFNetworking
#4 Send the request to webserver which has a php file to process the request. (in this case, take the file and copy it to a directory).

Ok, well #1 was easy we already do this in other parts of our code. But here’s the snippet for using an image bundled with your project. Oh and since we’re using UIImage, you need to import UIKit framework to your project if you haven’t already. UIImage is for iOS only, mac uses NSImage, but it’s very similar.

//This will look for a file called Default.png in your bundle
NSString *imgPath = [[NSBundle mainBundle] pathForResource:@"Default" ofType:@"png"];
//This loads the image into a NSData variable we'll use to send the message with
NSData *imgData = UIImagePNGRepresentation([UIImage imageWithContentsOfFile:imgPath]);

NSString *imgFileName = @"myDynamicFile.png";

Great. So we have that done. Now we construct the package from AFNetworking.

AFHTTPClient *client= [AFHTTPClient clientWithBaseURL:[NSURL URLWithString:@"http://myownwebserver.com/appUploads/"]];;
NSMutableURLRequest *myRequest = [client multipartFormRequestWithMethod:@"POST" path:@"upload.php" 
                                                             parameters:nil constructingBodyWithBlock: ^(id <AFMultipartFormData>formData) {
   [formData appendPartWithFileData:imgData name:@"uploadedfile" fileName:imgFileName mimeType:@"images/png"];

AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:myRequest];
[operation setUploadProgressBlock:^(NSInteger bytesWritten, NSInteger totalBytesWritten, NSInteger totalBytesExpectedToWrite) {
	NSLog(@"Sent %d of %d bytes", totalBytesWritten, totalBytesExpectedToWrite);
	[operation setCompletionBlock:^{
		NSLog(@"%@", operation.responseString); //Lets us know the result including failures
NSOperationQueue *queue = [[[NSOperationQueue alloc] init] autorelease];
[queue addOperation:operation];

Great! Now what I’ll point out is a bit I got stuck on.
This command:

   [formData appendPartWithFileData:imgData name:@"uploadedfile" fileName:imgFileName mimeType:@"images/png"];

The first argument is the NSData* we will pass, the next ‘name’ field is important. I was confused on the difference between this and filename, the last is the mimeType, make sure it’s appropriate for your file type, you can go here for valid types: .

So like I said I was confused on ‘name’ and ‘filename’, the filename is self explanitory, but the ‘name’ wasn’t, I later found in debugging that is going to be the name of the post object, so on our php script we’ll be iterating through that object (which comes as an associative array). So just hold that thought for now, we’ll show in the next step.

Now we need our PHP script setup on our server. A couple red herrings, make sure you have folder access and write access to your folders. Sometimes things like WordPress do a bunch of redirects which can cause your scripts to fail, we had this issue at one point, and had to modify .htaccess (I won’t cover that here, just googlie “wordpress exclude redirect”).

The script will be located in the path specified in the URL above, and it’ll be called ‘upload.php’ in this example. After a post is received, the script simply copies that to a subfolder called ‘uploads’ in this example.

Contents of upload.php

$target_path = "uploads/";

$target_path = $target_path . basename( $_FILES['uploadedfile']['name']); 

if(move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path)) {
    echo "The file ".  basename( $_FILES['uploadedfile']['name']). 
    " has been uploaded";
} else{
    echo "There was an error uploading the file, please try again!";

Ok remember that bit I got stuck on? That was the ‘uploadedfile’ which was the name we were passing from the JSON request. Initially I had a mismatch which would cause the php to not see any file as it was looking inside of $_Files['uploadedfile'], when in fact I sent something like $_Files['attachment']. The truth is you can have it named anything, just make sure they match! a small doh moment, but once I remembered how to debug a little php I sorted it out.

This is very simple… but hopefully it helps someone, if anything it’ll help me when I have to revisit this code. I wouldn’t use this code as-is, there is no type checking at all on the php, you may want that to validate your data and not crash your server (large files, etc).

I have to get back to work now to implement this in our new apps, highly likely there’s a typo in the code so feel free to correct it.

1 comment

  1. Yogev Sitton

    This was great – thank you very much :)

Leave a Reply