Ok I believe this must be a pretty common scenario. I need to send a NSData variable over a HTTP request through a PHP page which then subsequently stores it in MySQL. This will be retrieved later by some other HTTP call which then downloads it into a NSData again. What is the best way to do this?
Should I convert the NSData into some sort of string representation (base64 etc)? Should I store the data in MySQL as VARCHAR or Blob? The data length will not exceed the MySQL/HTTP limit.
You're probably going to make things much easier on yourself by Base64 encoding the data for transmission back and forth to the server. (Or yEnc, or some other ASCII encoding of the bytes.) You certainly can transmit raw bytes back and forth (after all, that's what we do with images, right?), but there's less to worry about with encodings and other HTTP headers with string data.
On the server side, then, you could store the strings in character fields in the database, you could decode them and store in BLOBs, you could save them out to the file system.... Without knowing more about the requirements of your app, it's kind of hard to say what the "best" option would be.
Easiest way is to Base64 encode the data and create a web service that lets you send the information back and forth.
Here's a category for doing Base64 encoding/decoding that I found on the web:
ECBase64.h
#import <Foundation/Foundation.h>
@interface NSData ( NSDataBase64Additions )
+ (NSData*)dataWithBase64EncodedString: (NSString*)string;
- (id)initWithBase64EncodedString: (NSString*)string;
- (NSString*)base64Encoding;
- (NSString*)base64EncodingWithLineLength: (NSUInteger)lineLength;
@end
ECBase64.m:
#import "ECBase64.h"
static char encodingTable[64] = {
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/' };
@implementation NSData ( NSDataBase64Additions )
+ (NSData*)dataWithBase64EncodedString: (NSString*)string
{
NSData* result = [[NSData alloc] initWithBase64EncodedString: string];
return [result autorelease];
}
- (id)initWithBase64EncodedString: (NSString*)string
{
NSMutableData* mutableData = nil;
if ( string )
{
unsigned long ixtext = 0;
unsigned long lentext = 0;
unsigned char ch = 0;
unsigned char inbuf[4], outbuf[3];
short i = 0, ixinbuf = 0;
BOOL flignore = NO;
BOOL flendtext = NO;
NSData* base64Data = nil;
const unsigned char* base64Bytes = nil;
// Convert the string to UTF8 data.
base64Data = [string dataUsingEncoding: NSUTF8StringEncoding];
base64Bytes = [base64Data bytes];
mutableData = [NSMutableData dataWithCapacity: [base64Data length]];
lentext = [base64Data length];
while ( YES )
{
if ( ixtext >= lentext )
break;
ch = base64Bytes[ixtext++];
flignore = NO;
if ( ( ch >= 'A' ) && ( ch <= 'Z' ) )
ch = ch - 'A';
else if ( ( ch >= 'a' ) && ( ch <= 'z' ) )
ch = ch - 'a' + 26;
else if ( ( ch >= '0' ) && ( ch <= '9' ) )
ch = ch - '0' + 52;
else if ( ch == '+' )
ch = 62;
else if ( ch == '=' )
flendtext = YES;
else if ( ch == '/' )
ch = 63;
else
flignore = YES;
if ( !flignore )
{
short ctcharsinbuf = 3;
BOOL flbreak = NO;
if ( flendtext )
{
if ( !ixinbuf )
break;
if ( ( ixinbuf == 1 ) || ( ixinbuf == 2 ) )
ctcharsinbuf = 1;
else
ctcharsinbuf = 2;
ixinbuf = 3;
flbreak = YES;
}
inbuf [ixinbuf++] = ch;
if ( ixinbuf == 4 )
{
ixinbuf = 0;
outbuf [0] = ( inbuf[0] << 2 ) | ( ( inbuf[1] & 0x30) >> 4 );
outbuf [1] = ( ( inbuf[1] & 0x0F ) << 4 ) | ( ( inbuf[2] & 0x3C ) >> 2 );
outbuf [2] = ( ( inbuf[2] & 0x03 ) << 6 ) | ( inbuf[3] & 0x3F );
for( i = 0; i < ctcharsinbuf; ++i )
[mutableData appendBytes: &outbuf[i] length: 1];
}
if ( flbreak )
break;
}
}
}
self = [self initWithData: mutableData];
return self;
}
#pragma mark -
- (NSString* ) base64Encoding
{
return [self base64EncodingWithLineLength: 0];
}
- (NSString*)base64EncodingWithLineLength: (unsigned int)lineLength
{
const unsigned char* bytes = [self bytes];
NSMutableString* result = [NSMutableString stringWithCapacity: [self length]];
unsigned long ixtext = 0;
unsigned long lentext = [self length];
long ctremaining = 0;
unsigned char inbuf[3], outbuf[4];
short i = 0;
short charsonline = 0, ctcopy = 0;
unsigned long ix = 0;
while ( YES )
{
ctremaining = lentext - ixtext;
if ( ctremaining <= 0 )
break;
for( i = 0; i < 3; ++i )
{
ix = ixtext + i;
if ( ix < lentext )
inbuf[i] = bytes[ix];
else
inbuf [i] = 0;
}
outbuf [0] = (inbuf [0] & 0xFC) >> 2;
outbuf [1] = ((inbuf [0] & 0x03) << 4) | ((inbuf [1] & 0xF0) >> 4);
outbuf [2] = ((inbuf [1] & 0x0F) << 2) | ((inbuf [2] & 0xC0) >> 6);
outbuf [3] = inbuf [2] & 0x3F;
ctcopy = 4;
switch ( ctremaining )
{
case 1:
ctcopy = 2;
break;
case 2:
ctcopy = 3;
break;
}
for( i = 0; i < ctcopy; ++i )
[result appendFormat: @"%c", encodingTable[outbuf[i]]];
for( i = ctcopy; i < 4; ++i )
[result appendFormat: @"%c",'='];
ixtext += 3;
charsonline += 4;
if ( lineLength > 0 )
{
if ( charsonline >= lineLength)
{
charsonline = 0;
[result appendString: @"\n"];
}
}
}
return result;
}
@end
1st Suggestion: you can store it in a session in PHP
e.g. $_SESSION['mytext'] = <NSDATA>; don't forget to session_start(); to retrieve your string.
2nd Suggestion: you can store it in a XML FILE. That's if it supports XML
3rd Suggestion: just call it back from MYSQL to be safe.