-1

I am building a simple login with password application using a MySQL Server and PHP files uploaded to a FTP. I have been trying many different ways to get the connection to work on Simulator but to no avail so far. I am using Swift 3.0 and XCode 8.3.2. Somewhere I have made a mistake but I have no idea where! Also I have set the Allow Arbitrary Loads to YES in the info.plist. Any help is appreciated.

In many tutorials I have seen I have seen this popup that I never have gotten. Pop up in tutorial I don't ever get

Simulator image #1

Simulator image #2

In my Login.swift

import UIKit

class Login: UITableViewController {
    @IBOutlet weak var txtUsername: UITextField!
    @IBOutlet weak var txtPassword: UITextField!
    @IBOutlet weak var loginView: UIButton!
    @IBOutlet weak var btnPasswordView: UIButton!
    var passwordString:String!
    var usernameString:String!

    override func viewDidLoad() {
        super.viewDidLoad()
        passwordViewConfig()

    }

    //Function PasswordView.
    func passwordViewConfig() {
        txtPassword.isSecureTextEntry = true
        btnPasswordView.setImage(UIImage(named: "EyeClosedIcon"), for: UIControlState.normal)


    }
    //Action change image PasswordView
    @IBAction func btnPasswordViewAction(_ sender: Any) {
        passwordString = txtPassword.text
        if btnPasswordView.currentImage!.isEqual(UIImage(named: "EyeClosedIcon")) {
            btnPasswordView.setImage(UIImage(named: "EyeOpenIcon"), for: UIControlState.normal)
            txtPassword.isSecureTextEntry = false
            txtPassword.text = nil
            txtPassword.text = passwordString
        } else {
            btnPasswordView.setImage(UIImage(named: "EyeClosedIcon"), for: UIControlState.normal)
            txtPassword.isSecureTextEntry = true
            txtPassword.text = passwordString
        }

    }
    //Redirect select cell to textField
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        if indexPath.section == 0 && indexPath.row == 0 {
            txtUsername.becomeFirstResponder()
        }

        if indexPath.section == 0 && indexPath.row == 1 {
            txtPassword.becomeFirstResponder()
        }
    }
    //Function config Return key
    func textFieldShouldReturn(textField: UITextField) -> Bool {
        if textField == txtUsername {
            textField.resignFirstResponder()
            txtPassword.becomeFirstResponder()
        }
        if textField == txtPassword {
            usernameString = txtUsername.text
            passwordString = txtPassword.text
            if usernameString.isEmpty || passwordString.isEmpty {
                textField.resignFirstResponder()
                txtUsername.becomeFirstResponder()
            } else {
                loginAction(self)
            }
        }
        return true
        }

    //Function config background image login button
    func loginViewConfig() {


    }

    @IBAction func loginAction(_ sender: Any) {
        usernameString = txtUsername.text
        passwordString = txtPassword.text
        if usernameString.isEmpty || passwordString.isEmpty {
            let alertAction:UIAlertAction = UIAlertAction(title: "Close", style: UIAlertActionStyle.default, handler: { (alert) -> Void in
                self.txtUsername.becomeFirstResponder()
            })
            alertView(title: "Error !", message: "Please fill in all fields", alertStyle: UIAlertControllerStyle.alert, alertAction: alertAction)
        } else {
            queryToServerLogin()
        }

    }

    func queryToServerLogin() {
        let url:String = "here is URL to my login.php file"
        /*
        $username = htmlentities($_GET['username']);
        $password = md5(htmlentities($_GET['username']));
        */
        let postString:String = "username=\(usernameString)&password=\(passwordString)"
        print ("username=\(usernameString!)&password=\(passwordString!)")

        self.queryToServer(urlSource: url, postString: postString) { (dataResult, errorResult) -> () in
            if errorResult != nil {
                let alertAction:UIAlertAction = UIAlertAction(title: "Close", style: UIAlertActionStyle.default, handler: nil)
                self.alertView(title: "Error !", message: "Could not connect to server", alertStyle: UIAlertControllerStyle.alert, alertAction: alertAction)
                } else {
                self.extractDataWithNSDictionary(data: dataResult! as NSData, result: { (statusResult, messageResult, errorResult) -> () in
                    if errorResult !== nil {
                        print(errorResult as Any)
                        let alertAction:UIAlertAction = UIAlertAction(title: "Close", style: UIAlertActionStyle.default, handler: nil)
                        self.alertView(title: "Error !", message: "Could not query to server.", alertStyle: UIAlertControllerStyle.alert, alertAction: alertAction)
                    } else {
                        if statusResult == "success" {
                            let alertAction:UIAlertAction = UIAlertAction(title: "Close", style: UIAlertActionStyle.default, handler: nil)
                            self.alertView(title: "Success !", message: messageResult!, alertStyle: UIAlertControllerStyle.alert, alertAction: alertAction)
                            } else {
                                if statusResult == "success" {
                                    let alertAction:UIAlertAction = UIAlertAction(title: "Close", style: UIAlertActionStyle.default, handler: nil)
                                    self.alertView(title: "Error !", message: messageResult!, alertStyle: UIAlertControllerStyle.alert, alertAction: alertAction)
                            }
                      }
                }
            }

        )}
    }
}
}

In my Extensions.swift

import Foundation
import UIKit
extension UIViewController {
    func makeImageViewWithColor(_ color: UIColor) -> UIImage {
        let rect: CGRect = CGRect (x: 0, y: 0, width: 1, height: 1)
        color.setFill()
        UIRectFill(rect)
        let image:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
        return image
    }
    //Function Alert View
    func alertView(title:String, message:String, alertStyle:UIAlertControllerStyle, alertAction:UIAlertAction) {
        let alert:UIAlertController = UIAlertController(title: title, message: message, preferredStyle: alertStyle)
        alert.addAction(alertAction)
        self.present(alert, animated: true, completion: nil)
    }

    //Function query to server
    func queryToServer(urlSource:String, postString:String, result:@escaping (Data?, Error?) -> ()) {
        let url = URL(string: urlSource)!
        var request = URLRequest (url: url, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: 10)
        request.httpMethod = "POST";
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")
        request.httpBody = postString.data(using: .utf8)
        let session = URLSession.shared
        session.dataTask(with: request) { (data, response, error) in
            DispatchQueue.main.async {
                result(data, error)
            }
            }.resume()
        }

        //Function extract data
        func extractDataWithNSDictionary(data:NSData, result:(_ statusResult:String?, _ messageResult:String?, _ errorResult:NSError?) -> ()){
            var json:NSDictionary!
            var errorParse:NSError!
            do {
            json = try JSONSerialization.jsonObject(with: data as Data, options: JSONSerialization.ReadingOptions.mutableContainers) as! NSDictionary
        } catch let error as NSError {
            errorParse = error
            json = nil
        }
        if errorParse != nil {
            result(nil, nil, errorParse)
        } else {
            let resultStatus:String = json["status"] as! String
            let resultMessage:String = json["message"] as! String
            result(resultStatus, resultMessage, nil)
    }
}

}

Then in my FTP root I have a MySQL.ini file which was not working

[section]
dbhost = mysql url
dbuser = username
dbpass = password
dbname = database name

Also a mysql.php

<?php

class mysql
{
    var $dbhost = null;
    var $dbuser = null;
    var $dbpass = null;
    var $dbname = null;
    var $conn = null;
    var $result = null;
    function _construct ()
    {
        $mysqlfile = parse_ini_file('MySQL.ini');
        $this->dbhost = $mysqlfile['dbhost'];
        $this->dbuser = $mysqlfile['dbuser'];
        $this->dbpass = $mysqlfile['dbpass'];
        $this->dbname = $mysqlfile['dbname'];

    }
    //Function connect to sql
    public function connection() {
        //$this->conn = new mysqli($this->dbhost, $this->dbuser, $this->dbpass, $this->dbname);
        $this->conn = new mysqli('mysql url', 'username', 'password', 'database name');
        if (mysqli_connect_error()){
            return false;
        }
        mysqli_set_charset($this->conn, 'utf8');
        return true;
    }
    //Function close sql
    public function closeConecttion() {
        if ($this->conn !=null) {
            mysqli_close($this->conn);
        }
    }

    //function check username does not exits
    public function checkUsername($username) {
        $sql = "SELECT authentication_username FROM time_employee WHERE authentication_username = '$username'";
        $this->result = mysqli_query($this->conn, $sql);
        if (mysqli_num_rows($this->result) <= 0 ) {
            return false;
        }
        return true;
    }

    //function check password username
    public function checkPasswordUsername($username, $password) {
        $sql = "SELECT authentication_username, authentication_password FROM time_employee WHERE authentication_username = '$username'";
        $this->result = mysqli_query($this->conn, $sql);
        $row = mysqli_fetch_array($this->result);
        if ($row['password'] != $password) {
            return false;
        }
        return true;
    }

}

And a login.php

<?php

