I am trying to create simple login and signup in swift with php mysql in backend. I was following "https://github.com/EMacco/ios-tutorials/tree/yummie-network-connection/Yummie" this project
I get the following error
The response is: {"data":[{"response":"Success","username":"Mohammad Tariq Shamim"}]} Error Response could not be decoded
I am getting response from the server but JSON is not getting decoded. Following is my code
enum Route {
static let baseurl = "http://arabscholar.net/android/"
case login
var description: String {
switch self {
case .login: return "login.php"
}
}
}
struct User: Decodable{ let username: String? let response: String? }
struct ApiResponse<T: Decodable>: Decodable {
let status: Int
let data: T?
let error: String?
}
AppError Swift file
enum AppError: LocalizedError {
case errorDecoding
case unknownError
case invalidUrl
case serverError(String)
var errorDescription: String? {
switch self {
case .errorDecoding:
return "Response could not be decoded"
case .unknownError:
return "Unknown error"
case .invalidUrl:
return "Url invalid"
case .serverError(let error):
return error
}
}
}
Main networking struct file
struct NetworkService {
static let shared = NetworkService()
private init() {}
func signin(username: String, password: String, completion: #escaping(Result<User, Error>) -> Void) {
let params = ["login": "user", "email": username, "password": password]
request(route: .login, method: .post, parameters: params, completion: completion)
}
private func request<T: Decodable>(route: Route, method: Method, parameters: [String: Any]? = nil, completion: #escaping(Result<T, Error>) -> Void) {
guard let request = createRequest(route: route, method: method, parameters: parameters) else {
completion(.failure(AppError.unknownError))
return
}
URLSession.shared.dataTask(with: request) { data, response, error in
var result: Result<Data, Error>?
if let data = data {
result = .success(data)
let responseString = String(data: data, encoding: .utf8) ?? "Could not stringify our data"
print("The response is: (responseString)")
} else if let error = error {
result = .failure(error)
print("The error is " + error.localizedDescription)
}
DispatchQueue.main.async {
self.handleResponse(result: result, completion: completion)
}
}.resume()
}
private func handleResponse<T: Decodable>(result: Result<Data, Error>?, completion: (Result<T, Error>) -> Void) {
guard let result = result else {
completion(.failure(AppError.unknownError))
return
}
switch result {
case .success(let data):
let decoder = JSONDecoder()
guard let response = try? decoder.decode(ApiResponse.self, from: data) else {
completion(.failure(AppError.errorDecoding))
return
}
if let error = response.error {
completion(.failure(AppError.serverError(error)))
return
}
if let decodedData = response.data {
completion(.success(decodedData))
} else {
completion(.failure(AppError.unknownError))
}
case .failure(let error):
completion(.failure(error))
}
}
private func createRequest(route: Route, method: Method, parameters: [String: Any]? = nil) -> URLRequest? {
let urlString = Route.baseurl + route.description
guard let url = urlString.asUrl else {return nil}
var urlRequest = URLRequest(url: url)
urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
urlRequest.httpMethod = method.rawValue
if let params = parameters {
switch method {
case .get:
var urlComponent = URLComponents(string: urlString)
urlComponent?.queryItems = params.map { URLQueryItem(name: $0, value: "($1)")}
urlRequest.url = urlComponent?.url
case .post:
let bodyData = try?JSONSerialization.data(withJSONObject: params, options: [])
urlRequest.httpBody = bodyData
}
}
return urlRequest
}
}
My PHP code
$postdata = json_decode( file_get_contents( "php://input" ), TRUE );
//$id = $postdata[ "email" ];
//$name = $postdata[ "password" ];
$result[ 'response' ] = "Success";
$result[ 'username' ] = "Mohammad Tariq Shamim";
// Store values in an array
$returnValue = array( $result );
$array['data'] = $returnValue;
// Send back request in JSON format
echo json_encode( $array );
//echo json_encode( array( 'response' => 'No data found for ' . $_POST[ 'email' ] ) );
Related
i am new to swift programming and i am working on a login and registry xcode example i found online.
it said, it works with all sort of backends. so i changed it to work with my login.php file. but i come only so far ...
func handleResponse(for request: URLRequest,
completion: #escaping (Result<[User], Error>) -> Void) {
let session = URLSession.shared
let task = session.dataTask(with: request) { (data, response, error) in
DispatchQueue.main.async {
guard let unwrappedResponse = response as? HTTPURLResponse else {
completion(.failure(NetworkingError.badResponse))
return
}
print(unwrappedResponse.statusCode)
switch unwrappedResponse.statusCode {
case 200 ..< 300:
print("success")
default:
print("failure")
}
if let unwrappedError = error {
completion(.failure(unwrappedError))
return
}
if let unwrappedData = data {
do {
let json = try JSONSerialization.jsonObject(with: unwrappedData, options: [])
print(json)
if let users = try? JSONDecoder().decode([User].self, from: unwrappedData) {
completion(.success(users))
} else {
let errorResponse = try JSONDecoder().decode(ErrorResponse.self, from: unwrappedData)
completion(.failure(errorResponse))
}
} catch {
completion(.failure(error))
}
}
}
}
task.resume()
}
i have this request function.
func request(endpoint: String,
loginObject: Login,
completion: #escaping (Result<User, Error>) -> Void) {
guard let url = URL(string: baseUrl + endpoint) else {
completion(.failure(NetworkingError.badUrl))
return
}
var request = URLRequest(url: url)
do {
let loginData = try JSONEncoder().encode(loginObject)
request.httpBody = loginData
print(loginObject)
} catch {
completion(.failure(NetworkingError.badEncoding))
}
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
handleResponse(for: request, completion: completion)
}
and then got this error
typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Dictionary<String, Any> but found an array instead.", underlyingError: nil))
so i was searching online, mostly in here, what went wrong. i tested the code and found out where the error comes from and i found out, i should change my code to...
if let unwrappedData = data {
do {
let json = try JSONSerialization.jsonObject(with: unwrappedData, options: [])
print(json)
if let users = try? JSONDecoder().decode([User].self, from: unwrappedData) {
completion(.success(users))
} else {
let errorResponse = try JSONDecoder().decode(ErrorResponse.self, from: unwrappedData)
completion(.failure(errorResponse))
}
} catch {
completion(.failure(error))
}
}
so i thought that is the proper fix for my problem. but unfortunately i got another error after this change...
Member 'success' in 'Result<User, Error>' produces result of type 'Result<Success, Failure>', but context expects 'Result<User, Error>'
and i cant even build and run the code anymore. can anybody help me?
if necessary i change my login.php from an array to dictionary.
is this the completion closure?
enum MyResult<T, E: Error> {
case success(T)
case failure(E) }
func handleResponse(for request: URLRequest,
completion: #escaping (Result<User, Error>) -> Void) {
... }
enum NetworkingError: Error {
case badUrl
case badResponse
case badEncoding }
ErrorResponse.swift
import Foundation
struct ErrorResponse: Decodable, LocalizedError {
let reason: String
var errorDescription: String? { return reason } }
Login.swift
import Foundation
struct Login: Encodable {
let username: String
let password: String }
User.swift
import Foundation
struct User: Decodable {
let user_id: Int
let username: String
let password: String
let firstname: String
let surname: String
let activated: Int
let reg_time: String
}
print(json) ...
({
activated = 1;
firstname = Thomas;
password = Maggie;
"reg_time" = "0000-00-00 00:00:00";
surname = Ghost;
"user_id" = 2;
username = "testuser";
})
now i am almost back in business. i found out that my user_id in mysql is int(3) but swift 5 doesnt take it as it should. when i take out let user_id: int, i finally get rid off the last error message. but now i can log in with any click of a button and any user and password, whether its right or wrong.
I believe the issue lies in the signature of your completion closure. Looks like you are using Swift.Result but varying the generic Success and Failure types. Can you post the enclosing function where you are passing completion closure?
OK, try changing handleResponse to:
unc handleResponse(for request: URLRequest,
completion: #escaping (Result<[User], Error>) -> Void) {
... }
And ensure that ErrorResponse implements Error
I'm not sure what I'm doing wrong, if anyone understands I would appreciate your help.
I might be putting values at the wrong place...
I use php to convert data from MySQL to a JSON format.
Php and swift below.
login.php file (http://zzzway.com/appMango/login.php)
<?php
header("Content-type: application/json");
if(isset($_POST['loginbutton']))
{
// Create connection
$conn = new mysqli("123", "123", "123", "123");
// Check connection
if ($conn->connect_error)
{
die("Connection failed: " . $conn->connect_error);
}
$email = $_POST["email"];
$password = $_POST["password"];
$sql = "SELECT * FROM `zusers` WHERE `cEmail` = '$email'";
$result = $conn->query($sql);
if(mysqli_num_rows($result)==1)
{
$row = mysqli_fetch_assoc($result);
$hash = password_verify($password, $row['cPassword']);
if ($hash == 1)
{
session_set_cookie_params(0);
session_start();
$firstname = $row['cFirstname'];
$lastname = $row['cLastname'];
$email = $row['cEmail'];
$numpts = $row['NumPts'];
$numuser = $row['NumUser'];
if($row !=1)
{
$erreur=0;
}
else
{
$erreur=1;
}
echo '{ "erreur":'.$erreur.', "nom":"'.$firstname.'", "id":"'.$numuser.'", "pseudo":"'.$email.'" }';
}
}
}
?>
index.html(http://zzzway.com/appMango/login.php)
<form action="login.php" class="login" method="post" autocomplete="on">
<input name="email" placeholder="Email" id="email" required>
<input name="password" placeholder="Mot de passe" id="password" required>
<input class="button border margin-top-5" type="submit" name="loginbutton" value="Connecter"><br>
</form>
swift Networking Service file
import Foundation
enum MyResult<T, E: Error> {
case success(T)
case failure(E)
}
class NetworkingService {
let baseUrl = "https://zzzway.com/appMango/"
func handleResponse(for request: URLRequest,
completion: #escaping (Result<User, Error>) -> Void) {
let session = URLSession.shared
let task = session.dataTask(with: request) { (data, response, error) in
DispatchQueue.main.async {
guard let unwrappedResponse = response as? HTTPURLResponse else {
completion(.failure(NetworkingError.badResponse))
return
}
print(unwrappedResponse.statusCode)
switch unwrappedResponse.statusCode {
case 200 ..< 300:
print("success")
default:
print("failure")
}
if let unwrappedError = error {
completion(.failure(unwrappedError))
return
}
if let unwrappedData = data {
do {
let json = try JSONSerialization.jsonObject(with: unwrappedData, options: [])
print(json)
if let user = try? JSONDecoder().decode(User.self, from: unwrappedData) {
completion(.success(user))
} else {
let errorResponse = try JSONDecoder().decode(ErrorResponse.self, from: unwrappedData)
completion(.failure(errorResponse))
}
} catch {
completion(.failure(error))
}
}
}
}
task.resume()
}
func request(endpoint: String,
parameters: [String: Any],
completion: #escaping (Result<User, Error>) -> Void) {
guard let url = URL(string: baseUrl) else {
completion(.failure(NetworkingError.badUrl))
return
}
var request = URLRequest(url: url)
var components = URLComponents()
var queryItems = [URLQueryItem]()
for (key, value) in parameters {
let queryItem = URLQueryItem(name: key, value: String(describing: value))
queryItems.append(queryItem)
}
components.queryItems = queryItems
// username=kiloloco&password=pass123
let queryItemData = components.query?.data(using: .utf8)
request.httpBody = queryItemData
request.httpMethod = "POST"
request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
handleResponse(for: request, completion: completion)
}
func request(endpoint: String,
loginObject: Login,
completion: #escaping (Result<User, Error>) -> Void) {
guard let url = URL(string: baseUrl) else {
completion(.failure(NetworkingError.badUrl))
return
}
var request = URLRequest(url: url)
do {
let loginData = try JSONEncoder().encode(loginObject)
request.httpBody = loginData
} catch {
completion(.failure(NetworkingError.badEncoding))
}
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
handleResponse(for: request, completion: completion)
}
}
enum NetworkingError: Error {
case badUrl
case badResponse
case badEncoding
}
swift loginViewController file
import UIKit
class LoginViewController: UITableViewController {
override var preferredStatusBarStyle: UIStatusBarStyle { return .lightContent }
#IBOutlet weak var usernameTextField: UITextField!
#IBOutlet weak var passwordTextField: UITextField!
let alertService = AlertService()
let networkingService = NetworkingService()
override func viewDidLoad() {
super.viewDidLoad()
tableView.keyboardDismissMode = .onDrag
}
#IBAction func didTapLoginButton() {
guard
let username = usernameTextField.text,
let password = passwordTextField.text
else { return }
// formDataRequest(username: username, password: password)
jsonRequest(cEmail: username, cPassword: password)
}
func formDataRequest(cEmail: String, cPassword: String) {
let parameters = ["cEmail": cEmail,
"cPassword": cPassword]
networkingService.request(endpoint: "/login.php", parameters: parameters) { [weak self] (result) in
switch result {
case .success(let user): self?.performSegue(withIdentifier: "loginSegue", sender: user)
case.failure(let error):
guard let alert = self?.alertService.alert(message: error.localizedDescription) else { return }
self?.present(alert, animated: true)
}
}
}
func jsonRequest(cEmail:String, cPassword: String) {
let login = Login(cEmail: cEmail, cPassword: cPassword)
networkingService.request(endpoint: "/login.php", loginObject: login) { [weak self] (result) in
switch result {
case .success(let user): self?.performSegue(withIdentifier: "loginSegue", sender: user)
case.failure(let error):
guard let alert = self?.alertService.alert(message: error.localizedDescription) else { return }
self?.present(alert, animated: true)
}
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let mainAppVC = segue.destination as? MainAppViewController, let user = sender as? User {
mainAppVC.user = user
}
}
}
swift User file
import Foundation
struct User: Decodable {
let NumUser: Int
let cFirstname: String
let cEmail: String
let cPassword: String
}
swift Login file
import Foundation
struct Login: Encodable
{
let cEmail: String
let cPassword: String
}
I am new to Swift and I am trying to create secure login with PHP in backend. But somewhere I am going wrong, my viewcontroller is segue to next view controller even though i Don't give login credential and getting following error in console:
Please help !!
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
my code:
#IBAction func loginAuthentication(sender: UIButton) {
//declare parameter as a dictionary which contains string as key and value combination. considering inputs are valid
let myUrl = NSURL(string: "my url");
var request = NSMutableURLRequest(URL:myUrl!)
request.HTTPMethod = "POST"// Compose a query string
let postString = "username = \( NameTextField.text!) & password = \( passwortTextField.text!) ";
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request){ data , response , error in
if error != nil
{
let alert = UIAlertView()
alert.title = "Login Failed!"
alert.message = "Error: \(error)"
alert.delegate = self
alert.addButtonWithTitle("OK")
alert.show()
return
}
// You can print out response object
print("*****response = \(response)")
let responseString = NSString(data: data! , encoding: NSUTF8StringEncoding )
if ((responseString?.containsString("")) != nil) {
print("incorrect - try again")
let alert = UIAlertController(title: "Try Again", message: "Username or Password Incorrect", preferredStyle: .Alert)
let yesAction = UIAlertAction(title: "Nochmalversuchen", style: .Default) { (action) -> Void in
}
// Add Actions
alert.addAction(yesAction)
// Present Alert Controller
self.presentViewController(alert, animated: true, completion: nil)
}
else {
print("correct good")
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyboard.instantiateViewControllerWithIdentifier("toPflegerProfile")
self.presentViewController(controller, animated: true, completion: nil)
}
print("*****response data = \(responseString)")
do {
//create json object from data
if let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as? [String: Any] {
if let email = json["UserName"] as? String,
let password = json["passowrd"] as? String {
print ("Found User id: called \(email)")
}
}
} catch let error {
print(error)
}
}
task.resume()
}
php code :
<?php
require_once 'db.php';
$conn = connect();
if($conn)
{
if (isset($_GET['loginuser']))
{
//Getting post values
require_once 'getuserdata.php';
//1.Check if user is looged in
$loggedin = checkuserloggedin($username, $conn);
if ($loggedin)
{
$response['error']=true;
$response['message']='User is already logged in!';
}
else
{
//2.If not, insert pfleger
//Inserting log in values
if (insertuserdata($name,$username, $password, $gps, $logintime, $conn))
{
$response['error']=false;
$response['message']='Log Data added successfully';
}
else
{
$response['error']=true;
$response['message']='Could not add log in data';
}
}
}
else
{
$response['error']=true;
$response['message']='You are not authorized';
}
echo json_encode($response);
?>
use this
var request = URLRequest(url: URL(string: “url”)!)
request.httpMethod = "POST"
let userName = self.emailTextField.text!
let password = self.passtextField.text!
let postString = NSString(format: "emailId=%#&password=%action=%#",userName, password,”action name”)
request.httpBody = postString.data(using: String.Encoding.utf8.rawValue)
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)")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 { // check for http errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(response)")
}
do {
let jsonResults : NSDictionary = try JSONSerialization.jsonObject(with: data, options: [])as! NSDictionary
print("login json is ---%#",jsonResults)
let str = jsonResults.object(forKey: "status")as! String
if (str == "Success")
{
let newdic:NSDictionary = jsonResults.object(forKey: "response") as! NSDictionary
} catch {
// failure
print("Fetch failed: \((error as NSError).localizedDescription)")
}
}
task.resume()
Hello I'm writing an ios swift 3 application to communicate with a website, the app after doing a number of things should return a type value of false or true, but it does not happen you can tell me where I'm wrong and how to correct the mistake!
VALUE RETURN at swift:
....response = Optional( { URL: "http://....myurl.php"}.....
SWIFT CODE:
let myUrl = URL(string: "http://....myurl.php");
var request = URLRequest(url:myUrl!)
request.httpMethod = "POST"// Compose a query string
let postString = "username=James&password=Bond";
request.httpBody = postString.data(using: String.Encoding.utf8);
let task = URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
if error != nil
{
print("error=\(error)");
// return false
}
print("response = \(response)")
}
task.resume()
return 0;
PHP CODE:
include 'user.php';
$user = new User();
$username= $_REQUEST["username"];
$password = $_REQUEST["password"];
if($user->login($username,$password)==true){
echo json_encode("true");
}
else{
echo json_encode("false");
}
ERROR IMAGE:
You need to look into data and not response.
And maybe you should encapsulate your return value in your PHP code, like this for example:
if($user->login($username,$password)==true){
echo '{"success":true}';
}else{
echo '{"success":false}';
}
And then get the result in swift:
func login(request_completed:#escaping (_ succeded:Bool) -> ()) {
let myUrl=URL(string: "http://....myurl.php");
var request=URLRequest(url:myUrl!)
request.httpMethod="POST"
let postString = "username=James&password=Bond";
request.httpBody = postString.data(using: String.Encoding.utf8);
let task=URLSession.shared.dataTask(with: request, completionHandler: { data, response, error in
guard data != nil else {
print("no data found")
request_completed(false)
return
}
do{
if let jsonData=try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as? NSDictionary{
print(jsonData)
let success=jsonData.value(forKey: "success") as! Bool
if success{
print("login succeded")
request_completed(true)
return
}else{
print("login failed")
request_completed(false)
return
}
}else{
print("could not parse json")
request_completed(false)
}
}catch{
print("request failed")
request_completed(false)
}
})
task.resume()
}
i have php file to check a value passed from swift ios, i print json data, this is the code:
<?php
$said = $_REQUEST['sa_id'];
if($said == '123456') {
$returnValue = array("said" => "true");
}else{
$returnValue = array("said" => "false");
}
echo json_encode($returnValue);
?>
Also i wrote a swift function to check the returned said value, my code is work success in second click, i want it from first click:
class ViewController: UIViewController {
var saidResult = false;
#IBOutlet var saidField: UITextField!
#IBOutlet var labelField: UILabel!
override func viewDidLoad(){
super.viewDidLoad()
}
#IBAction func checkSAID(sender: UIButton) {
if ( isValidSAID(saidField.text) == false ) {
labelField.text = "SAID is Invalid"
} else {
labelField.text = "Done"
}
}
func isValidSAID(said2Test: String) -> Bool {
let myUrl = NSURL(string: "http://*****.com/said.php");
let request = NSMutableURLRequest(URL:myUrl!);
request.HTTPMethod = "POST";
// Compose a query string
let postString = "sa_id=\(said2Test)";
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding);
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
(data, response, error) in
if error != nil {
println("error=\(error)")
return
}
// You can print out response object
println("response = \(response)")
// Print out response body
let responseString = NSString(data: data, encoding: NSUTF8StringEncoding)
println("responseString = \(responseString)")
//Let's convert response sent from a server side script to a NSDictionary object:
var err: NSError?
var myJSON = NSJSONSerialization.JSONObjectWithData(data, options: .MutableLeaves, error:&err) as? NSDictionary
if let parseJSON =myJSON {
// Now we can access value of First Name by its key
var saidValue = parseJSON["said"] as? String
println("saidValue: \(saidValue)")
if ((saidValue) == "true" ) {
self.saidResult = true;
}
println("saidResult: \(self.saidResult)");
}
}
task.resume()
println("saidResult: \(self.saidResult)");
if ( self.saidResult == true ){
return true
} else {
return false
}
}
}
As i say, in first click the value of saidResult is false but after that it is take the true value
How i can solve this issue, or is there another way to improve my code?
I think this is probably because the http request is not answered on the first click but is on the second click.
you could try replacing your checkSAID function with this.
#IBAction func checkSAID(sender: UIButton) {
let saidQueue = dispatch_queue_create("saidQueue", DISPATCH_QUEUE_CONCURRENT)
// Do the checking on a background thread.
dispatch_async(saidQueue, {
if ( isValidSAID(saidField.text) == false ) {
// As the UI updates are performed on the main queue, update the label on the main queue.
dispatch_async(dispatch_get_main_queue()) {
labelField.text = "SAID is Invalid"
})
} else {
dispatch_async(dispatch_get_main_queue()) {
labelField.text = "Done"
})
}
})
}
Finally, after 4 days of testing i solved my problem.
I changed isValidSAID function code:
func isValidSAID(said2Test: String) -> Bool {
var status: String = "";
let myUrl = NSURL(string: "http://*****.com/said.php?sa_id=\(said2Test)");
let data = NSData(contentsOfURL: myUrl!)
let json = NSHSONSerialization.JSONObjectWithData(data!, option: nil, error: nil) as! NSDictionary
status = (json["said"] as? String)!
println(status)
return ( status == "true" ) ? true : false
}
and solved my issue.