Submit form as a server and not the client with cURL

What?
A quick article on how to create a middleware script which accepts the values from a submitted HTML form and sends it to a server on another domain for processing. This applies to Linux Apache MySQL and PHP (LAMP) setups.

Why?
A customer wanted to connect their Mobile App to a third-party API. The third-party only accepts requests from a static and permitted IP address. If the end-user were to make the request, then their own IP address would be the one checked against, and it just wouldn't be manageable to add every new user's IP address to their service. The request has to come from a permitted server with a single IP address.

How?
It's likely that you already know how to submit a HTML form to a server via your Mobile application so the following will only document the process of sending data under the server IP address. We're going to use a PHP script with the cURL function to receive and send the data. cURL is a standard feature on most LAMP setups. If not you can install it from here: http://curl.haxx.se/download.html

I'm demonstrating this with 3 scripts on the intermediary server:
1. to display the HTML form (usually handled by the mobile app)
2. to send the values to the third-party (executable script)
3. to receive the values from the third-party service/server/api

Script #1: The HTML form:
copyraw
<form id="my_form" method="post" action="./send.php">
	Sender: <input id="my_sender" name="my_sender" value="MyMobile" readonly="readonly" /><br />
	Receiver: <input id="my_receiver" name="my_receiver" value="JoelLipman.com" readonly="readonly" /><br />
	<input type="submit" name="submit" value="Submit" />
</form>
  1.  <form id="my_form" method="post" action="./send.php"> 
  2.      Sender: <input id="my_sender" name="my_sender" value="MyMobile" readonly="readonly" /><br /> 
  3.      Receiver: <input id="my_receiver" name="my_receiver" value="JoelLipman.com" readonly="readonly" /><br /> 
  4.      <input type="submit" name="submit" value="Submit" /> 
  5.  </form> 

Script #2: Send to third-party in XML format: (because that's the format they accept)
Note that in the following example, the XML is sent as a url encoded value paired with a key (posted variables must be key1=value1&key2=value2...)
copyraw
<?php
        /*
        * XML Sender/Client.
        */
        header ("Content-Type:text/xml");

        // format submitted values
        $the_sender = trim($_POST['my_sender']);
        $the_receiver = trim($_POST['my_receiver']);

        // set some values
        $the_thirdparty_url = "http://www.joellipman.com/my_api";

        // split out parameters and put in format the third-party is expecting
        $the_message_xml = "the_message=" . urlencode("<?xml version='1.0' encoding='UTF-8' ?>
                <the_message>
                        <header sender='".$the_sender."' receiver='".$the_receiver."' mode='TEST'></header>
                </the_message>");

        // We send XML via CURL using POST with a http header of text/xml.
        $ch = curl_init();

        // set URL and other appropriate options
        curl_setopt($ch, CURLOPT_URL, $the_thirdparty_url); // where to send the variables
        curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: text/xml'));
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $the_message_xml);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
        curl_setopt($ch, CURLOPT_REFERER, 'receive.php');  // my receiving file
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $ch_result = curl_exec($ch);
        curl_close($ch);

        // Print CURL result.
        echo $ch_result;
?>
  1.  <?php 
  2.          /* 
  3.          * XML Sender/Client. 
  4.          */ 
  5.          header ("Content-Type:text/xml")
  6.   
  7.          // format submitted values 
  8.          $the_sender = trim($_POST['my_sender'])
  9.          $the_receiver = trim($_POST['my_receiver'])
  10.   
  11.          // set some values 
  12.          $the_thirdparty_url = "http://www.joellipman.com/my_api"
  13.   
  14.          // split out parameters and put in format the third-party is expecting 
  15.          $the_message_xml = "the_message=" . urlencode("<?xml version='1.0' encoding='UTF-8' ?> 
  16.                  <the_message> 
  17.                          <header sender='".&#36;the_sender."' receiver='".$the_receiver."' mode='TEST'></header> 
  18.                  </the_message>")
  19.   
  20.          // We send XML via CURL using POST with a http header of text/xml. 
  21.          $ch = curl_init()
  22.   
  23.          // set URL and other appropriate options 
  24.          curl_setopt($ch, CURLOPT_URL, $the_thirdparty_url)// where to send the variables 
  25.          curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: text/xml'))
  26.          curl_setopt($ch, CURLOPT_HEADER, 0)
  27.          curl_setopt($ch, CURLOPT_POST, 1)
  28.          curl_setopt($ch, CURLOPT_POSTFIELDS, $the_message_xml)
  29.          curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0)
  30.          curl_setopt($ch, CURLOPT_REFERER, 'receive.php');  // my receiving file 
  31.          curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1)
  32.          $ch_result = curl_exec($ch)
  33.          curl_close($ch)
  34.   
  35.          // Print CURL result. 
  36.          echo $ch_result
  37.  ?> 