include_once('mysql.php');
$mysql = new mysql();
$username = htmlentities($_REQUEST['username']);
$password = md5(htmlentities($_REQUEST['password']));
$resultValue = array();
//Function check connect to database
if ($mysql->connection()) {
    //Function check username exist
    //if !mysql->checkUsername($username) return false
    if(!$mysql->checkUsername($username)) {
        $resultValue['status'] = "error";
        $resultValue['message'] = "username does not exist";
        echo json_encode($resultValue);
    } else {
        //Function check password
        //If !$mysql->checkPasswordUsername($username, $password) return false
        if (!$mysql->checkPasswordUsername($username, $password)) {
            $resultValue['status'] = "error";
            $resultValue['message'] = "Incorrect password";
            echo json_encode($resultValue);
        } else {
            $resultValue['status'] = "success";
            $resultValue['message'] = "Logged in successfully";
            echo json_encode($resultValue);
        }
    }
} else {
    $resultValue['status'] = "error";
    $resultValue['message'] = "could not connect to database";
    echo json_encode($resultValue);
}
?>
<?php exit; ?>
  • What error are you getting? – Sloan Thrasher May 30 '17 at 07:00
  • No error really, I heard there should be a popup in Simulator that pops up so I can connect to the Server but it never comes up. – Victor Larsson May 30 '17 at 07:05
  • You really need to remove a lot of extraneous information from this question. Just say which bit of code is failing, what your inputs were and what was the result. When you get an errorResult in queryToServerLogin have you checked to see what it is? – adamfowlerphoto May 30 '17 at 07:28
  • I don't get any errors in the debugger it just prints my username and password I enter no matter what is: username=victor@bluescreen.se&password=blabla – Victor Larsson May 30 '17 at 08:13
  • MD5 is not sufficient for password hashing. Use [`password_hash()`](http://us3.php.net/manual/en/function.password-hash.php) and [`password_verify()`](http://us3.php.net/manual/en/function.password-verify.php) instead – Alex Howansky May 30 '17 at 13:40
  • Your code is vulnerable to [**SQL injection**](https://en.wikipedia.org/wiki/SQL_injection) attacks. You should use [**mysqli**](https://secure.php.net/manual/en/mysqli.prepare.php) or [**PDO**](https://secure.php.net/manual/en/pdo.prepared-statements.php) prepared statements with bound parameters as described in [**this post**](https://stackoverflow.com/questions/60174/how-can-i-prevent-sql-injection-in-php). – Alex Howansky May 30 '17 at 13:40
  • Are you trying to connect to an http or https site? – adamfowlerphoto May 30 '17 at 17:32
  • @Spads it is a https I changed it from http because I heard http is not working anymore correctly. Now if I run my PHP script on the URL it says {"status":"success","message":"Logged in successfully"} but when I try to log in on the app simulator it says {"status":error","message":"username does not exist"} so I think the problem is on the XCode side right now if anyone has any ideas that would be great! – Victor Larsson May 31 '17 at 06:32

1 Answers1

0

I also noticed you are sending your post data in the form username=...&password=... But in queryToServer() you have the line

request.addValue("application/json", forHTTPHeaderField: "Content-Type")

You are saying the data you have attached is json when it is not. Try this instead.

 request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
adamfowlerphoto
  • 2,708
  • 1
  • 11
  • 24
  • I tried this but still same error {"status":error","message":"username does not exist"} – Victor Larsson May 31 '17 at 07:34
  • Add the username you are checking for to your error message, to make sure it is getting through – adamfowlerphoto May 31 '17 at 07:56
  • how do i do this? ö,ö – Victor Larsson May 31 '17 at 08:02
  • In your php code when you set the message to "username does not exist" set it to $username." username does not exist". – adamfowlerphoto May 31 '17 at 08:04
  • In my login.php it says that the connection, checkUsername and checkPasswordUsername methods are not found. Referenced method is not found in subject class. Does this mean that it is not reading it from mysql.php? – Victor Larsson May 31 '17 at 08:14
  • Sounds like it isn't finding your mysql.php file. Change your include_once to require_once. If it can't find the file it will stop execution and it should be pretty obvious it can't find it – adamfowlerphoto May 31 '17 at 08:18
  • Oh by the way if you are going to stick your db username and password in a ini file make sure it can't be read by a web browser – adamfowlerphoto May 31 '17 at 08:23
  • thanks I changed it to require_once but still XCode side error – Victor Larsson May 31 '17 at 09:03
  • You said your php wasn't running correctly you need to look at that first. Have you tried curl to test out your php? Try curl -d "username=...&password=..." – adamfowlerphoto May 31 '17 at 09:29
  • I was wrong about these errors my boss said because the php side should be fine if I put the incorrect password or username it says incorrect password and/or username and if I put the correct username and password it will say say successfully logged in. So the PHP seems fine it is just how the XCode Swift is asking for the data we think. – Victor Larsson May 31 '17 at 12:24
  • I have seen in some tutorials in the Simulator they get a popup asking to connect to the server...but I never get this popup (I added an image of this in my original question. – Victor Larsson May 31 '17 at 12:43
  • I'm not seeing a popup and my iphone, webserver connection works fine. You are getting a response (ie username doesnt exist) so you must be making a connection. I would suggest you write a simple php file that returns the contents of the $_REQUEST and raw post to see what the iphone is sending to you. – adamfowlerphoto May 31 '17 at 15:57
  • Hi again, the PHP is going fine but there is some error in my XCode still it does not know what login is correct it just says Success! Logged in Successfully no matter what I input. – Victor Larsson Jun 02 '17 at 07:49
  • Have you tried my suggestions with curl and the one above to see what variables are coming through to the server? Also you seemed to have had 3 different responses from the server (couldnt connect, username doesnt exist and now success all the time) during the process of asking this question. – adamfowlerphoto Jun 02 '17 at 12:19