So, you want to communicate data between your app and web server?

Before we delve into this, you may want to read about the legal implications on including encryption in your app, how to configure an HTTPS server and how to encrypt data in your app.

Once we are done here, you’ll have a good foundation for being able to send encrypted data between our app and web server. This just adds an extra layer of protection on top of HTTPS along with giving you the chance to store encrypted data on the local device. So, what’s the first thing we need to do? Let’s take a look at the functionality Unity provides to communicate with a web server. There are two classes we’ll look at for this, “WWW” and “WWWForm”. Unity makes it pretty easy to send info to a web server and wait for the result. Here is a basic example of how to do this:


// Set up form to send POST data
WWWForm wwwForm = new WWWForm();
wwwForm.AddField("yourField", data);

// Send data and wait for result
www = new WWW("https://yourUrlHere", wwwForm);
yield return www;
error = www.error;

// Process the data
if (String.IsNullOrEmpty(error) == true) {
  ProcessResults(www.text);

You can add as many fields as you would like for sending data to your web server. So if you were sending a player name and a score, you create two fields on your WWWForm object. When you send the data, your script on the web server will process the data and send back a result that your app can then respond to. One thing to point out, we use a “yield return www” statement, this effectively allows the app to continue without waiting for a response from our web server. That yield statement is where the app is just waiting for the script shown below to complete while allowing the other code to run. This is done through coroutines which I’ll talk about in a bit. For now lets jump to the PHP side to see how we’d process this info and then we’ll get into a more complicated example that includes retrying our result if there was a problem and encrypting the data before we send it to our web server.

So in PHP on your web server we’ll access the data in the request using the $_POST variable. This will look something like this:

// Note that we named the variable "yourField" from
// the C# portion of the code above
$yourFieldData = $_POST["yourField"]; 

// Do something here with $yourFieldData like insert it in a database

header("Access-Control-Allow-Origin: *");
print("Some sort of return value(s) for your app to process");

That is what we are looking at from the PHP side. We take the data sent in from our app, process it, then respond by outputting something that our app will then read  Maybe like a return code so it knows if things were process properly or the ranking of the record just inserted in comparison to all the other records in that table. Now that we’ve got the basic idea down of how that all works, we can add things to it like encryption and retrying if there was a communications issue. I’ll cover caching the results to the device in another post so that if the user quits out of the game and the data hasn’t been saved yet to our server or there was a complete loss in communications, the request will be retried again later. For now, we are going to assume the transaction goes through the 2nd or 3rd time we try it if there was a slight hiccup in the communications between our app and the web server.

First thing we’ll do is setup our code for making calls to our web server. I created a script named DAO.cs (This stands for Data Access Object) and made it a static singleton instance. The reason I did this was because StartCoroutine is a method of the Monobehaviour class and needs an instance to be able to be called since StartCoroutine is not static. If StartCoroutine is called from a script that can be destroyed (i.e. calling your StartCoroutine then calling Application.LoadLevel() right afterwards), the StartCoroutine also dies because it is called from your scene’s instance (derived from Monobehaviour) even if that call to StartCoroutine isn’t finished yet. This had me very confused at first when my coroutine was killing out during an HTTPS request because I had called a LoadLevel() to get to the next scene of my app. I assume (falsely) that a coroutine was similar to a thread and would continue independent of what had called it. So came the necessity to make our DAO script and attach it to a game object that just goes with us through the life of that gaming session. In the script below, you see the methods themselves of the DAO class are static, but we still use the static singleton instance of the DAO object to call StartCoroutine from. I guess you don’t have to make the DAO methods static since you have a static singleton instance of the DAO class following you around, but when I first designed it, I didn’t think I’d need this static singleton DAO instance. The following code is more of a guide/example, I pulled it from one of my working projects and cut it down a bit, so you’ll have to modify it to fit your needs.

For passing data in your POST, you could pass a separate key/value for each and just encrypt the values on each key. What I decided to do is have just one key and pass in multiple key/values on that one parameter and separated each key/value with a pipe. I let my PHP code split up everything once the payload made it there. You could also use serialization or pass the data in an XML string if you wanted. So, in effect, what I have is a query string passed to the web server that looks something like “https://some-web-page.php?data=key1=value1|key2=value2|key3=value3“. However you decide to pass data to your web server is really up to you.

Some things to note:

  • Wait…you can’t pass an equal sign/spaces/whatever special character safely to your web server without URL encoding it! Yes, you are right, but my payload is encrypted (via the Crypt class) and effectively URL encoded. So passing equal signs are okay here since the value part of the “data” parameter looks something like “g1tThXzmX1Mjunux1Eto5YA” when it is sent along its way to the web server.
  • Make sure the function you want to call via StartCoroutine has a return parameter of IEnumerator. This will allow us to do some nice things like yield for a return while allowing the rest of the code to run. Pseudo-multi-threading I guess is the best way to define this.
  • We define a maximum amount of attempts we’ll try the request ALONG with a slight pause in between trying multiple times. If there is a small hiccup in communications, we want to give the device a little bit of time to correct before retrying.
  • www.text will be the response we receive from the web server. Again, this is up to you on how you want your PHP script to respond to this request. For your PHP script to respond, all you have to do is simply print() something before exiting the PHP script.
  • You did read How can I securely save my app data?, right?
  • Don’t hate on the use of prepended underscores for private variables 🙂
using UnityEngine;
using System;
using System.Collections;

public class DAO : MonoBehaviour {

  // Specific instance of this class
  public static DAO instance = null;

  // Max attempts to send data to the web server
  private static int _maxAttempts = 3;

  /**
  */
  void Start() {
    // Making sure we only have one instance of this game object
    if (DAO.instance == null) {
      DAO.instance = this;
      DontDestroyOnLoad(this);
    }
    else {
      Destroy(gameObject);
    }
  }

/**
 */
  public static IEnumerator GetScores() {
    int attempts = 0;
    string error = "ERROR";
    WWW www = null;
    // This is the payload to your web server. For a simple
    // GetScore type of functionality, you might pass it
    // a date to get scores inserted past a specific date
    string data = "key1=value1|key2=value2";
    // This is the key you share between your app and
    // your web server so that you can encode/decode
    // information
    string key = "yourKeyHere";
    string encryptedData = Crypt.Encrypt(data, key);

    // Try maxAttempts times to get the data
    while (attempts < DAO._maxAttempts && String.IsNullOrEmpty(error) == false) {
      // Sleep for 3 seconds before trying multiple times
      if (attempts > 1)
        yield return new WaitForSeconds(3f);

      // Set up form to send POST data
      WWWForm wwwForm = new WWWForm();
      wwwForm.AddField("data", encryptedData);

      // Send data and wait for result
      www = new WWW("https://yourURL", wwwForm);
      yield return www;
      error = www.error;
      attempts++;

      // Process the data and put it into an
      // array if there were no errors
      if (String.IsNullOrEmpty(error) == true) {
        DAO.PopulateScores(www.text);
      }
      else {
        // Handle any errors here
      }
    }
  }

/**
 */
  public static void PopulateScores(string text) {
    // This is the key you share between your app and
    // your web server so that you can encode/decode
    // information
    string key = "yourKeyHere";
    try {
      string decryptedText = Crypt.Decrypt(text, key);
      if (decryptedText.Contains("|") == true) {
        string[] scores = decryptedText.Split('|');
        // Do something with "scores"
      }
      else {
        // Invalid return from web server
      }
    }
    catch (Exception e) {
      // Handle exception here
    }
  }
}

To call this from your app, all you have to do is something like:

DAO.instance.StartCoroutine(DAO.GetScores());

This uses the instantiated static singleton DAO object “instance” to call StartCoroutine on the static method GetScores(). And because we are using a static instance, we don’t have to worry about the coroutine killing out if we go to another scene while the coroutine might still be running.

So how about the PHP side of things? In this example, we are retrieving scores from a database and returning the data so the app can do something with that data like display it. Again, how you decide to structure the return data is up to you. We could easily return something like “score1|score2|score3|score4” (which is the structure this example is expecting) and when our app receives the data, splits the string into an array or you could use serialization on your objects or even XML as well. It would probably be more “proper” to use serialization or XML. I’m actually not very fond of using XML in this instance due to how verbose XML can be. I want the smallest amount of data transfer as possible…especially with mobile devices.

For pulling back the scores, let’s pretend we have a table named “PlayerScores” in our MySQL database and it consists of three columns, an “id”, “name” and “score”. Below is some PHP code that uses this structure to query for the data and send it to our app who is patiently waiting for a response from our web server via the “yield return www” C# statement.

Some more things to note:

  • Procedural code? That’s so 1990s. Yeah well, think of it as an exercise to convert it to object oriented code.
  • Wait…where did “Decrypt” come from? That isn’t a PHP function. Yup, you are right. “Decrypt” is one of the the sister functions to our Crypt class in C#. More on that a little later.
  • Again, this code is cut down from one of my projects and so doesn’t have some error handling, so it may not be fully functional as is but it gives you a very good direction on how to go about doing something like this.
  • Depending on how you passed the data in your POST from your app, you will need to design your “WhateverFunctionYouCreateToExtractYourData” function to handle it.
  • Whats up with the header(“Access-Control-Allow-Origin: *”); code in your PHP? This just has to do with my Unity Web Player hosted on Dropbox trying to call my PHP scripts on a different domain. I’m just letting the browser know it is okay to do this.

<?php
  // Include whatever classes and files you need here

  // Make sure things look right from the request
  // This simply makes sure we are communicating across HTTPS
  // and "data" is present in our POST
  if (!isset($_SERVER["HTTPS"]) || !isset($_POST["data"])) {
    die();
  }

  $key = "whateverKeyYouUsedInTheAppToEncryptTheData";
  $decryptedData = Decrypt($_POST["data"], $key);
  $values =
    WhateverFunctionYouCreateToExtractYourData($decryptedData);

  // Check to make sure all expected keys are present
  if (!isset($values["key1"]) || !isset($values["key2"])) {
    die();
  }

  // You'll have to supply the connection information below
  // based on how your database is setup
  $link = mysqli_connect($server, $userName, $password, $database);
  $result =
    mysqli_query($link, "SELECT score FROM PlayerScores ORDER BY score DESC");

  // Putting scores into data
  $allScores = array();
  while (($scores = mysqli_fetch_assoc($result)) != false) {
    $allScores[] = $scores;
  }

  // Cleaning some things up
  mysqli_free_result($result);
  mysqli_close($link);

  // Encrypting the data and sending it back to the requestor
  $encryptedData = Encrypt(implode("|", $allScores), $key);
  header("Access-Control-Allow-Origin: *");
  print($encryptedData);
?>

For this to all work like it needs to, our PHP code needs to be able to decrypt the data sent to it and then encrypt a response. Before returning our scores, we encrypt the string and print() it out. Once the script does this, the “yield return www” completes and we now have our response data in www.text on the C# side. Here is how you’d create some Encrypt/Decrypt functionality on the PHP side. Most of this encryption/decryption code here is NOT mine.

<?php
  /**
   *
   * @param Info to encrypt $data
   * @param Used to generate key $secret
   */
  function Encrypt($data, $secret) {
    // Generate a key from a hash, use 192 bit key
    $key = bin2hex(substr(md5(utf8_encode($secret), true), 0, 12));

    // Pad for PKCS7
    $blockSize = mcrypt_get_block_size('tripledes', 'ecb');
    $len = strlen($data);
    $pad = $blockSize - ($len % $blockSize);
    $data .= str_repeat(chr($pad), $pad);

    // Encrypt data
    $encData = mcrypt_encrypt('tripledes', $key, $data, 'ecb');
    return (base64_encode($encData));
}

  /**
   *
   * @param Info to decrypt $data
   * @param Used to generate key $secret
   */
  function Decrypt($data, $secret) {
    // Generate a key from a hash, use 192 bit key
    $key = bin2hex(substr(md5(utf8_encode($secret), true), 0, 12));
    $data = base64_decode($data);

     // Decrypt data
    $data = mcrypt_decrypt('tripledes', $key, $data, 'ecb');
    $block = mcrypt_get_block_size('tripledes', 'ecb');
    $len = strlen($data);
    $pad = ord($data[$len-1]);
    return (substr($data, 0, strlen($data) - $pad));
  }
?>

The PHP code feels a bit simpler than the C# code for encrypting/decrypting. Once you have this in a PHP script, include it in the other script above, then you can call Encrypt() and Decrypt() to your heart’s desire! Now your app and web server should be able to send encrypted data to each other across HTTPS! Got any suggestions or tips? Share them in the comments below, I’m always looking for ways to make my code better.