Script #3: process returned data
copyraw
<?php
        /*
        * XML Server.
        */
        // We use php://input to get the raw $_POST results.
        $xml_post = file_get_contents('php://input');

        // If we receive data, save it.
        if ($xml_post) {
                $xml_file = 'received_xml_' . date('Y_m_d-H-i-s') . '.xml';
                $fh       = fopen($xml_file, 'w') or die();
                fwrite($fh, $xml_post);
                fclose($fh);

                // Return, as we don't want to cause a loop by processing the code below.
                return;
        }
?>
  1.  <?php 
  2.          /* 
  3.          * XML Server. 
  4.          */ 
  5.          // We use php://input to get the raw $_POST results. 
  6.          $xml_post = file_get_contents('php://input')
  7.   
  8.          // If we receive data, save it. 
  9.          if ($xml_post) { 
  10.                  $xml_file = 'received_xml_' . date('Y_m_d-H-i-s') . '.xml'
  11.                  $fh       = fopen($xml_file, 'w') or die()
  12.                  fwrite($fh, $xml_post)
  13.                  fclose($fh)
  14.   
  15.                  // Return, as we don't want to cause a loop by processing the code below. 
  16.                  return; 
  17.          } 
  18.  ?> 

UPDATE 2015 - Implementation
Finally I opted with a single PHP script that receives the variables from a mobile application, talks to the third-party API, parses the response, and returns the data to the mobile app. Additionally, the client wanted the reply to mobile in JSON format so we will extract the values with SIMPLEXML_LOAD_STRING (as of PHP 5), store the values in an array for easy encoding to JSON. This is a cut-down version of my final script:
copyraw
// set headers for JSON file
header('Content-Type: text/javascript; charset=utf8');
header('Access-Control-Allow-Origin: http://mobile.joellipman.com/');
header('Access-Control-Max-Age: 3628800');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE');

// the posted XML
$the_message_xml="<?xml version='1.0' encoding='UTF-8' ?><message><request><my_xml_string /></request></message>";

// We send XML via cURL using POST with a http header of text/xml.
$ch = curl_init();

// set URL and other appropriate options
curl_setopt($ch, CURLOPT_URL, "http://api.myexample.com"); // action where to POST the variables
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: text/xml'));
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $the_message_xml);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
curl_setopt($ch, CURLOPT_REFERER, 'receive.php');  // my receiving file
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

// execute and store
$ch_result = curl_exec($ch);
curl_close($ch);

// Store cURL result
$api_result = simplexml_load_string($ch_result) or die("Error: Cannot create object");

// Declare main array to store all variables
$reply_array = array();

// parse out some global values we want from XML
if($api_result->reply!=null){

        // our own script reply to the request
        $reply_array["sys"] = array("message"=>"ok", "code"=>200);

        // parse and store the attribute value "entry_count" of element "room_rate_list".
        // NOTE: also declare the datatype or this won't work!
        $entry_count = (int) $api_result->reply->room_rate_list['entry_count'];

        // parse and store the attribute value "currency" of first entry in element "room_rate_list".
        // NOTE: declare the datatype for string as (string) or this won't work!
        $api_currency = (string) $api_result->reply->room_rate_list->room_rate[0]['currency'];

        $reply_array["data"] = array("entry_count"=>$entry_count, "currency"=>$api_currency);

} else {

        // our own script reply to the request
        $reply_array["sys"] = array("message"=>"ERROR", "code"=>404);

}

// return and print the JSON
$json_array = json_encode($reply_array);
echo $json_array;


