37

I've successfully created two different methods where each of them can upload either an image or text. But I am having problem writing a method that can post both text and image simultaneously!

// Here's my new method witch worked fine thanx to @sgosha:

- (void) upload {
    NSString *urlString = @"http://www.examplescript.com";
    NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
    [request setURL:[NSURL URLWithString:urlString]];
    [request setHTTPMethod:@"POST"];

    NSMutableData *body = [NSMutableData data];


    NSString *boundary = [NSString stringWithString:@"---------------------------14737809831466499882746641449"];
    NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
    [request addValue:contentType forHTTPHeaderField:@"Content-Type"];

    // file
    NSData *imageData = UIImageJPEGRepresentation(imageView.image, 90);

    [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithString:@"Content-Disposition: attachment; name=\"userfile\"; filename=\".jpg\"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithString:@"Content-Type: application/octet-stream\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[NSData dataWithData:imageData]];
    [body appendData:[[NSString stringWithString:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];

    // Text parameter1
    NSString *param1 = @"parameter text";
    [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"parameter1\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithString:param1] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithString:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];

    // Another text parameter
    NSString *param2 = @"Parameter 2 text";
    [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"parameter2\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithString:param2] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithString:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];

    // close form
    [body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];

    // set request body
    [request setHTTPBody:body];

    //return and test
    NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
    NSString *returnString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];

    NSLog(@"%@", returnString);
}

//Old question: Obviously this was too easy and didn't work! I do not get any error in the console or anything, and the image is uploaded, but the text is not sent. Any ideas?

Btw: The server-side script is a very simple php script.

Aleksander Akerø
  • 545
  • 2
  • 6
  • 9

4 Answers4

34

Try this (EDITED):

NSMutableData *body = [NSMutableData data];

// file
[body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithString:@"Content-Disposition: attachment; name=\"userfile\"; filename=\".jpg\"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithString:@"Content-Type: application/octet-stream\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[NSData dataWithData:imageData]];
[body appendData:[[NSString stringWithString:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];

// text parameter
[body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"parameter1\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[parameterValue1 dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithString:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];

// another text parameter
[body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"parameter2\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[parameterValue2 dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithString:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];

// close form
[body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];

// set request body
[request setHTTPBody:body];
sgosha
  • 1,299
  • 12
  • 19
  • Is "attachment" the only edit you've done here? If so, where should i pass the text? Would this just state that the image is sent as an attachment, and that I could then send the text in code following the boundary but before the setHTTPBody-call? – Aleksander Akerø Mar 26 '11 at 15:29
  • Tnx, for quality code:D Worked perfectly now, will update the original post with my method wich now works fine! – Aleksander Akerø Mar 30 '11 at 15:44
  • thanks for this. Really helped. Was totally stuck on how to send a text param along with the image – Maleck13 Jul 07 '11 at 20:08
  • 1
    Please consider updating to use `Content-Disposition:form-data;charset=UTF-8;name=...` as this will match the encoding `NSUTF8StringEncoding`. Non-english characters pasted into a form create are unusable to the server with this solution as posted – William Entriken Jun 12 '12 at 02:58
  • What is boundary? Can anyone explain please? – Tripti Kumar Jun 13 '14 at 11:36
  • @iPhoneDeveloper read this: http://www.w3.org/Protocols/rfc1341/7_2_Multipart.html – sgosha Jun 13 '14 at 19:20
  • changing "form-data"with "attachment" give me a "The request sent by the client was syntactically incorrect". – doxsi Jun 23 '14 at 11:56
7

I also wanted to upload an image along with other data in the same POST, most information about uploading images is just for uploading an image alone in one server connection, here is how I solved this.

This is the PHP

<?php
/* As you can see there are more values not only the image */
$variableOne    = $_POST['variableOne'];
$variableTwo    = $_POST['variableTwo'];
$variableThree  = $_POST['variableThree'];
$variableFour   = $_POST['variableFour'];
$variableFive   = $_POST['variableFive'];
$variableSix    = $_POST['variableSix'];
$variableSeven  = $_POST['variableSeven'];
$variableEight  = $_POST['variableEight'];
$variableNine   = $_POST['variableNine'];
$variableTen    = $_POST['variableTen'];

/* Our image */
$image = $_REQUEST['image'];

/* This is for trying to get a unique name for the image file, since maybe you want to store large amount of images */
$currentDate = date("Y-m-d");
$name  = "" . $currentDate . microtime() . rand(0, 999) . rand(0, 999) . rand(0, 999) . ".jpg";

/* 
 * Here comes the image stuff
 */
if (file_exists($name)) {
    echo "File already exists";
} else {
        /* Decoding image */
        $binary = base64_decode($image);

        /* Opening image */
        $file = fopen($name, 'wb');

        /* Writing to server */
        fwrite($file, $binary);

        /* Closing image file */
        fclose($file);

        echo "Added";
    }   
}   
?>

Then in Xcode copy and paste this method (taken from Creating a base-64 string from NSData)

- (NSString*)base64forData:(NSData*) theData {
    const uint8_t* input = (const uint8_t*)[theData bytes];
    NSInteger length = [theData length];

    static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

    NSMutableData* data = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
    uint8_t* output = (uint8_t*)data.mutableBytes;

    NSInteger i;
    for (i=0; i < length; i += 3) {
        NSInteger value = 0;
        NSInteger j;
        for (j = i; j < (i + 3); j++) {
            value <<= 8;

            if (j < length) {
                value |= (0xFF & input[j]);
            }
        }

        NSInteger theIndex = (i / 3) * 4;
        output[theIndex + 0] =                    table[(value >> 18) & 0x3F];
        output[theIndex + 1] =                    table[(value >> 12) & 0x3F];
        output[theIndex + 2] = (i + 1) < length ? table[(value >> 6)  & 0x3F] : '=';
        output[theIndex + 3] = (i + 2) < length ? table[(value >> 0)  & 0x3F] : '=';
    }

    return [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
}

In YourViewController.h file

@interface YourViewController : UIViewController {
    NSURLConnection *serverConnection;
    NSMutableData *returnData;
}

This is the server connection code

NSURL *sendURL = [NSURL URLWithString:@"http://yourdomainname/imagefolder/phpscript.php"];

NSMutableURLRequest *sendRequest = [NSMutableURLRequest requestWithURL:sendURL cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30];

[sendRequest setHTTPMethod:@"POST"];

[sendRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];

NSData *imageData = UIImageJPEGRepresentation(yourImage, 1.0);

NSString *encodedString = [[self base64forData:imageData] stringByReplacingOccurrencesOfString:@"+" withString:@"%2B"];

NSString *dataToSend = [[NSString alloc] initWithFormat:@"variableOne=%@&variableTwo=%@&variableThree=%@&variableFour=%@&variableFive=%@&variableSix=%@&variableSeven=%@&variableEight=%@&variableNine=%@&variableTen=%@&image=%@", valueOne, valueTwo, valueThree, valueFour, valueFive, valueSix, valueSeven, valueEight, valueNine, valueTen, encodedString];

[sendRequest setHTTPBody:[dataToSend dataUsingEncoding:NSUTF8StringEncoding]];

serverConnection = [[NSURLConnection alloc] initWithRequest:sendRequest delegate:self];

[serverConnection start];

Set delegate methods for server connection

- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    returnData = [[NSMutableData alloc] init];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    [returnData appendData:data];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    if (connection == serverConnection) {
        NSString *responseString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];

        NSLog(@"Response: %@", responseString);

        if ([responseString isEqualToString:@"Added"]) {

            /* Make something on success */

        } else {

            /* Make something else if not completed with success */

        }
    }
}

- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    /* Make something on failure */
}
Community
  • 1
  • 1
Carlo Espino
  • 1,354
  • 1
  • 15
  • 21
2

This code works for me with 1 image and 7 other parameters using POST Request

Make sure to change your variable names plus values and also image parameter name plus 'showPhoto' which is my IBOutlet UIImageView object 'name' shows URL parameter name.

NSString *str=@"http://xxx.xxx.xxx.xx/xxxx/xxxxx/xxxxx.php?action=add_place"; NSString *urlString = [NSString stringWithFormat:@"%@",str];

NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:urlString]];
[request setHTTPMethod:@"POST"];
NSMutableData *body = [NSMutableData data];
NSString *boundary = @"---------------------------14737809831466499882746641449";
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",boundary];
[request addValue:contentType forHTTPHeaderField: @"Content-Type"];

 NSData *imageData = UIImageJPEGRepresentation(_showPhoto.image, 90);

[body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[@"Content-Disposition: form-data; name=\"host_pic\"; filename=\"parkN.jpg\"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[@"Content-Type: application/octet-stream\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:imageData];
[body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];

//  parameter username

[body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"userID\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];

[body appendData:[@"17" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];


//  parameter token
[body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"longitude\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];

[body appendData:[@"50.0011" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];

//  parameter token
[body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"latitude\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];

[body appendData:[@"50.0011" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];

// parameter method
[body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"place_name\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];

[body appendData:[@"lahore" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];


//parameter method
[body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"place_description\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];

[body appendData:[@"lahore" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];

//parameter method
[body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"zip_code\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];

[body appendData:[@"123456" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];

//parameter method
[body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"phone_number\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];

[body appendData:[@"033333333" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];


// close form
[body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];


// setting the body of the post to the reqeust
[request setHTTPBody:body];


NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
// NSString *returnString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];
NSDictionary *dict=[NSJSONSerialization JSONObjectWithData:returnData options:NSJSONReadingMutableLeaves error:nil];
NSLog(@"%@",dict);
0

If you want to name the image:

 NSMutableString *nombreImagen= [[NSMutableString alloc]init];
    [nombreImagen appendString:@"Content-Disposition: attachment; name=\"file\"; filename=\""];
    [nombreImagen appendString:@"hoy"];
    [nombreImagen appendString:@".jpg\"\r\n"];
    .......

   [body appendData:[[NSString stringWithString:nombreImagen] dataUsingEncoding:NSUTF8StringEncoding]];
Carlos Mayoral
  • 313
  • 3
  • 12