Authenticating Iphone Login with PHP/MySQL and HTTP Responses - objective-c

Im trying to create a iPhone Objective C login page using PHP/MySQL to authenticate. Im trying to use HTTP responses as a way of authenticating. Right now it always fails to login , regardless of what you enter.
`- (IBAction) login: (id) sender
{
// this part isnt really implemented yet!
NSString *post =[NSString stringWithFormat:#"username=%#&password=%#",usernameField.text, passwordField.text];
NSURL *url = [NSURL URLWithString:#"MY URL HERE.php"];
NSURLRequest *request = [NSURLRequest requestWithURL: url];
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)request;
responseStatusCode = [httpResponse statusCode];
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:response error:nil];
if ([responseStatusCode statusCode] == 200) {
//do something
UIAlertView *alertsuccess = [[UIAlertView alloc] initWithTitle:#"success" message:#"Your have logged in" delegate:self cancelButtonTitle:#"No" otherButtonTitles:#"Yes", nil];
[alertsuccess show];
[alertsuccess release];
}
else {
NSLog(#"Login failed.");
//do something else
UIAlertView *alertfail = [[UIAlertView alloc] initWithTitle:#"fail" message:#"login fail" delegate:self cancelButtonTitle:#"No" otherButtonTitles:#"Yes", nil];
[alertfail show];
[alertfail release];
}
`
and the PHP looks like
<?
session_start();
require("iphoneconnection.php");
$u = $_POST['username'];
$pw = $_POST['password'];
$check = "SELECT username, password FROM iphoneusers WHERE username='$u' AND password= '$pw'";
$login = mysql_query($check, $connect) or die(mysql_error());
// check user level and store in $row
if (mysql_num_rows($login) == 1) {
$row = mysql_fetch_assoc($login);
//$_SESSION['level'] = $row['level'];
$_SESSION['username'] = $u;
echo 'login success';
header("HTTP/1.1 200 OK");
//header("Location: index.php");
} else {
//header("Location: login.php");
//echo '403 Forbidden';
header("403 Forbidden");
}
mysql_close($connect);
?>
Anyone got any pointers? Even if its just to tell me if Im formatting my repsonses correctly in the PHP.
Thanks in advance.