// field validation, variable formatting/transform rules, and user logging are also done via this script.
  1.  // set headers for JSON file 
  2.  header('Content-Type: text/javascript; charset=utf8')
  3.  header('Access-Control-Allow-Origin: http://mobile.joellipman.com/')
  4.  header('Access-Control-Max-Age: 3628800')
  5.  header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE')
  6.   
  7.  // the posted XML 
  8.  $the_message_xml="<?xml version='1.0' encoding='UTF-8' ?><message><request><my_xml_string /></request></message>"
  9.   
  10.  // We send XML via cURL using POST with a http header of text/xml. 
  11.  $ch = curl_init()
  12.   
  13.  // set URL and other appropriate options 
  14.  curl_setopt($ch, CURLOPT_URL, "http://api.myexample.com")// action where to POST the variables 
  15.  curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: text/xml'))
  16.  curl_setopt($ch, CURLOPT_HEADER, 0)
  17.  curl_setopt($ch, CURLOPT_POST, 1)
  18.  curl_setopt($ch, CURLOPT_POSTFIELDS, $the_message_xml)
  19.  curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0)
  20.  curl_setopt($ch, CURLOPT_REFERER, 'receive.php');  // my receiving file 
  21.  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1)
  22.   
  23.  // execute and store 
  24.  $ch_result = curl_exec($ch)
  25.  curl_close($ch)
  26.   
  27.  // Store cURL result 
  28.  $api_result = simplexml_load_string($ch_result) or die("Error: Cannot create object")
  29.   
  30.  // Declare main array to store all variables 
  31.  $reply_array = array()
  32.   
  33.  // parse out some global values we want from XML 
  34.  if($api_result->reply!=null){ 
  35.   
  36.          // our own script reply to the request 
  37.          $reply_array["sys"] = array("message"=>"ok", "code"=>200)
  38.   
  39.          // parse and store the attribute value "entry_count" of element "room_rate_list". 
  40.          // NOTE: also declare the datatype or this won't work! 
  41.          $entry_count = (int) $api_result->reply->room_rate_list['entry_count']
  42.   
  43.          // parse and store the attribute value "currency" of first entry in element "room_rate_list". 
  44.          // NOTE: declare the datatype for string as (string) or this won't work! 
  45.          $api_currency = (string) $api_result->reply->room_rate_list->room_rate[0]['currency']
  46.   
  47.          $reply_array["data"] = array("entry_count"=>$entry_count, "currency"=>$api_currency)
  48.   
  49.  } else { 
  50.   
  51.          // our own script reply to the request 
  52.          $reply_array["sys"] = array("message"=>"ERROR", "code"=>404)
  53.   
  54.  } 
  55.   
  56.  // return and print the JSON 
  57.  $json_array = json_encode($reply_array)
  58.  echo $json_array
  59.   
  60.   
  61.  // field validation, variable formatting/transform rules, and user logging are also done via this script. 

Issues?
- Internal Server Error - I can get this when the third-party API doesn't return expected XML. Ensure that CURLOPT_POSTFIELDS is a string of paired values (ie. key1=value1&key2=value2&key3=value3).
- DataType or value is blank - the data that gets parsed with SIMPLEXML_LOAD_STRING needs to have each variable's datatype declared or it will return as an object. Prefix with (int) for numbers/integers and (string) for strings.

Category: API Miscellaneous :: Article: 601

Credit where Credit is Due:


Feel free to copy, redistribute and share this information. All that we ask is that you attribute credit and possibly even a link back to this website as it really helps in our search engine rankings.

Disclaimer: The information on this website is provided without warranty and any content is merely the opinion of the author. Please try to test in development environments prior to adapting them to your production environments. The articles are written in good faith and, at the time of print, are working examples used in a commercial setting.

Thank you for visiting and, as always, we hope this website was of some use to you!

Kind Regards,

Joel Lipman
www.joellipman.com

Related Articles

Joes Revolver Map

Accreditation

Badge - Certified Zoho Creator Associate
Badge - Certified Zoho Creator Associate

Donate & Support

If you like my content, and would like to support this sharing site, feel free to donate using a method below:

Paypal:
Donate to Joel Lipman via PayPal

Bitcoin:
Donate to Joel Lipman with Bitcoin - Valid till 8 May 2022 3QnhmaBX7LQSRsC9hh6Je9rGQKEGNQNfPb
© 2021 Joel Lipman .com. All Rights Reserved.