RESTful Web Service in iPhone: Data not inserted to database
I started out by doing a tutorial using the 'shapes' web services that comes with MAMP. Now I am trying to recreate a service for myself. I have now been looking for solutions or how to debug the problem for the past 5 hours. My forte is not PHP, so I am not sure how I can setup debug or some sort of way to print out the URL response. Anyone's help is greatly appreciated.
Objective-C Code:
NSString* serviceRootUrlString = @"http://localhost:8888/answers/Answers/";
NSURL* answerService = [NSURL URLWithString:serviceRootUrlString];
_database = [[Database alloc] initWithServiceUrl:answerService];
- (void)nextQuestionWithAnswer:(NSString *)answer andComment:(NSString *)comment
{
NSString* deviceId = [[UIDevice currentDevice] uniqueIdentifier];
NSData* deviceIdAsData = [deviceId dataUsingEncoding:NSUTF8StringEncoding];
NSString* deviceHash = [Database MD5Hash:deviceIdAsData];
NSMutableDictionary* answerDictionary = [NSMutableDictionary dictionary];
[answerDictionary setObject:deviceHash forKey:@"SetId"];
[answerDictionary setObject:[NSNumber numberWithInt:(_currentQuestionNumber + 1)] forKey:@"QuestionId"];
[answerDictionary setObject:answer forKey:@"Answer"];
[answerDictionary setObject:comment forKey:@"Comment"];
[_database insertRecordWithDictionary:answerDictionary];
[self nextQuestion];
}
- (BOOL)insertRecordWithDictionary:(NSDictionary *)recordDictionary
{
NSData* recordPropertyListData = [NSPropertyListSerialization dataFromPropertyList:recordDictionary format:NSPropertyListXMLFormat_v1_0 errorDescription:nil];
NSMutableURLRequest* urlRequest = [NSMutableURLRequest requestWithURL:_serviceUrl];
[urlRequest setHTTPMethod:@"POST"];
[urlRequest setHTTPBody:recordPropertyListData];
NSURLResponse* response = nil;
NSError* error = nil;
NSData* responseData = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:&error];
id propertyList = [NSPropertyListSerialization propertyListWithData:responseData options:NSPropertyListImmutable format:nil error:nil];
NSDictionary* responseDictionary = (NSDictionary*)propertyList;
NSLog(@"New Record result: %@", responseDictionary);
if (error == nil)
{
return YES;
}
else
{
NSLog(@"Database Error: %@", [error description]);
return NO;
}
}
PHP Code:
<?php
require_once 'CFPropertyList/CFPropertyList.php';
// connect to database
$connection = mysql_connect("localhost:8889","root","root");
if (!$connection)
die("Could not connect: " . mysql_error());
// Database layout
$databaseName = "answers";
$surveyAnswersTableName = "Answers";
$surveyAnswersArrayName = "Answers";
$answerId = "Id";
$answerTimeStamp = "TimeStamp";
$answerSetId = "SetId";
$answerQuestionId = "QuestionId";
$answerAnswer = "Answer";
$answerComment = "Comment";
// Determine the requested resource, stripping开发者_开发技巧 empty resource elements and the base name
$base = "answers";
$resourceKeys = array_merge(array_diff(explode("/", $_SERVER[REQUEST_URI]), array("", $base)));
// Detect usage of the old setup
if (count($resourceKeys) == 0)
die("Specify a table that contains your shapes. Ex: http://the_host_name:8888/answers/your_user_name/");
// Use the first resource key as the table name, then strip it away
$surveyAnswersTableName = $resourceKeys[0];
$resourceKeys = array_merge(array_diff($resourceKeys, array($surveyAnswersTableName)));
// Check for the database. Create the database and populate it if it does not exist
$databaseExists = mysql_select_db($databaseName, $connection);
if (!$databaseExists)
{
// Create and select the ozzie database
mysql_query("CREATE DATABASE $databaseName",$connection);
$databaseExists = mysql_select_db($databaseName, $connection);
if (!$databaseExists)
die("Could not create database $databaseName: " . mysql_error());
}
// Check for the requested answers table
$sql = "SHOW TABLES LIKE '$surveyAnswersTableName'";
mysql_query($sql, $connection);
$row = mysql_fetch_array($result);
print($row);
// Create it if it does not exist
if ($row == FALSE)
{
// Create the table that holds the answers
$sql = "CREATE TABLE $surveyAnswersTableName
(
$answerId int NOT NULL AUTO_INCREMENT PRIMARY KEY,
$answerTimeStamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
$answerSetId text,
$answerQuestionId int,
$answerAnswer text,
$answerComment text
)";
mysql_query($sql, $connection);
}
if ($_SERVER[REQUEST_METHOD] == "POST")
{
// Insert or append shape specified in POST to the database
if (count($resourceKeys) == 0)
{
// Load the posted plist into a property list object
// HACK: Save post data to file to load into plist. Should be able to load directly from php://input, but won't...
$postdata = file_get_contents("php://input");
$fileName = dirname(__FILE__) . "/tmp.php";
$file = fopen($fileName, 'w') or die("Cannot open file");
fwrite($file, $postdata);
fclose($file);
$postPlist = new CFPropertyList($fileName);
unlink($fileName);
// Unpack data for answer
// TODO: Verify data
$answerDictionary = $postPlist->getValue(true);
$setId = $answerDictionary->get($answerSetId);
$questionId = $answerDictionary->get($answerQuestionId);
$answer = $answerDictionary->get($answerAnswer);
$comment = $answerDictionary->get($answerComment);
// Insert answer into database
$sql = "INSERT INTO $surveyAnswersTableName
(
$answerSetId,
$answerQuestionId,
$answerAnswer,
$answerComment
)
VALUES
(
'$setId',
'$questionId',
'$answer',
'$comment'
)";
mysql_query($sql,$connection);
print($sql);
// Package result into outer dictionary
// TODO: Call method instead
$resultDictionary = new CFDictionary();
$resultDictionary->add($surveyAnswersArrayName, new CFString("Answer inserted."));
// Package outer dictionary into a property list and transmit
$resultPlist = new CFPropertyList();
$resultPlist->add($resultDictionary);
header("Content-type: text/xml");
print($resultPlist->toXML(true));
}
else if (count($resourceKeys) >= 1)
{
// Load the posted plist into a property list object
// HACK: Save post data to file to load into plist. Should be able to load directly from php://input, but won't...
$postdata = file_get_contents("php://input");
$fileName = dirname(__FILE__) . "/tmp.php";
$file = fopen($fileName, 'w') or die("Cannot open file");
fwrite($file, $postdata);
fclose($file);
$postPlist = new CFPropertyList($fileName);
unlink($fileName);
// Unpack data for shape
// TODO: Verify data
$answerDictionary = $postPlist->getValue(true);
$setId = $answerDictionary->get($answerSetId);
$questionId = $answerDictionary->get($answerQuestionId);
$answer = $answerDictionary->get($answerAnswer);
$comment = $answerDictionary->get($answerComment);
// Determine requested shape
$requestedAnswerSetId = $resourceKeys[0];
// Query to re-number shapes
$sql = "UPDATE $surveyAnswersTableName SET $answerId = $answerId + 1 WHERE $answerId >= $requestedAnswerId";
print($sql);
$result = mysql_query($sql);
// Insert shape into database
$sql = "INSERT INTO $surveyAnswersTableName
(
$answerSetId,
$answerQuestionId,
$answerAnswer,
$answerComment
)
VALUES
(
'$setId',
'$questionId',
'$answer',
'$comment'
)";
mysql_query($sql,$connection);
print($sql);
// Package result into outer dictionary
// TODO: Call method instead
// TODO: Verify that add completed successfully
$resultDictionary = new CFDictionary();
$resultDictionary->add($surveyAnswersArrayName, new CFString("Answer inserted."));
// Package outer dictionary into a property list and transmit
$resultPlist = new CFPropertyList();
$resultPlist->add($resultDictionary);
header("Content-type: text/xml");
print($resultPlist->toXML(true));
}
else
die("Invalid request");
}
?>
I know I am asking a lot for someone to analyze this code but it would be greatly appreciated.
For print response using iOS and XCode:
NSData* responseData = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:&error];
NSLog(@"Reponse: %@", [[[NSString alloc]initWithData:responseData encoding:NSUTF8StringEncoding] autorelease]);
For check php response without iOS just create somewhere html file with HTML form which contains inputs. Those inputs must have the same keys and values like in your recordDictionary variable. Form action should be like in your serviceRootUrlString variable, method POST.
See this tutorial for more information about HTML forms
精彩评论