Thanks for the response. I got it to work using:
- (IBAction) login: (id) sender
{
NSString *post =[NSString stringWithFormat:#"username=%#&password=%#",usernameField.text, passwordField.text];
NSString *hostStr = #"MY URL.php?";
hostStr = [hostStr stringByAppendingString:post];
NSData *dataURL = [NSData dataWithContentsOfURL: [ NSURL URLWithString: hostStr ]];
NSString *serverOutput = [[NSString alloc] initWithData:dataURL encoding: NSASCIIStringEncoding];
if([serverOutput isEqualToString:#"Yes"]){
UIAlertView *alertsuccess = [[UIAlertView alloc] initWithTitle:#"success" message:#"You are authorized"
delegate:self cancelButtonTitle:#"No" otherButtonTitles:#"Yes", nil];
[alertsuccess show];
[alertsuccess release];
} else {
UIAlertView *alertsuccess = [[UIAlertView alloc] initWithTitle:#"Fail" message:#"Invalid Access"
delegate:self cancelButtonTitle:#"No" otherButtonTitles:#"Yes", nil];
[alertsuccess show];
[alertsuccess release];
}
loginIndicator.hidden = FALSE;
[loginIndicator startAnimating];
loginButton.enabled = FALSE;
}

According to the sample you've given, I don't see that you're actually sending the username & password with the request. You're creating a string "post", but never including it in the request.
Also, this cast:
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)request;
doesn't look right. Why are you typecasting the request object to a response?

Related

How to upload UIImage from iOS to Azure storage

I try to upload an image to Azure storage through MVC 4 web API. But the server side always return:
"Invalid length for a Base-64 char array or string."
Below is Objective-C code:
- (IBAction)btnUploadReceipt:(id)sender {
UIImage *img = self.imgReceipt.image;
NSData *dataObj = UIImagePNGRepresentation(img);
NSString *fff = [dataObj base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
//NSString *ddd = [self base64EncodeString:imgData];
//NSString *ddd = [dataObj base64EncodedString];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"%#/api/upload/UploadAzure",baseUrl]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"Post"];
NSString *jsonData = [NSString stringWithFormat:#"FileName=%#&FileData=%#&FolderName=%#&UserName=%#&Point=%#&DateTime=%#&MerchantName=%#&OutletID=%#",fileName,fff,imgFolder,userName,#"3",dateTime,_mName,_mOutletID];
[request setHTTPBody:[jsonData dataUsingEncoding:NSUTF8StringEncoding]];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response,
NSData *data, NSError *connectionError)
{
if (data.length > 0 && connectionError == nil)
{
NSString * json =[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"%#",json);
if ([json isEqualToString:#"\"True\""]) {
NSLog(#"%#",#"Success Add Photo");
//[self dismissViewControllerAnimated:YES completion:nil];
//[[self navigationController]popViewControllerAnimated:YES];
}
else
{
UIAlertView *messageAlert = [[UIAlertView alloc]initWithTitle:#"Connection Error" message:#"Please Check Internet Setting" delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[messageAlert show];
}
}
else
{
UIAlertView *messageAlert = [[UIAlertView alloc]initWithTitle:#"Connection Error" message:#"Please Check Internet Setting" delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[messageAlert show];
}
}];
}
- (NSString *)base64String2 {
UIImage *img = self.imgReceipt.image;
NSData * data = [UIImagePNGRepresentation(img) base64EncodedDataWithOptions:NSDataBase64Encoding64CharacterLineLength];
return [NSString stringWithUTF8String:[data bytes]];
}
Anyone face this kind of problem?
Have you tried using the Azure Storage iOS Library? The Getting Started documentation should be able to help with your scenario.

Parsing Json to handle and direct a user to view controller. Objective C

I have a Login screen and I POST username and password to a login page.
The webservice gives me 2 responses if the Login user details are correct I get a response of back from the request.
{"value":1}
and if the user details are wrong I get back from request.
{"value":0}
I have been able to parse that JSON Result to give me a log output of
value: 1 or value:0
I am battling to handle the parsed json e.g
//parse out the json data
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:urlData //1
options:kNilOptions
error:&error];
NSArray* defineJsonData = [json objectForKey:#"value"]; //2
NSLog(#"value: %#", defineJsonData); //3
if ([[json objectForKey:#"value"] isEqualToNumber:[NSNumber numberWithInt:1]])
{
HUD.customView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"37x-Checkmark.png"]];
HUD.mode = MBProgressHUDModeCustomView;
[HUD hide:YES afterDelay:0];
[self performSegueWithIdentifier: #"introScreenView" sender:self];
}
else {
HUD.customView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"37x-Checkmark.png"]];
HUD.mode = MBProgressHUDModeCustomView;
[HUD hide:YES afterDelay:0];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Wrong Credentials" message:#"Please try to login again" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
}
Here is the rest of my code.
- (void)myTask {
if ([userNameTextField.text isEqualToString:#""] || [passwordTextField.text isEqualToString:#""]) {
HUD.customView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"37x-Checkmark.png"]];
HUD.mode = MBProgressHUDModeCustomView;
[HUD hide:YES afterDelay:0];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Feilds Missing" message:#"Please Fill all the field" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
return;
}
NSString *data = [NSString stringWithFormat:#"UserName=%#&Password=%#",userNameTextField.text, passwordTextField.text];
NSData *postData = [data dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
// preaparing URL request to send data.
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init] ;
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:request delegate:self];
NSString *url = [NSString stringWithFormat:#"http://www.ddproam.co.za/Central/Account/LogOnIOS?"];
[request setURL:[NSURL URLWithString:url]];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody:postData];
[request setTimeoutInterval:7.0];
NSURLResponse *response;
NSError *error;
NSData *urlData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSString *str=[[NSString alloc]initWithData:urlData encoding:NSUTF8StringEncoding];
NSLog(#"Login response:%#",str);
NSHTTPCookie *cookie;
NSLog(#"name: '%#'\n", [cookie name]);
for (NSHTTPCookie *cookie in [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies])
{
NSLog(#"name: '%#'\n", [cookie name]);
NSLog(#"value: '%#'\n", [cookie value]);
NSLog(#"domain: '%#'\n", [cookie domain]);
NSLog(#"path: '%#'\n", [cookie path]);
}
//parse out the json data
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:urlData //1
options:kNilOptions
error:&error];
NSArray* defineJsonData = [json objectForKey:#"value"]; //2
NSLog(#"value: %#", defineJsonData); //3
if ([defineJsonData isEqual:0])
{
HUD.customView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"37x-Checkmark.png"]];
HUD.mode = MBProgressHUDModeCustomView;
[HUD hide:YES afterDelay:0];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Wrong Credentials" message:#"Please try to login again" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
}
else {
HUD.customView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"37x-Checkmark.png"]];
HUD.mode = MBProgressHUDModeCustomView;
[HUD hide:YES afterDelay:0];
[self performSegueWithIdentifier: #"introScreenView" sender:self];
}
if (theConnection) {
}
}
If response from the server is really just {"value":1}, then you correctly parse JSON to dictionary using NSJSONSerialization.
However under value key, there is an instance of NSNumber, not NSArray.
Your code to retrieve value and check it should look like this:
NSNumber *defineJsonData = [json objectForKey:#"value"];
NSLog(#"value: %#", defineJsonData);
if ([defineJsonData integerValue] == 0) {
NSLog(#"Wrong credentials");
}
else {
NSLog(#"Welcome :-)");
}

Why does isEqualToString not work for NSString?

I am trying to code the login process for an iPhone app in XCode. The problem is with the NSString serverOutput below. When I print it using printf(serverOutput.UTF8String); it prints 'Yes' to the console. However when I compare serverOutput to "Yes" it doesn't work. Any help would be appreciated. Here's my code:
- (IBAction) loginButton: (id) sender
{
// TODO: spawn a login thread
indicator.hidden = FALSE;
[indicator startAnimating];
NSString *post =[NSString stringWithFormat:#"username=%#&password=%#",userName.text, password.text];
NSString *hostStr = #"http://10.243.1.184/connectDB.php?";
hostStr = [hostStr stringByAppendingString:post];
NSData *dataURL = [NSData dataWithContentsOfURL: [ NSURL URLWithString: hostStr ]];
NSString *serverOutput = [[NSString alloc] initWithData:dataURL encoding: NSASCIIStringEncoding];
printf(serverOutput.UTF8String);
if([serverOutput isEqualToString:#"Yes"]){
UIAlertView *alertsuccess = [[UIAlertView alloc] initWithTitle:#"Congrats" message:#"You are authorized"
delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alertsuccess show];
[alertsuccess release];
}
else {
UIAlertView *alertsuccess = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Username or Password Incorrect"
delegate:self cancelButtonTitle:#"OK"otherButtonTitles:nil, nil];
[alertsuccess show];
[alertsuccess release];
//[self.navigationController pushViewController:DashboardViewController animated:YES];
loginbutton.enabled = TRUE;
}
loginbutton.enabled = FALSE;
}
Based on helping others with similar situations I would say the problem is that the response from the server isn't just the string "Yes". Most likely there is some whitespace before and/or after the text. Perhaps a stray newline or two.
Try this:
NSString *serverOutput = [[NSString alloc] initWithData:dataURL encoding: NSASCIIStringEncoding];
NSLog(#"Result = '%#'", serverOutput); // look for space between quotes
serverOutput = [serverOutput stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];

Pull more than 1 echo from PHP

OK, I have a login screen that sends username and password to a PHP page. The PHP page echo's Yes or No based on the login status, but I would like it to echo the user id from the database for further use. Do I have to use JSON for this? I dont know how to retrieve more than one echo's. Currently the code is:
- (IBAction) login: (id) sender
{
NSString *post =[NSString stringWithFormat:#"username=%#&password=%#",usernameField.text, passwordField.text];
NSString *hostStr = #"https://www.mysite.com/login.php?";
hostStr = [hostStr stringByAppendingString:post];
NSData *dataURL = [NSData dataWithContentsOfURL: [ NSURL URLWithString: hostStr ]];
NSString *serverOutput = [[NSString alloc] initWithData:dataURL encoding: NSASCIIStringEncoding];
if([serverOutput isEqualToString:#"Yes"]){
UIAlertView *alertsuccess = [[UIAlertView alloc] initWithTitle:#"Business Manager" message:#"Login Successful"
delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alertsuccess show];
[alertsuccess release];
RootViewController *viewMenu = [[RootViewController alloc]
initWithNibName:#"RootViewController" bundle:[NSBundle mainBundle]];
self.rootViewController = viewMenu;
[viewMenu release];
[self.navigationController pushViewController:self.rootViewController animated:YES];
} else {
UIAlertView *alertsuccess = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Username or Password Incorrect"
delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alertsuccess show];
[alertsuccess release];
}
}
Now I just want to pull one more echo called "ID". Forming JSON for this seems arbitrary.
Technically you can use whatever response format you want -- though it's best to stick with something standard as you'll be able to find libraries made for you already. A REST service with a JSON response is a pretty easy way to facilitate communication between a server and client, so it would probably be a good idea to start there.

Method gets called two times

I am doing a NSURLConnection that downloads a file only if there is a new one (checked with the last-modified date). But to accomplish this I am using two methods with two different NSURLRequests and NSURLConnection. Well, they do the same.
- (IBAction)uppdatera:(id)sender
{
checkHeaders = YES;
NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.forellgatan.se/site/ftp_files/Kapareskolan.zip"] cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:10.0];
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection)
{
self.receivedData = [[NSMutableData data] retain];
}
else
{
UIAlertView *connectFailMessage = [[UIAlertView alloc] initWithTitle:#"Ingen internetanslutning! 1" message:#"Anslut dig till internet för att ladda ner!" delegate: self cancelButtonTitle:#"Ok" otherButtonTitles: nil];
[connectFailMessage show];
[connectFailMessage release];
}
}
- (void)downloadNewFile
{
NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.forellgatan.se/site/ftp_files/Kapareskolan.zip"] cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:10.0];
NSURLConnection *theConnection2 = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection2)
{
self.receivedData = [[NSMutableData data] retain];
}
else
{
UIAlertView *connectFailMessage = [[UIAlertView alloc] initWithTitle:#"Ingen internetanslutning! 2" message:#"Anslut dig till internet för att ladda ner!" delegate: self cancelButtonTitle:#"Ok" otherButtonTitles: nil];
[connectFailMessage show];
[connectFailMessage release];
}
checkHeaders = NO;
self.progressView.hidden = NO;
}
It goes through the didReceiveResponse method:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
if (checkHeaders == YES)
{
NSHTTPURLResponse *test = (NSHTTPURLResponse *)response;
if ([test respondsToSelector:#selector(allHeaderFields)])
{
NSDictionary *metaData = [test allHeaderFields];
NSString *lastModifiedString = [metaData objectForKey:#"Last-Modified"];
NSString *savedString = [[NSUserDefaults standardUserDefaults] stringForKey:#"LastModified"];
if (![lastModifiedString isEqualToString:savedString])
{
[self downloadNewFile];
}
else if ([lastModifiedString isEqualToString:savedString])
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Ingen uppdatering tillgänglig" message:#"Det finns ingen uppdatering att hämta just nu." delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alert show];
[alert release];
}
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
[standardUserDefaults setObject:lastModifiedString forKey:#"LastModified"];
[standardUserDefaults synchronize];
}
}
[self.receivedData setLength:0];
self.fileSize = [[NSNumber numberWithLong: [response expectedContentLength]] retain];
}
Last the connectionDidFinishLaunching method:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
if (checkHeaders == NO)
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
[self.receivedData writeToFile:[basePath stringByAppendingPathComponent:#"Kapareskolan.zip"] atomically:YES];
[self unzipDownloadedFile];
self.progressView.hidden = YES;
NSLog(#"Finished...");
}
[connection cancel];
}
I know the didFinishLaunching method gets called twice, but I want to know how I could get so the method doesn't get called twice if there is an update?
I know it's a lot asked and much code here but just give me a hint and I'll be very thankful.
If you're done with the first connection object in the didReceiveResponse method you should cancel it then. Otherwise it's going to make it to the connectionDidFinishLoading method.
I think this is what you want:
if (![lastModifiedString isEqualToString:savedString])
{
[connection cancel];
[self downloadNewFile];
}
Also It looks like you're setting checkHeaders to NO after you start the second request which could cause a race condition.
According to the programming guide, a connection "can be canceled any time before the delegate receives a connectionDidFinishLoading: or connection:didFailWithError: message by sending the connection a cancel message".
so why not try moving
[connection cancel];
from the connectionDidFinishLoading method to just after your if-else block in the didReceiveResponse delegate method? You want to cancel the "checkHeaders==YES" connection in either case; either you're about to kick off a new connection, or you already know all you need to know about the current connection.
UPDATED as requested:
if (![lastModifiedString isEqualToString:savedString]) {
[self downloadNewFile];
} else { // you've already implicitly checked for equality above
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Ingen uppdatering tillgänglig" message:#"Det finns ingen uppdatering att hämta just nu." delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alert show];
[alert release];
}
// you've used the connection for everything that you need, so cancel it in either case
[connection cancel];
as downloadNewFile kicks off its NSURLConnection asynchronously, this should be okay in the event that the two strings are equal. Slightly safer would be to move the cancel method call to just prior to the if-else check.