How to post JSON data to PHP database using objective-c? - php

I'm having an issue sending data to my online database. Nothing seems to post when I check the database. I performed an NSLog on the received response, and it's blank.
Here is the .php:
<?php
$db_host="someurl.com";
$db_username="some_user";
$db_pass="some_passwd";
$db_name="some_db";
$conn = mysql_connect($db_host, $db_username, $db_pass) or die ("Could not connect to
MySQL");
mysql_select_db("$db_name") or die ("No database");
// array for JSON response
$json = $_SERVER['HTTP_JSON'];
$data = json_decode($json);
$some1_id = $data->some1_id;
$imei = $data->imei;
//does the imei exist?
$result = mysql_query("SELECT * FROM usr_go WHERE imei = '".$imei."'");
if (mysql_num_rows($result) == 0){
if(isset($some1_id))
$result = mysql_query("INSERT INTO usr_go(some1_id, imei) VALUES('".$some1_id."','".$imei."')");
}
else{
if(isset($some1_id))
$result = mysql_query("UPDATE usr_go SET some1_id = '".$some1_id."' WHERE imei = '". $imei ." AND some1_id IS NULL ");
}
mysql_close($conn);
header('Content-type: application/json');
$response = $result;
echo json_encode($response);
?>
However, if I hard-code the $response to be some string value, and NSLog the received response, it receives the appropriate string value.
Here is my code:
NSDictionary *dict = #{#"some1_id" : [NSNumber numberWithInt:self.cellIndex]};
NSError *error = nil;
NSData *json = [NSJSONSerialization dataWithJSONObject:dict options:0 error:&error];
if (json)
{
NSURL *url = [NSURL URLWithString:#"someurl.com"];
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
[req setHTTPMethod:#"POST"];
[req setValue:#"application/json; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[req setHTTPBody:json];
NSURLResponse *res = nil;
NSData *ret = [NSURLConnection sendSynchronousRequest:req returningResponse:&res error:&error];
NSString *resString = [[NSString alloc] initWithData:ret encoding:NSUTF8StringEncoding];
NSLog(#"response String: %#",resString);
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSLog(#"JSON Output: %#", jsonString);
}
else
{
NSLog(#"Unable to serialize the data %#: %#", dictionary, error);
}
Is it the fact that it's not possible to insert the IMEI, which is why it's not posting, or some other issue?
Thanks for your assistance.

A couple of observations:
You should use msqli interface rather than the deprecated mysql interface.
You should never take input and just use it in SQL statement. Either use mysqli_real_escape_string or bind values (as shown below). This is critical to ensure you aren't susceptible to SQL injection attacks. It also protects you against innocent errors that can arise if the inserted value just happens to contain a reserved character.
Rather than trying to just json_encode the result of mysqli_query result, you should build a more meaningful associative array. For example, you might check the result of the mysqli call and return one JSON if it was successful, and another on failure. I might suggest having the failure rendition return the error message.
You should test your PHP either in a web browser, or test it from a device using something like Charles. Make sure you're getting back the JSON you expected before you go too far with your client code. Bottom line, see if you can test the client code and the server code in isolation of each other (or keeping it as simple as possible at first).
I'm not familiar with this $_SERVER['HTTP_JSON']; construct. If that works for you, great, but it doesn't work on my server. I've historically done fopen of php://input as illustrated below.
For example, this is a different database/table, but it might illustrate the idea of what the PHP code might look like:
// read JSON input
$handle = fopen("php://input", "rb");
$raw_post_data = '';
while (!feof($handle)) {
$raw_post_data .= fread($handle, 8192);
}
fclose($handle);
$request_data = json_decode($raw_post_data, true);
// prepare header for reply
header("Content-Type: application/json");
// open database
$mysqli = new mysqli($host, $userid, $password, $database);
// check connection
if ($mysqli->connect_errno) {
echo json_encode(array("success" => false, "message" => $mysqli->connect_error, "sqlerrno" => $mysqli->connect_errno));
exit();
}
// perform the insert
$sql = "INSERT INTO locations (message, device, longitude, latitude) VALUES (?, ?, ?, ?)";
if ($stmt = $mysqli->prepare($sql)) {
$stmt->bind_param("ssdd", $request_data["message"], $request_data["device"], $request_data["latitude"], $request_data["longitude"]);
if (!$stmt->execute())
$response = array("success" => false, "message" => $mysqli->error, "sqlerrno" => $mysqli->errno, "sqlstate" => $mysqli->sqlstate);
else
$response = array("success" => true);
$stmt->close();
} else {
$response = array("success" => false, "message" => $mysqli->error, "sqlerrno" => $mysqli->errno, "sqlstate" => $mysqli->sqlstate);
}
$mysqli->close();
echo json_encode($response);
Obviously, change this for your tables, but it illustrates some of the above concepts. I would generally add more error checking (e.g. the Content-Type of the request, test to make sure variables were set before I tried to use them, etc.), but you probably get the idea.
On the client side, there are also a few more minor observations:
The most serious problem is the use of sendSynchronousRequest. Use sendAsynchronousRequest instead (or any of a myriad of other, asynchronous techniques). Never issue synchronous requests from the main thread.
When parsing the response, resString will contain the raw JSON. I don't know what the jsonData variable you reference when building jsonString, but that doesn't look right.
If you want to parse the response, it would be:
NSError *parseError;
NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
By the way, the above assumes you return a JSON dictionary in your response, like I do in my example, rather than what your original JSON did.

Related

Sending array from PHP to NSURLSession

I'm currently trying to send an array, which contains text and images, from my PHP file to my iOS application using NSURLSession. Initially, I've tested with a text-only array which I've converted in JSON format before sending to my application: everything worked fine, but now I need to send an array with text and images, so I've done something like this:
Here is the code:
- PHP (sorry for non - english comments and variable names)
<?php
// Connessione al server mediante le credenziali.
$con = mysql_connect("localhost", "mobdev2015", "Pistacchio1");
if(!$con){
die("Server non trovato" . mysql_error());
}
// Seleziono il database.
$db = mysql_select_db("gandalf", $con);
if(!$db){
die("Database non trovato" . mysql_error());
}
// Mi metto in ascolto per ricevere l'user dall'utente.
$user = file_get_contents('php://input');
// Prelevo i dati dello studente, controllando se tutto va bene.
$sql = "SELECT * FROM Studente WHERE nomeUtente = '$user' ";
if(!mysql_query($sql, $con))
die ("Errore nella ricerca dello studente" . mysql_error());
// Prelevo i valori delle colonne del result set.
$result = mysql_query($sql, $con);
$resultSet = mysql_fetch_row($result);
// Prelevo il percorso dell'immagine dell'università dello studente, dato l'id nel risultato,
// Facendo sempre i vari controlli del caso.
$queryImmagineUni = "SELECT immagine FROM Universita WHERE id = '$result[5]'";
if(!mysql_query($queryImmagineUni, $con))
die ("Errore nella ricerca dell'università" . mysql_error());
$result = mysql_query($queryImmagineUni, $con);
$pathImmagine = mysql_result($result, 0);
//Inserisco tutti i dati nell'array, ottenendo le immagini mediante file_get_contents.
$datiutente = array(
"nome" => $resultSet[1],
"cognome" => $resultSet[2],
"email" => $resultSet[4],
"nomeUtente" => $resultset[6],
"immagineProfilo" => file_get_contents($resultSet[3]),
"immagineUni" => file_get_contents($pathImmagine)
);
//Mando in output il risultato e chiudo la connessione.
echo $datiutente;
mysql_close($con);
?>
immagineProfilo and (aka profileImage) and immagineUni (aka universityImage) are two paths retrieved from database (like "./folder/image.jpg").
iOS:
// Setting up the url of the request (we will call a php file).
NSURL *url = [[NSURL alloc]initWithString:#"http://inserturlhere.com/userdata.php"];
// Creating the NSMutableRequest object, which will contain the HTML headers and the nickname needed to retrieve data.
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:url];
// Converting the NSString into NSData to append at MutableURLRequest.
NSData *postData = [user dataUsingEncoding:NSASCIIStringEncoding];
//Setting the method to post
[request setHTTPMethod:#"POST"];
// Setting the body of the post to the reqeust
[request setHTTPBody:postData];
//
/*
NSURLSession needs a NSURLSessionConfiguration to run, so we instiate a NSURLSessionConfiguration object saying
we want to use a default Session, then we create a session with that configuration
*/
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
// Starting a dataTask with the request previously defined. The completion handler will be used to manage the response
// from the server, stored in a NSURLResponse object.
[[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSArray *datiUtente = [NSKeyedUnarchiver unarchiveObjectWithData:data];
NSLog(#"%#", datiUtente);
}]resume];
The problem in this solution is I can't print the content of the array which should contain the contents of the PHP array, but using the debugger I can see data is not NULL, so it seems like something is sent.
Your PHP line says:
echo $datiutente;
Instead, you want to return JSON, which can be easily parsed by the client. So, you should specify that the response will be JSON (and do this before you echo anything):
header('Content-type: application/json');
And then, the echoing of the response data would be:
echo json_encode($datiutente);
And then to parse it on the client side, you want:
[[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(#"%#", error);
}
if (!data) {
return;
}
NSError *parseError;
NSArray *datiUtente = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
if (datiUtente) {
NSLog(#"responseObject = %#", datiUtente);
} else {
NSLog(#"parseError = %#", parseError);
NSLog(#"responseString = %#", [[NSString alloc] initWithData:data encoding: NSUTF8StringEncoding]);
}
}] resume];
By the way, when you build a JSON response, you cannot include binary data (namely, the image payload). So if you're going to include the image(s) in the JSON response, make sure to base64_encode them (and then decode them on the client side):
$datiutente = array(
"nome" => $resultSet[1],
"cognome" => $resultSet[2],
"email" => $resultSet[4],
"nomeUtente" => $resultset[6],
"immagineProfilo" => base64_encode(file_get_contents($resultSet[3])),
"immagineUni" => base64_encode(file_get_contents($pathImmagine)),
"success" => true
);
Personally, I would not be inclined to include the image payload in the JSON ar all (because it increases the size of the response by several orders of magnitude, slowing it down). I might prefer to just include a URL for the image in the response, and let the client request the image itself, if and when it needs it. You can make the app more responsive with that sort of design. But that's up to you.
Note, in addition to the above change, I also added a success code. This can be useful so that the client can quickly determine whether the response was successful or not.
Obviously, you want to JSON encode failures, too. For example, if the MySQL connection failed, you should indicate that in a JSON response (and include the appropriate information provided by MySQL):
if (!$con) {
$response = array(
"success" => false,
"message" => "Server non trovato",
"sqlerror" => mysql_error(),
"sqlerrno" => mysql_errno()
);
echo json_encode($response);
exit();
}
Once you get this working, a few other observations:
Do not just take the posted data and use it in a query. That exposes you to SQL injection attacks. Remember to mysql_real_escape_string that input before using it in a query.
I'd probably change the request created by the client code to be a application/x-www-form-urlencoded request (e.g., user=...) or a application/json request (e.g. use NSJSONSerialization dataWithJSONObject to build request that looks like {"user": "..."}). and then parse it on the server side.
Note this MySQL interface is deprecated. As the docs say:
This extension was deprecated in PHP 5.5.0, and it was removed in PHP 7.0.0. Instead, the MySQLi or PDO_MySQL extension should be used. See also MySQL: choosing an API guide and related FAQ for more information.

Show result in a UITextField

I am facing a problem with fill (text field) with result which requested from MySql via a PHP file. I did change the PHP file to a different ways but I still have the same problem.
Her is my PHP file:
<?php
$host="localhost"; // Host name
$username="UserName"; // Mysql username
$password="PassWord"; // Mysql password
$db_name="DataBase"; // Database name
$tbl_name="Table"; // Table name
// Connect to server and select databse.
mysql_connect("$host", "$username", "$password")or die("cannot connect");
mysql_select_db("$db_name")or die("cannot select DB");
mysql_set_charset('utf8');
// To protect MySQL injection (more detail about MySQL injection)
$userName = $_REQUEST['userName'];
$userName = stripslashes($userName);
$userName = mysql_real_escape_string($userName);
$userName = html_entity_decode($_REQUEST['userName'], ENT_QUOTES, "UTF-8");
$sql="SELECT * FROM $tbl_name WHERE userName = '$userName'";
mysql_query("SET NAMES 'utf8'"); //5
$result = mysql_query($sql);
// Mysql_num_row is counting table row
$count = mysql_num_rows($result);
$count = 1;
$items;
while($row = mysql_fetch_array($result)) {
$item['userName'] = $row['userName'];
$item['emailAddress'] = $row['emailAddress'];
$items[$count] = $item;
}
//echo json_encode($items);
echo json_encode($items, JSON_UNESCAPED_UNICODE);
?>
Her is the Objective-c code (in Xcode):
- (id)makeURLRequestWithString:(NSString *)url {
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:url]
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:10];
NSURLResponse *response;
NSError *error;
// Make synchronous request
NSData *urlData = [NSURLConnection sendSynchronousRequest:urlRequest
returningResponse:&response
error:&error];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
if (urlData) {
NSDictionary *dict = [NSJSONSerialization
JSONObjectWithData:urlData
options:kNilOptions
error:&error];
return dict;
} else return error;
}
Her is the code when I press the button:
- (IBAction)callJson:(id)sender {
dispatch_queue_t jsonParsingQueue = dispatch_queue_create("jsonParsingQueue", NULL);
dispatch_async(jsonParsingQueue, ^{ //Do request on another queue to prevent it from blocking UI
id result = [self makeURLRequestWithString:#"http:/MyWebSite.com/PHPFile.php?userName=123"];
NSLog(#"%#", result);
// Her where I need to fill my text with info from the above url
// self.emailAddress.text = ...............What to do her?
});
}
Her is the result from Xcode:
{
1 = {
emailAddress = "123#hotmail.com";
userName = "123";
};
}
The request shows the data, but I don't no how to fill the text with it.
I hope my question is clear.
Thanks
You can parse the results into an NSDictionary/NSArray with NSJSONSerialization. If your result is a data object, you could call
NSError *err;
NSDictionary *results = [NSJSONSerialization JSONObjectWithData:data options:0 error:&err];
NSString *email = [[results objectForKey:#"1"] objectForKey:#"emailAddress"];
Then to stick it in the textbox you would just use the normal code
textbox.text = email;
EDIT:
Ok, I see now you have already thrown in the Parsing JSON in the above method. So when you are calling self.emailAddress.text You are still in a background thread with your dispatch_async() call. So in order to make it actually update the text box you would do the following right after you get id result =...
dispatch_async(dispatch_get_main_queue(), $^{
self.emailAddress.text = [[result objectForKey:#"1"] objectForKey:#"emailAddress"];
});
Another tip, it's a little weird that your JSON data starts at index 1, if it is going to be an ordered list (eg. 1, 2, 3, 4..) you should format it like an array. I think I see the problem in your PHP, it should look more like this (assuming I understand what you are trying to do):
...
while($row = mysql_fetch_array($result)) {
var $tmp = [];
$tmp['userName'] = $row['userName'];
$tmp['emailAddress'] = $row['emailAddress'];
$items[] = $tmp;
}
...
That will output an array of Items from the database with dictionaries containing the emails and usernames like so
[
{'email1', 'user1'},
{'email2', 'user2'}
]
But if you do it that way, you'd have to change your code above in the makeUrlrequestwithstring method to return an array like this:
if (urlData) {
NSArray *arr = [NSJSONSerialization
JSONObjectWithData:urlData
options:kNilOptions
error:&error];
return arr;
} else return error;
Then your output code would look like this (assuming you wanted the first item in the query result)
dispatch_async(dispatch_get_main_queue(), $^{
self.emailAddress.text = [result[0] objectForKey:#"emailAddress"];
});

iOS not accepting json response from php web service

I am a beginner to iOS. I have a simple web service that retrieves data from a table and sends out the results in JSON. I am trying to communicate with that web service from iOS to receive the JSON response but facing issues. This is the error i receive:
Request Failed with Error: Error Domain=AFNetworkingErrorDomain Code=-1016 "Expected content type {(
"text/json",
"application/json",
"text/javascript"
)}, got text/html" UserInfo=0x7598e70
Here are my code snippets:
PHP Web Service:
$stmt = "SELECT STORE_TYPE, STORE_NAME FROM STORE WHERE STORE_ZIP = $zip";
$result = mysqli_query($this->databaseconnection, $stmt);
$storelist = array();
$store = array();
$jsondata;
while ($row = mysqli_fetch_assoc($result)) {
$store['STORE_TYPE'] = $row['STORE_TYPE'];
$store['STORE_NAME'] = $row['STORE_NAME'];
array_push($storelist,$store);
}
$jsondata = json_encode($storelist);
echo $jsondata;
I am getting the following result when i execute my php form the browser:
[{"STORE_TYPE":"GROCERY","STORE_NAME":"Walmart"},{"STORE_TYPE":"BAKERY","STORE_NAME":"Lanes Bakery"},{"STORE_TYPE":"GROCERY","STORE_NAME":"Copps"}]
iOS Code Snippet to communicate with the Web Service:
NSURL *url = [NSURL URLWithString:#"http://localhost/~Sandeep/store/store.php?rquest=getstores&zip=53715"];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSLog(#"%#", JSON);
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
NSLog(#"Request Failed with Error: %#, %#", error, error.userInfo);
}];
[operation start];
I looked at a lot of tutorials and they all say that performing a 'json_encode' on an array in php encodes the data in JSON format and 'echo' of that is the way to go send the encoded JSON as a response. For some reason my iOS is not seeing that as JSON. I am not sure what I am missing/doing wrong here.
I really appreciate your inputs on this.
Thanks!
You need to set the correct content type(use header), the error lists the acceptable types though you should use application/json
$stmt = "SELECT STORE_TYPE, STORE_NAME FROM STORE WHERE STORE_ZIP = $zip";
$result = mysqli_query($this->databaseconnection, $stmt);
$storelist = array();
$store = array();
$jsondata;
while ($row = mysqli_fetch_assoc($result)) {
$store['STORE_TYPE'] = $row['STORE_TYPE'];
$store['STORE_NAME'] = $row['STORE_NAME'];
array_push($storelist,$store);
}
$jsondata = json_encode($storelist);
header('Content-Type: application/json');
echo $jsondata;

Parsing JSON from PHP by SBJson

Now I'm trying to POST jpeg files to MySQL via PHP and GET from MySQL to iOS.
In GET method I encode jpeg(as NSData) and some related data(ex. caption, timestamp) to JSON on PHP script using json_encode().
{"caption":"(captiondata)","img":"(imagedata)","timestamp":"(timestampdata)"}
Then I set the datas into array like,
[{"caption":"(captiondata)","img":"(imagedata)","timestamp":"(timestampdata)"},
{"caption":"(captiondata)","img":"(imagedata)","timestamp":"(timestampdata)"},
.......,
{"caption":"(captiondata)","img":"(imagedata)","timestamp":"(timestampdata)"}]
I believe I can parse and get this JSON by echo (json_encode ()) on PHP and SBJsonParser on iOS but nothing returns to my App. Here's my code in iOS.(Also I use TTURLRequest by Three20)
TTURLRequest* request = [TTURLRequest requestWithURL:url delegate:self];
request.cachePolicy = cachePolicy;
TTURLJSONResponse* response = [[[TTURLJSONResponse alloc] init] autorelease];
request.response = response;
[request send];
- (void)requestDidFinishLoad:(TTURLRequest*)request {
TTURLJSONResponse* response = request.response;
NSLog(#"%#",response);
}
Can you print all the logs in requestDidFinishLoad:?
The response is the rootObject of TTURLJSONResponse.
- (void)requestDidFinishLoad:(TTURLRequest*)request {
TTURLJSONResponse *response = request.response;
NSDictionary *dict = response.rootObject;
NSLog(#"dict : %#",dict);
}
In your case,
- (void)requestDidFinishLoad:(TTURLRequest*)request {
TTURLJSONResponse* response = request.response;
NSLog(#"%#",response);
}
The response may look like <TTURLJSONResponse: 0x125398c0>
If still nothing returns, you may check the requestDidFinishLoad: is been called and not the cache issue.

JSON Encoding Multiple Query returns in PHP for iOS

I followed Ray Wenderlich's tutorial on creating a web service / hooking it up to iOS but his example the returned results only have one possible row returned in the query. I'd like to return all possible results in a JSON format but I am confused how to store them as the correct key.
Here's what I have for the PHP:
$stmt = $this->db->prepare('SELECT userID, lat, lng FROM Connections WHERE airline=? AND flight_number=? ');
$stmt->bind_param("si", $airline, $flight_number);
$stmt->execute();
$stmt->bind_result($otherUser, $otherLat, $otherLng);
while ($stmt->fetch()) {
break;
}
$stmt->close();
if ($otherUser) {
//sendResponse(403, 'Code already used');
//return false;
$myLatLng = "$lat,$long";
$otherLatLng="$otherLat,$otherLng";
$results = getDistanceBetween($myLatLng,$otherLatLng);
$miles = $results[0];
$minutes = $results[1];
$result = array(
"other_user" => $otherUser,
"distance" => $miles,
"duration" => $minutes,
);
sendResponse(200, json_encode($result));
return true;
}
On the Obj-C side of things I get these values using this code:
if (request.responseStatusCode == 200) {
NSString *responseString = [request responseString];
NSDictionary *responseDict = [responseString JSONValue];
NSString *otherUser = [responseDict objectForKey:#"other_user"];
NSString *otherDistance = [responseDict objectForKey:#"distance"];
NSString *otherDuration = [responseDict objectForKey:#"duration"];
Can someone please help me out?
In your PHP code you want to create a nested array and then use json_encode(). Here is a previous question with more detail about the PHP side of your problem: How to create an array for JSON using PHP?
On the iOS side, since your webservice will return a JSON response representing multiple items, calling JSONValue on the response string will return an NSArray object instead of an NSDictionary. You can then iterate over the items in the array (which will themselves be NSDictionary items) and pull out the values you need.
NSString *responseString = [request responseString];
NSArray *responseArray = [responseString JSONValue];
for (NSDictionary* item in responseArray) {
NSString *otherUser = [item objectForKey:#"other_user"];
NSString *otherDistance = [item objectForKey:#"distance"];
NSString *otherDuration = [item objectForKey:#"duration"];
}

Categories