I have a PHP script on a server, all working fine for most of the thing I need it to do. I'm now setting up special user privileges for certain users.
I check if the logged in user is registered on a special user database, then return the name of their privleges or 'blank' using the following:
private function checkSpecialUser($userID)
{
$db = new DbConnect();
$result = $db->query("SELECT privelege FROM special_users WHERE userID = $userID");
if ($privName = $result->fetch_object())
{
echo $privName->privelege;
}
else
{
echo 'blank';
}
$db->close();
}
In Xcode, I have set up a simple function to return the string which is returned by the PHP script (I'll leave out the connection part since that all works fine):
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&requestError];
NSString *packName = (NSString *)[[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];
packName = [packName stringByReplacingOccurrencesOfString:#" " withString:#""];
NSLog(#"packName is %#", packName);
if([packName isEqualToString:#"blank"])
{
NSLog(#"user is not special");
}
else
{
NSLog(#"User is special :-)");
}
return packName;
Now to the problem I have. If the user does not have special privileges then the first NSLog prints "packName is blank" which is exactly what I would expect. However, the if statement should then pick up that packName is equalToString "blank", which it doesn't. It always reaches 'else' and prints "User is special :-)".
I've double checked with users who ARE registered, and although it returns the string I would expect, again it doesn't trigger an equalToString response.
Do PHP echoes have hidden characters in them that I would need to remove, or am I somehow getting the value from the database incorrectly? In the database each row is simply a userID which is a varchar, and the name of their privilege which is also a varchar.
If anyone has any tips I'd be really grateful. Thanks.
Try, instead of sending back "blank", sending back nothing, or an empty string. Then, instead of matching the word "blank", test the length of the string. This will at least tell you if there are other characters in packName... you might remove more than just space whitespace, if I had to guess I'd say you've got a newline in there.
Related
I am doing some work in php try to encrypt a string by SHA1. However, I need to match the result to the result of someone else who has done in Xcode.
What he has written in Xcode is as following:
NSString *saltedPassword = [NSString stringWithFormat:#"%#%#",_myTextField.text,saltKey];
NSString *hashedPassword = nil;
unsigned char hashedPasswordData[CC_SHA1_DIGEST_LENGTH];
NSData *saltedData = [saltedPassword dataUsingEncoding:NSUTF8StringEncoding];
if (CC_SHA1([saltedData bytes], [saltedData length], hashedPasswordData)) {
hashedPassword = [[NSString alloc] initWithBytes:hashedPasswordData length:sizeof(hashedPasswordData) encoding:NSASCIIStringEncoding];
} else {
NSLog(#"ERROR: registerAction, should not be here");
abort();
}
I don't know Xcode very well. My understand of what he has done is:
concatenate the string with the key to get a new string, let's call it "string1".
encode the string1 as UTF-8,let's call the encodes string "string2"
use SHA1 to encrypt string2, length is 20 (CC_SHA1_DIGEST_LENGTH is 20,right?),let's call the encrypted string "string3"
encode "string3" as ASCII to get the final result.
So, based on my understanding above, I wrote the code in php as following:
$password.=$configs['key'];
$password=mb_convert_encoding($password, "UTF-8");
$codedPassword=sha1($password, $raw_output = TRUE);
$codedPassword=mb_convert_encoding($codedPassword, "ASCII");
echo($codedPassword);
$password is the string I want to encrypt.
But the result I got is different from the result from Xcode. We use the same key.
For example:
If the input is "123456", the output of Xcode is "Õÿ:>/
o×NVÛ²¿+(A7", the output of php is "|J? ?7b?a?? ?=?d???". (I am not sure if these are the exact string or the string itself contains some characters that cannot be displayed.)
Does anyone know how to change the php code to get the same result?(It would be perfect that your solution is about how to change the PHP code. Because I cannot change the Xcode for the moment. My job is to write the PHP code to match the Xcode's result.)
You seem to be describing:
NSData *saltedData = [saltedPassword dataUsingEncoding:NSUTF8StringEncoding];
as 'encode the string1 as UTF-8,let's call the encodes string "string2"' and doing:
$password=mb_convert_encoding($password, "UTF-8");
However that step is converting the string into a byte array, look at for instance the answers to this question String to byte array in php, it seems you should do something like this in that step:
$bytes = unpack("H*",$password);
Like the title says, my UITextView is setup to print data found within "userName". Instead of behaving appropriately, it prints "userName".
PHP code:
<?php
header('Content-Type: application/json');
$arr = array ('userName'=>'derekshull', 'userBio'=>'This is derekshulls bio','userSubmitted'=>'15');
echo json_encode($arr);
?>
Objective C:
- (void)viewDidLoad
{
[super viewDidLoad];
NSURL *myURL = [[NSURL alloc]initWithString:#"http://techinworship.com/json.php"];
NSData *myData = [[NSData alloc]initWithContentsOfURL:myURL];
NSError *error;
NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData:myData options:NSJSONReadingMutableContainers error:&error];
if(!error)
{
for (id element in jsonArray) {
textview.text = [NSString stringWithFormat:#"%#", [element description]];
// text view will contain last element from the loop
}
}
else{
textview.text = [NSString stringWithFormat:#"Error--%#",[error description]];
}
}
What am I missing here? Also, when run, the application does not crash and give error. However, the following is documented in the DeBug Area.
2014-03-24 20:20:53.258 testtest[11434:60b] Unknown class textview in Interface Builder file.
I don't currently have a OSX computer available so I can't evaluate my code.
It seems like the array you have in you PHP code is an associative array and the JSON will be similar. When you are parsing the JSON string in your Obj-C code try assigning it to a NSDictionary, this way you will have access to the associative array.
NSDictionary *jsonArray = [NSJSONSerialization JSONObjectWithData:myData options:NSJSONReadingMutableContainers error:&error];
When using the data in the jsonArray don't iterate it, use the NSDictionary method objectForKey to get get the value you want.
As an example, to get the value of userName, you can do this:
[jsonArray objectForKey: #"userName"] // jsonArray is not actually a array, but a dictionary now
And to change the text of the textview, you can do the following:
textview.text = [NSString stringWithFormat:#"%#", [jsonArray objectForKey: #"userName"]];
Ask if something is unclear!
Cheers!
I'm building an IOS app that queries a database. I keep getting the results out of order, and in some functionality in the app, like comments, it's crucial that I get them in order. It's obvious JSON is returning a dict, but I need the results ordered. Here's the server side code:
function sendResponse($status = 200, $body = '', $content_type = 'text/html') {
$status_header = 'HTTP/1.1 ' . $status . ' ' . getStatusCodeMessage($status);
header($status_header);
header('Content-type: ' . $content_type);
echo $body;
}
$result = array();
$i = 0;
$sqlGetComments = mysqli_query($link, "SELECT * FROM photo_comments WHERE photo_id='$photoID' ORDER BY post_date DESC");
while ($row = mysqli_fetch_array($sqlGetComments)) {
$result[$i] = array(
'photoID' => $row['photo_id'],
'userID' => $row['userID'],
'username' => $row['username'],
'comment' => $row['comment'],
'postedDate' => $row['post_date'],
);
$i++;
} // end while
sendResponse(200, json_encode($result));
I have IOS code that parses that, but out of order from how I need it. So there has to be something I can do server side.
Update, Here is the client side code:
[request setCompletionBlock:^{
NSString *responseString = [request responseString];
[self updateComments:responseString];
}];
- (void)updateComments:(NSString *)update {
NSDictionary *root = [update JSONValue];
NSEnumerator *enumerator = [root keyEnumerator];
id key;
while (key = [enumerator nextObject]) {
NSDictionary *value = [root objectForKey:key];
_photoID = [value objectForKey:#"photoID"];
NSString *photoID = [value objectForKey:#"photoID"];
NSString *userID = [value objectForKey:#"userID"];
NSString *username = [value objectForKey:#"username"];
NSString *comment = [value objectForKey:#"comment"];
NSString *postedDate = [value objectForKey:#"postedDate"];
NSString *cellString = [NSString stringWithFormat:#"%# \n %# \n %#", username, comment, postedDate];
[_queryResultsMessage addObject:cellString];
}
[_tableView reloadData];
}
Here's the print out keeping in mind that "Test" string in the comment field is how the JSON string should print out:
{"1":{"photoID":"1","userID":"17","username":"kismet","comment":"Test 6","postedDate":"7 hrs ago"},"2":{"photoID":"1","userID":"17","username":"kismet","comment":"Test 5","postedDate":"8 hrs ago"},"3":{"photoID":"1","userID":"17","username":"kismet","comment":"Test 4","postedDate":"8 hrs ago"},"4":{"photoID":"1","userID":"17","username":"kismet","comment":"Test 3","postedDate":"8 hrs ago"},"5":{"photoID":"1","userID":"17","username":"kismet","comment":"Test 2","postedDate":"8 hrs ago"},"6":{"photoID":"1","userID":"17","username":"kismet","comment":"Test 1","postedDate":"8 hrs ago"}}
It prints out OK but I'm guessing it's getting jumbled when being assigned to NSDictionary. If nobody has any answers, I'll try to fiddle around with it by assigning it to an NSArray and see if I can parse that somehow.
A little client side IOS hackery was needed
For those who are still interested in the solution:
NSDictionary *userData = [update JSONValue];
NSArray *keys = [[userData allKeys] sortedArrayUsingSelector:#selector(compare:)];
NSMutableArray *array = [NSMutableArray arrayWithCapacity: [keys count]];
int i = 0;
for (NSString *key in keys) {
[array addObject: [userData objectForKey: key]];
i++;
}
for (NSDictionary *myDict in array) {
NSString *comment = [myDict objectForKey:#"comment"];
NSLog(#"USERCOMMENT %#", comment);
}
Returns JSON all in order:
USERCOMMENT Test 6
USERCOMMENT Test 5
USERCOMMENT Test 4
USERCOMMENT Test 3
USERCOMMENT Test 2
USERCOMMENT Test 1
It's worth noting that
- You're requesting the items ordered from MySQL
- Ergo, PHP is generating the JSON in order.
Because of this, I would simply suggest editing the loop in PHP...
while ($row = mysqli_fetch_array($sqlGetComments)) {
$result[$i] = array(
'photoID' => $row['photo_id'],
'userID' => $row['userID'],
'username' => $row['username'],
'comment' => $row['comment'],
'postedDate' => $row['postedDate'],
'orderBy' => $i
);
$i++;
} // end while
... and organising them by "orderBy" in Obj-C.
Note, all I've done is add an extra variable to the JSON items - "orderBy"; as the MySQL results will be in the correct order, and thus are parsed in the correct order, this "orderBy" variable could act like a key.
It's a while since I've worked with the iOS SDK - but I'm pretty sure they will be a method to sort an NSMutableArray; if not - a simple loop could work; requesting each object with the key of x, whilst x < length of NSMutableArray. I'll look up the "correct" way of doing it however, as that will bug me!
I would suggest investigating the real reason behind the results coming in out of order though! That shouldn't be happening! I haven't done similar in iOS but I would assume this isn't the correct behaviour when requesting JSON.
Troubleshooting steps may be checking the returned JSON in-browser or on a desktop environment and ensuring the PHP is returning it correctly, then seeing how it's returned to the app - ensuring all data is present and whether there is a pattern to the distortion of order.
Edit: I've noticed you're saying it's returning an array of dictionaries. My bad.
I did find another question that goes into sorting an array of dictionaries.
In your MySql query, you are sorting on post_date, but then refer to postedDate when adding it to your results array. Do both exist?
If post_date does not in fact exist then your database query is not sorting as you expect...
I hope someone can help me put because I've trying the whole day :( ( newly stuff )
I have a database mySQL, which contains one table "products" ( two rows : "id" and "stock" ).
And I want my ios5 app to send an "id" and receive the "stock" of that product.
In my PHP code:
echo json_encode(array(
'id'=>$id,
'stock'=>$stock, ));
Which I believe sends a JSON to my app, my app receives this JSON in a function called:
- (void)requestFinished:(ASIHTTPRequest *)request
{
NSString *responseStringWEB = [request responseString];
NSLog(#"STRING:: %# \n", responseStringWEB); //3
NSDictionary *responseDict = [responseStringWEB JSONValue];
NSLog(#"DICT: %# \n", responseDict); //3
NSString *id_producto = [responseDict objectForKey:#"id"];
NSString *stock = [responseDict objectForKey:#"stock"];
NSLog(#"ID: %#\n", id_producto); //3
NSLog(#"stock: %#", stock); //3
}
and checking the console I get:
**`STRING`::**
Connection establishedDatabase selected..
***{"id":"3","stock":"46"}***
Connection closedDesconectado
2011-12-26 18:58:57.170 CaeDeCajon[1998:16403] Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be completed. (Cocoa error 3840.)" (JSON text did not start with array or object and option to allow fragments not set.) UserInfo=0x984aeb0 {NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}
2011-12-26 18:58:57.171 CaeDeCajon[1998:16403] **`DICT`**: (null)
2011-12-26 18:58:57.171 CaeDeCajon[1998:16403] **`ID`**: (null)
2011-12-26 18:58:57.171 CaeDeCajon[1998:16403] **`stock`**: (null)
The question is : I do not know what format the JSON is coming ( array, How should I parse the NSstring responseStringWEB to get those two values ( ID and STOCK ). It seems I receive them from the database but I do not reach to extract them.
HELP :) thank you ,
EDITING::
Thanks. It really Helped.
It seemed that there has had something to do with the multiple echos I used in the PHP code. Now I only have one echo, sending data in json format. It works perfectly with my database and my app: I receive the whole table ( "id" and "stock" ) of all items. Thanks.
But I have found another obstacle ( no wonder ), is that I need to change the database once the products have been sold, and as they´re not usually sold 1 by 1 must post arrays into PHP,, my intention is to POST the id and reductor(reductor represent how many products of that "id" were sold ) of the products/items affected ( array_id and array_reductor).
IOS5 CODE:
NSArray *array_id=[[NSArray alloc]initWithObjects:#"0",#"3",#"5", nil];
//with the id products;
NSArray *array_reductor=[[NSArray alloc]initWithObjects:#"10",#"5",#"40", nil];
//with the number of products sold ( so I have to decrease the previous stock number in the database by these to obtain the current stock numbers ).
NSURL *url=[[NSURL alloc]initWithString:#"http://www.haveyourapp.com/promos/"];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setPostValue:array_id forKey:#"id"];
[request setPostValue:array_reductor forKey:#"reductor"];
[request setDelegate:self];
[request startAsynchronous];
MY PHP FILE:
if (isset($_POST['id'])&&isset($_POST['reductor'])) // check if data is coming
{
$id = array(); // I create arrays
$reductor = array();
$id=$_POST['id']; // and store arrays in them ( At least is what I believe )
$reductor=$_POST['reductor'];
$connection = new createConnection(); //i created a new object
$connection->connectToDatabase(); // connected to the database
$connection->selectDatabase();
/////////////////////////////////////////////////////////////////////////////////////////////////////////////// Stock reduction in the items affected////////////////////////////////
$num=mysql_numrows($id);
$i=0;
$stock_anterior=array();
while ($i < $num) {
$query=" SELECT stock FROM productos WHERE id = $id[$i]";
$stock_anterior[$i] = mysql_query($query);
++$i;
}
$l=0;
$num2=mysql_numrows($id);
while ($l < $num2) {
$stock_reductor[$l] = $stock_anterior[$l] - $reductor[$l];
$query = "UPDATE productos SET stock = '$stock_reductor[$l]' WHERE id = $id[$l] ";
mysql_query($query);
++$l;
}
$connection->closeConnection();
But my code is not working, I don not know if the problem is in my app or in the PHP file ( likely ), but how can I receive those two arrays and work with them????
Thanks in advance
I spend a lot of time on stack Overflow: VERY USEFULLLLLLLL!!!!!
json_encode works only with UTF-8 encoded data, so when find a invalid character, it returns NULL for all.
Check your data is encoded in UTF-8.
Also check your file is using UTF-8.
An alternative to json_encode:
// función interna: comprueba si un array es puro o no
// es puro si sus índices son: 0, 1, 2, ..., N
function aputio($a) {
$i=0;
foreach ($a as $n=>$v) {
if (strcmp($n,$i)) return(true);
$i++;
}
return(false);
}
// cambiar quotes, \n y \r para devolver cadenas válidas JSON
function qcl2json($qcl) {
return str_replace('"','\"',str_replace("\n",'\n',str_replace("\r",'\r',$qcl)));
}
// devolver variable en formato json
function ajson($av,$level=0,$utf8=false) {
if (($av===null) && !$level) return("null");
if (!is_array($av)) return (gettype($av)=="integer"?$av:'"'.($utf8?utf8_encode($av):$av).'"');
$isobj=aputio($av);
$i=0;
if (!$level) $e=($isobj?"{":"["); else $e="";
foreach ($av as $n=>$v) {
if ($i) $e.=",";
if ($isobj) $e.=(is_numeric($n) && !is_string($n)?$n:"\"".qcl2json($utf8?utf8_encode($n):$n)."\"").":";
if (!is_array($v)) {
if (is_bool($v)) $e.=($v?"true":"false");
else if ($v==NULL) $e.='""';
else if (is_int($v)||is_double($v)) $e.=$v;
else $e.='"'.qcl2json($utf8?utf8_encode($v):$v).'"';
} else {
$e.=(count($v)
?(aputio($v)
?"{".ajson($v,$level+1)."}"
:"[".ajson($v,$level+1)."]")
:"{}");
}
$i++;
}
if (!$level) $e.=($isobj?"}":"]");
return($e);
}
Avoid using this functions if you can use UTF-8.
your json encoding is correct try add this line to your php script because IOS may be really strict with the response.
add this to your php script:
header('Content-type: application/json');
besides that check you are matching the case of your parameters. I see your php script sends id but looks like your ios script is looking for ID
Check the PHP script output using a tool such as HTTPScoop. I suspect that something is wrong, based on the console output, which contains the lines Connection establishedDatabase selected.. and Connection closedDesconectado...
**`STRING`::**
Connection establishedDatabase selected..
***{"id":"3","stock":"46"}***
Connection closedDesconectado
It looks like you've got some logging from that script that is printed before the JSON starts, which isn't accepted by the JSON parser on the iOS end.
Please help me with my problem in posting a JSON decoded emoji character.
I have a UITextView, this text view may have a emoji character. I am posting the data to a web server with the UITextView.text presented as JSON, the problem is when the text has a an emoji, I am not able to get the data. What I do is:
$postData = file_get_contents("php://input") to get the data.
then I use
$post = json_decode($postData,true);
to decode the data and have a assoc array and insert the data in database.
here is a code snippet when I insert my data into database.
$postData = file_get_contents("php://input");
//$postData = '{"body":"characters here ","subject":"subject here","username":"janus","from_id":"185","to_id":"62"}';
$post = json_decode($postData,true);
$data=array(
'user_id_from'=>mysql_real_escape_string($post['from_id']),
'user_id_to'=>mysql_real_escape_string($post['to_id']),
'subject'=>mysql_real_escape_string($post['subject']),
'message'=>mysql_real_escape_string($post['body']));
$messages_obj->insert($data);
Without an emoji character found, it works fine. no problem. the problem is when an emoji character found, the data in $post (decoded data) is null.
I tried to use dummy data (line 2 in code snippet)
//$postData = '{"body":"characters here ","subject":"subject here","username":"janus","from_id":"185","to_id":"62"}';
and I succesfully inserted the emoji characters in database. I dont know why but It dont work the same when the data is from the device ($postData = file_get_contents("php://input"))
This is how I encode and post my data in client.
NSMutableDictionary *messageDetails = [[NSMutableDictionary alloc] init];
[messageDetails setObject:[loginItems objectForKey:#"user_id"] forKey:#"from_id"];
[messageDetails setObject:recipientID forKey:#"to_id"];
[messageDetails setObject:#"subject here" forKey:#"subject"];
[messageDetails setObject:newMessageField.text forKey:#"body"];
[messageDetails setObject:[loginItems objectForKey:#"username"] forKey:#"username"];
NSString *strPostData = [messageDetails JSONRepresentation];
[messageDetails release];
NSData *postData = [NSData dataWithBytes:[strPostData UTF8String] length:[strPostData length]];
[urlRequest setHTTPMethod:#"POST"];
[urlRequest setHTTPBody:postData];
Once the data is sent to your php script you need to convert it to a multibyte string:
$content = mb_convert_encoding($content, 'UTF-8');
You can use this function:
function cb($content){
if(!mb_check_encoding($content, 'UTF-8')
OR !($content === mb_convert_encoding(mb_convert_encoding($content, 'UTF-32', 'UTF-8' ), 'UTF-8', 'UTF-32'))) {
$content = mb_convert_encoding($content, 'UTF-8');
}
return $content;
}
Edit: The data was probably of type application/x-www-form-urlencoded for us and that function converted it correctly.
emoji characters are most likely transcoded in UNICODE, so it should be sufficient to just send, receive and manage your data in UTF-8.
When receiving with this
$postData = file_get_contents("php://input")
(I suppose that is a real URL), make sure your php script sends an Content-Encoding header (like the following, choose a MIME-type that suits you)
header("Content-Type: text/html; charset=utf-8");
Please follow following steps:
Convert Emoji characters to base64 and send to server.
On server side save base64 in database without decode.
When you want to display Emoji on Application then retrieve same base64 data from server.
Decode retrieve string and display on app.
Your Emoji character will display properly.