简体   繁体   中英

Store Device Token in MySQL Database using Swift

I have been making progress but stuck for days on how to get my user's device tokens into a MySQL database using PHP on the serverside and Swift code on my iOS app. It successfully registers for the push notifications but will not send to my server. The code snippets are below. In addition, I will want to also send the IP of the device to match up with current users of my app. Any help is appreciated!

The Swift code:

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    // 1. Convert device token to string
    let tokenParts = deviceToken.map { data -> String in
        return String(format: "%02.2hhx", data)
    }
    let token = tokenParts.joined()
    // 2. Print device token to use for PNs payloads
    print("Successfully registered for notifications!")
    print("Device Token: \(token)")
    URLRequest(url: URL(string:"https://MY_URL.com/registerPushApple.php?key=MY_KEY&token=\(token)")!)

}

The PHP code:

//Put in database
date_default_timezone_set('America/New_York');
$date = date("Y-m-d");
$device_ip = $_GET['device_ip'];
$device_token = $_GET['token'];
$key = $_GET['key'];

if($key == "MY_KEY") {

    // Insert Info into Database
    $mysqli->query("INSERT INTO device_info (date, device_ip, device_token) VALUES ('$date', '$device_ip', '$device_token')");


} else {

    die();

}

// close connection 
$mysqli->close();

A few observations:

  1. Your Swift code isn't sending the request to the server. You might do something like:

     var request = URLRequest(url: URL(string:"https://MY_URL.com/registerPushApple.php")!) request.httpBody = "key=MY_KEY&token=\\(token)".data(using: .utf8) request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") request.httpMethod = "POST" let task = URLSession.shared.dataTask(with: request) { data, response, error in guard let data = data, error == nil else { print(error ?? "Unknown error") return } // OK, if you got here, the server successfully responded, but you now // need to parse it with `JSONDecoder` and make sure there weren't any // SQL errors reported. But I'm just going to print the response JSON for now: print(String(data: data, encoding: .utf8)) } task.resume()

    Note:

    • it's a POST request;
    • we're sending our data in the httpBody of the request, not the URL; and
    • we're performing the request with resume .

    I'd also suggest percent-encoding the request body just in case any of your values contain any reserved characters. Or use a library like Alamofire , which gets you out of the weeds of building well-formed requests.

  2. Your PHP code isn't checking to see if the INSERT succeeded or not, and if not, respond with enough information for you to diagnose what's going on. For example:

     <?php header('Content-type: application/json'); // You didn't send IP in your request, so you won't find it in `$_GET` or `$_POST` // Perhaps https://stackoverflow.com/a/2031935/1271826 function get_ip_address(){ foreach (array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR') as $key){ if (array_key_exists($key, $_SERVER) === true){ foreach (explode(',', $_SERVER[$key]) as $ip){ $ip = trim($ip); // just to be safe if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false){ return $ip; } } } } } $mysqli = new mysqli('localhost', 'user', 'pwd', 'db'); // check connection if ($mysqli->connect_errno) { echo json_encode(array('success' => false, 'message' => $mysqli->connect_error, 'sqlerrno' => $mysqli->connect_errno)); exit(); } $mysqli->set_charset('utf8'); // perform the insert $device_ip = get_ip_address(); $device_token = $_POST['token']; $key = $_POST['key']; $sql = 'INSERT INTO device_info (date, device_ip, device_token, key) VALUES (NOW(), ?, ?, ?)'; if ($stmt = $mysqli->prepare($sql)) { $stmt->bind_param('sss', $device_ip, $device_token, $key); if (!$stmt->execute()) $response = array('success' => false, 'message' => $mysqli->error, 'sqlerrno' => $mysqli->errno, 'sqlstate' => $mysqli->sqlstate); else $response = array('success' => true); $stmt->close(); } else { $response = array('success' => false, 'message' => $mysqli->error, 'sqlerrno' => $mysqli->errno, 'sqlstate' => $mysqli->sqlstate); } $mysqli->close(); echo json_encode($response); ?>

    Note:

    • you want to bind your values to ? in the SQL to protect against SQL injection attacks (or use real_escape_string ); and
    • you want to check that the insert succeeded and return meaningful JSON responses, whether successful or not.

Now, I just dashed this off, so please forgive any typographical errors. But hopefully this gives you the basic idea.

Clearly, you shouldn't just print the JSON that's returned, but parse it with JSONDecoder and look at the result for errors.

Likewise, your PHP should probably do some graceful checking that the parameters have been found in the request and return nice JSON error response if not. But hopefully this gets you going in the right direction.


You said:

I will want to also send the IP of the device to match up with current users of my app.

No, you don't want the device to add its IP number in the request, because the device will only know its local IP number (eg, if on wifi, it's often something like 192.168.0.x and many users may have the same local IP number on their respective LANs). Obviously, as far as the server is concerned, that's often meaningless. You should have the PHP extract the IP number from the request it received like shown above.

On top of this, I don't think the IP number is a good way to verify users, anyway. If you walk into a cafe and hop on their wifi: The IP number has changed. You turn on your VPN: The IP number changes again. You lose your Internet connection and reconnect: The IP number likely changes again. Bottom line, IP numbers (even if you let the server grab it rather than asking the device to figure it out) are subject to changes and are not a good way to verify a user.

Don't get me wrong: I don't think capturing the IP number is necessarily a bad idea. But use it for informational purposes only. If you want to validate the user, there are generally other, better ways to do this.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM