i need help with my app login code.
I try to make a Http Request to my local server, a simple login request with mail and password but i've a issue and i don't know how to fix it.
#IBAction func clickConnexionBtn(sender: AnyObject)
{
if(!mailTf.text!.isEmpty && !passwordTf.text!.isEmpty)
{
let mail = mailTf.text!
let password = passwordTf.text!
let param = String(format: "mail=%#&password=%#", arguments: [mail, password]);
let url = NSURL(string: "http://localhost:8888/MoneyManager/login.php")!
RequestObject.sharedInstance.prepareRequest(param, _url: url, _method: "POST")
let task = NSURLSession.sharedSession().dataTaskWithRequest(RequestObject.sharedInstance.request)
{ data, response, error in
if error != nil
{
let alertView = UIAlertController(title: "Error server", message: "Could not connect to server", preferredStyle: UIAlertControllerStyle.Alert)
self.showViewController(alertView, sender: self)
}
else
{
let serverResponse = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("Server response: \(serverResponse)")
do
{
if let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments) as? NSDictionary {
print(json)
}
} catch let error2 as NSError {
print(error2.description)
}
}
}
task.resume()
}
}
So this is the action when i click on the 'connexionButton'.
Unfortunately when i try to Serialize the JSON, i have this error:
Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 0." UserInfo={NSDebugDescription=Invalid value around character 0.}
My PHP code is like:
if($result)
{
$return = array("Success" => 1, "Message" => "Insert user done", "user_id" => $_SESSION['id'], "api_key" => $_SESSION['api_key']);
echo json_encode($return);
}
Here is the code of my 'print("Server ....")'
Server response: Optional(Connexion successfully {"Success":1,"Message":"Insert user done","user_id":"9","api_key":"aa3b0c16fc63efe207be1a7471ac234a"})
Its all the data that i want to get and turn into JSON object
I look many subject but no one of them could help me cause most of the people use Alamofire to perform request.
So please if you have an idea, i listening
Thanks all.
Related
I am trying to retrieve data from my own API, if i try to connect to my API using chrome browser, it gives JSON data back like this
{"id":"52","username":"aasad23","fullname":"aasad
laksana","email":"aasad#gmail.com","avatar":"/Applications/XAMPP/xamppfiles/htdocs/Twitter/Avatar/52/avatar.jpg"}
but, when I tried to access the API through my iOS app, it gives an error while doing JSON serialization, it give an error:
the data couldn’t be read because it isn’t in the correct format
what does it mean the correct format?
I have checked that the code error in this line
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
Thats why the catch error is activated and give that error message.
here is the full code of this task
URLSession.shared.dataTask(with: request) { data, response, error in
DispatchQueue.main.async(execute: {
if error == nil {
do {
// json containes $returnArray from php
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
// declare new parseJSON to store json
guard let parsedJSON = json else {
print("Error while parsing")
return
}
print(parsedJSON)
// get id from $returnArray["id"] in PHP - parseJSON["id"]
let id = parsedJSON["id"]
// successfully uploaded
if id != nil {
// save user information yang berasal dari server
UserDefaults.standard.set(parsedJSON, forKey: "parsedJSON")
} else {
// get main queue to communicate back to user
DispatchQueue.main.async(execute: {
let message = parsedJSON["message"] as! String
self.showAlert(alertTitle: "opppps", alertMessage: message, actionTitle: "OK")
})
}
// JSON serialization error
} catch {
// get main queue to communicate back to user
DispatchQueue.main.async(execute: {
let message = error.localizedDescription
self.showAlert(alertTitle: "Sorry", alertMessage: message, actionTitle: "OK")
})
}
// error when connecting to server
} else {
// get main queue to communicate back to user
DispatchQueue.main.async(execute: {
let message = error!.localizedDescription
self.showAlert(alertTitle: "oppps", alertMessage: message, actionTitle: "OK")
})
}
})
}.resume()
}
try
let json = try JSONSerialization.jsonObject(with: data, options: []) as! [String: AnyObject]
rather than
try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
I have a function in Swift 3 to POST data to a PHP server. The PHP server send a JSon answer to iOS and I have an error.
This is my function :
func sendRequestPost(urlString: String, dataToPost: String, completion: #escaping (_ dictionary: NSDictionary?, _ error: Error?) -> Void) {
DispatchQueue.global(qos: .background).async {
var request = URLRequest(url: URL(string: urlString)!)
let postString = dataToPost
request.httpMethod = "POST"
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else { // Check for fundamental networking error
print("error=\(error)")
completion(nil, error)
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 { // Check for http(s) errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(response)")
// make error here and then
completion(nil, error)
return
}
let responseString = String(data: data, encoding: .utf8)
print("responseString : \(responseString)!")
DispatchQueue.main.async {
print("DispatchQueue.main.async")
do {
print("enter do")
let jsonDictionary:NSDictionary = try JSONSerialization.jsonObject(with: data, options: []) as! [String: Any] as NSDictionary
print("jsonDictionary")
print(jsonDictionary)
completion(jsonDictionary, nil)
} catch {
print("CATCH ERROR !")
completion(nil, error)
}
}
}
task.resume()
}
}
For example I call my function like that :
let url = "https://mywebsite.com/signup/ios/signup.php"
let postData = "username=\(txtUsername.text!)&password=\(txtPassword.text!)&confirmPassword=\(txtConfirmPassword.text!)&email=\(txtEmail.text!)&firstname=\(txtFirstname.text!)&lastname=\(txtLastname.text!)"
sendRequestPost(urlString: url, dataToPost: postData) {
dictionary, error in
print("---directory---")
print(dictionary)
print("---error---")
print(error)
print("==========")
This is what I see in the console :
responseString : "{\"exception\":false,\"success\":false,\"status\":-9,\"message\":\"This username already exist !\",\"confirmMessage\":\"null\",\"html\":\"null\",\"data\":\"boblongueuil\"}"!
DispatchQueue.main.async
---ENTER DO :
CATCH ERROR !
---directory---
nil
---error---
Optional(Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.})
So how can I return the JSon string after call this function to see a registration is OK or registration have a problem (in this case the username already exist in database). I change answer from my PHP server to an array.
So basically I have a login script on my server that returns a result depending on if the user credentials are correct or wrong, and I have an iOS App that sends data to that login script to return the correct or wrong result.
Here is the relevant part of my login page that shows the return code ($userDetails being the TRUE or FALSE check of correct or wrong credentials) :
$userDetails = $dao->getUserDetailsWithHashedPassword($email,$password);
if($userDetails===TRUE) {
$returnValue["status"] = "Success";
$returnValue["message"] = "User logged in !";
echo json_encode($returnValue);
} else {
$returnValue["status"] = "error";
$returnValue["message"] = "User not found";
echo json_encode($returnValue);
}
If anyone needs to see what that getUserDetailsWithHashedPassword() does, click here
Using Postman to test the HTTP POST, everything works fine, I get the correct result when posting email#email.com & testpassword in the body and using the correct Content-Type (application/x-www-form-urlencoded) :
{"status":"error","message":"User not found"}
Now my iOS is supposed to interpret this with this code :
#IBAction func loginButtonPressed(_ sender: AnyObject) {
let userEmail = emailLoginField.text
let userPassword = passwordLoginField.text
// Check for empty fields
if((userEmail?.isEmpty)! || (userPassword?.isEmpty)!) {
// Display alert message
displayMyAlertMessage(userMessage: "All fields are required");
return ;
}
// Send user data to server side
let myUrl = URL(string: "https://support.vincentsolutions.ca/userLogin.php");
var request = URLRequest(url:myUrl!);
request.httpMethod = "POST";
request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
let postString = "email=\(userEmail!)&password=\(userPassword!)";
request.httpBody = postString.data(using: String.Encoding.utf8);
URLSession.shared.dataTask(with: request, completionHandler: { (data:Data?, response:URLResponse?, error:Error?) -> Void in
if error != nil {
print ("error=\(error)")
return
}
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
if let parseJSON = json {
var resultValue = parseJSON["status"] as? String
print("result: \(resultValue)")
var isUserLoggedIn:Bool = false;
if(resultValue=="Success") {
// Login is successful
UserDefaults.standard.set(true, forKey: "isUserLoggedIn");
UserDefaults.standard.synchronize();
self.performSegue(withIdentifier: "loginSuccesful", sender: self)
}
var messageToDisplay:String = parseJSON["message"] as! String!;
if(!isUserLoggedIn) {
messageToDisplay = parseJSON["message"] as! String!;
}
DispatchQueue.main.async(execute: {
// Display alert message with confirmation.
var myAlert = UIAlertController(title: "Alert", message: messageToDisplay, preferredStyle: UIAlertControllerStyle.alert);
let okAction = UIAlertAction(title: "Ok", style: UIAlertActionStyle.default){ action in
self.dismiss(animated: true, completion: nil);
}
myAlert.addAction(okAction);
self.present(myAlert, animated: true, completion: nil);
});
}
} catch let error as NSError {
print("An error occured: \(error)")
}
}).resume()
Now I'm getting this error when I run the code from the iOS App :
An error occured: Error Domain=NSCocoaErrorDomain Code=3840 "JSON text
did not start with array or object and option to allow fragments not
set."
Does anyone see what could be wrong here ? I've tried looking for that error here on SO and on the internet but couldn't find anything related to my situation.
That is because the response you are receiving from the URL probably not in correct JSON format. I will suggest you to do 2 things -
Try to NSLog the data and response
Try this
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.AllowFragments) as! NSDictionary
I am trying to get login/register on my iOS app to work. I am using mySQL and PHP besides Swift 2.0. For some reason when I try to send my HTTP POST to the PHP-scripts I keep geting the error: "The data couldn’t be read because it isn’t in the correct format."
I am using MAMP for the mySQL server.
let request = NSMutableURLRequest(URL: NSURL.fileURLWithPath("/Users/robin/Programming/xcode/Projects/Quix/php_scripts/userRegister.php"))
request.HTTPMethod = "POST"
let postString = "email=\(userEmail)&password=\(userPassword)"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
print(postString)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, response, error in
if (error != nil) {
print("error=\(error)")
}
do {
if let parseJSON = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? NSDictionary {
let resultValue = parseJSON["status"] as? String
print("result: \(resultValue)")
var isUserRegistered:Bool = false
if (resultValue == "Success") { isUserRegistered = true }
var messageToDisplay:String = parseJSON["message"] as! String!
if (!isUserRegistered) {
messageToDisplay = parseJSON["message"] as! String!
}
dispatch_async(dispatch_get_main_queue(), {
let myAlert = UIAlertController(title: "Alert", message: messageToDisplay, preferredStyle: UIAlertControllerStyle.Alert)
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default) { action in
self.dismissViewControllerAnimated(true, completion: nil)
}
myAlert.addAction(okAction)
self.presentViewController(myAlert, animated: true, completion: nil)
});
}
} catch let error as NSError {
print(error.localizedDescription)
}
}
task.resume()
In my database I have the table 'users' and the parameters id (auto_increment), email and password. I am using port: 3306 for mySQL aswell. The standard IP for MAMP is 127.0.0.1, should I use the IP: 127.0.0.1 or localhost:3306 aswell?
You are using a file URL with a NSURLSession request. You should use a https:// or http:// request. NSURLSession is for making network requests, not local file system requests. So, if you're running this on the iOS simulator, you can use http://localhost/.... But when you run it on an device, you'll have to supply it a host name that will resolve to your machine running MAMP.
By the way, if you use http, you may need to add a NSExceptionDomains entry as outlined in https://stackoverflow.com/a/31254874/1271826.
I have a very similar problem like in Why the http post request body always wrapped by Optional text in the Swift app
but I can´t apply the solution from this thread to my code, because I don´t have a request.setValue.
Does anyone know what I need to do to get rid of the Optional?
My Code:
#IBAction func LoginButtonTapped(sender: UIButton) {
let username = UsernameTextField.text
let password = PasswordTextField.text
if(username!.isEmpty || password!.isEmpty) {return; }
let request = NSMutableURLRequest (URL: NSURL(string: "http://myip/loginregister.php")!)
request.HTTPMethod = "POST"
let postString = "username=\(username)&password=\(password)"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, response, error in
guard error == nil && data != nil else {
// check for fundamental networking error
print("error=\(error)")
return
}
let data = postString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
do {
if let json = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? NSDictionary {
let success = json["success"] as? Int // Okay, the `json` is here, let's get the value for 'success' out of it
print("Success: \(success)")
} else {
let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding) // No error thrown, but not NSDictionary
print("Error could not parse JSON: \(jsonStr)")
}
} catch let parseError {
print(parseError) // Log the error thrown by `JSONObjectWithData`
let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding)
print("Error could not parse JSON: '\(jsonStr)'")
}
}
task.resume()
You must unwrapping the value when get text from UITextField first, because the text property of UITextField allow nil
let username = UsernameTextField.text!
let password = PasswordTextField.text!
Explain more
When you unwrap the text of the UITextField, the username and password will be not nil variable.
The code compare empty should be:
if(username.isEmpty || password.isEmpty) {return }
If you does not unwrap, when you use this "\(username)", your are try to convert a nilable object to string, so the string result will be appended with a "Optional" text.
To Solve problem with Content-Type for request
Paste this line to your code. I don't believe that you do not have setValue method.
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField:"Content-Type")