Sending data to a graph script with URI arguments (GET and POST)

In order to send data between different HTML pages (or to a specific page) there are two ways to do this. Either by including the parameters in the URI directly, (e.g. http://localhost/mygraph.php?d1=12) or by creating a POST request and send to a page. The details of these two methods are discussed below.

Note

There might be some confusion when to use the '&' and when to use '&' to separate variables in GET or POST requests.

When writing URL in HTML the string should always be written with a full entity encoding since the '&' is a special character indicating the start of an entity that ends with an ';'. So for example writing a URI in a HTML page should look like.

<a href="myscript.php?idx=1&amp;start=2009&amp;end=2010">

the browser will then correctly convert the URI to single '&' which is what should be sent to the server. When typing URI directly in the browser (or in any plain text file) one should of course always just use a single '&'

Tip

Use the method http_build_query() to build http queries from an array with keys and values.

Using GET arguments

GET arguments are the arguments that can be added as part of the URI. For example as

http://localhost/mygraph.php?id=12&start=20081223&end=20090115

PHP automatically places all given arguments in the "super global" array variable $_GET as an associative array.

There are a couple of things to note here

  • The values in the argument string in the URI must be URL encoded, this can easily be done with the PHP function urlencode() (See PHP Manual)

  • When the arguments are read from $_GET the must be un-quoted with a call to urldecode()

  • Some browsers restrict the length of the URI that they will read (typically < 2048bytes) which means that there is a limit on how much data can be send as URI arguments

  • Some browsers will allow the syntax "a[0]=10&a[1]=11&a[2]=12" i order to send the array (10,11,12)

This way of specifying the argument string is mostly useful when

  • The arguments are short

  • When the user should be able to bookmark an URI

  • When the data is not sensitive (since it can be seen in the URI)

  • When the graph should be viewable by clicking on a link (more on this when we compare the GET method with the POST method below)

The "best practice" of using this method is to send a short key (or id) to the graph script and the graph script itself will use this id to extract the real data from a DB (or a plain text file). This way the same core graph script can be used in various context to display wanted data.

Using a POST request

Warning

This is a fairly advanced topic and it is recommended to use the other methods of sending data to a script unless the specifications explicitly demands that a POST request is constructed. Furthermore this requires a very good understanding of HTTP request headers and the difference between server side and browser side so if you are not sure that you have the necessary background we strongly recommend to stay away from this method.

Two of the obvious restrictions with the GET method is that a) the length of the data is restricted and b) the data is visible directly in the URI. The other way to send data as part of the HTTP request is to use the POST method.

Unfortunately this is not as easy as just doing some magic and then we get the same functionality as with the GET method. Even some authors get this wrong in some very prominent PHP text books. Unfortunately it will take us too far to discuss all the details of HTTP request headers (as described in RFC2616) but we will explain the very basics.

First. let's state what an HTTP request is

  • A POST HTTP request is used to send data to a specified URI from a client. A client is normally a WEB-browser but can also (as we will use it) be a script that sends the request to the same or to another server. The data is URL encoded and passed in the body of the request. There is no theoretically limit on the length of the data.

A further common misunderstanding is that it is possible to use the PHP method header() in order to create a POST request. This is even given as an example in the notes to the header() method in the PHP manual (See PHP Manual). This is wrong. It is not possible to use the header() method to send a POST header. Trying to do this reveals a basic misunderstanding of the role of a server and client.

  • The header() method is used to send one or more headers from the server to the client (i.e. WEB-browser)

  • The HTTP POST request goes from the client (i.e. WEB-browser) to the server

Figure 13.1. Post vs. header() data direction

Post vs. header() data direction

Note that the image is greatly simplified to help illustrate the vital point on data direction. For example the post request shown to originate from a browser could originate from any client, for example another script taking the role of a client.


Hence it is never possible to "simulate" a POST call with the use of the header() function. There are basically three (correct) ways to simulate a POST request as described below.

Before we continue lets first recapitulate the most common use of a POST request, i.e. in a HTML form submission. When data is entered in a form on a HTML page and the user presses the "Submit" button the data from the form is packed as a POST request which is sent to the server at the specified URI (the action URI). The server will the reply back to the POST request (with the data sent back from the target of the post request) and the browser will show the reply in the window in place of the original HTML form page.

However there is a crucial difference when we do this manually from a script (running on the server) compared with the original form post data from the browser to the server. After issuing a POST request (originating from a HTML form) the browser automatically replaces the current page with the reply from the POST request as a "new" page (by default using the same target window as the request was made from).

This is not possible to do when sending a "fake" post request to a page since we are not the browser. Instead what we will see in the browser is the page sending the POST request, and not the target of the post request. The best we can accomplish is to show the reply inline in the calling page which are then shown in the browser.

This means that it is not possible to create a POST request and then somehow directly show the reply as the resulting image. Instead what we can do is to send the data to a image script (via a POST header) and then the graph script can write the image to a file that is accessible from the server.

So to summarize. What we can do with a post request is to send the data to a script b.php from a script a.php. The b.php can then execute some statements, for example creating a graph and store it on the server. This stored image can later be read by the a.php script, for example via a <img> tag.

How to create a POST request

There are in principle three ways of constructing a POST request to send data to a specified URI as shown below.

After we have made the request (with any of the three methods shown below) the server will reply back with the response created by the URI. This response is any output sent by the script we are sending our request to. Normally this should just be a return code indicating if the request was successful or not.

Remember that these are calls made from the script a.php running on server A to a script b.php running on server B. There are no browser involved in these calls apart from the initial request to run a.php. The figure below illustrates the first phase when the request is sent to the B side

Figure 13.2. The request phase of a POST header

The request phase of a POST header

1. The request is initially made by calling the a.php script, e.g. http://localhost/a.php in the browser

2. When the a.php script is executed it will create the POST header and call script b.php o the server B (could possibly be the same server). Since the browser is displaying script a.php we can never change that directly but we can display the reply from b.php in the page displayed by a.php


Figure 13.3. The reply phase of a POST request

The reply phase of a POST request

3. The b.php returns a reply by fir example echoing back a reply code

4. The script running the browser receives its final data (which is the reply from the b.php script) and then finish the original request started in step 1.


Note: All the sendPostData_vX() methods below assumes that the data is already urlencoded.

  1. Create a stream request.

    The advantage with this method is that it is available by default in PHP >= 4.3 and of course in PHP5,6 without the need to install additional libraries.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    <?php
    function sendPostData_v1($url, $data) { 
      $opts = array('http' => array(
        'method' => 'POST', 
        'header' => 
            "Content-type: application/x-www-form-urlencoded\r\n".
            "Content-Length: ".strlen($data)."\r\n".
        'content' => $data,
        ); 
      $stream = stream_context_create($opts); 
      $fp = fopen($url, 'rb', false, $stream); 
      if (!$fp) { // Some error handling } 
     
      // Find out what the page returns as its body 
      $reply = stream_get_contents($fp); 
      if ($reply === false) { // Some error handling } 
     
      return $reply; 
    } 
    ?>

  2. Open a socket directly and write to it

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    <?php
    function sendPostData_v2($url,$data,$port=80) { 
      $errno=-1;
      $errstr=''; 
      $fs = fsockopen($url,$port,$errno,$errstr); 
      if( $fs === false ) { // Some error handling } 
     
      $header = "POST $url HTTP/1.0\r\n"; 
      $header .= "Content-Type: application/x-www-form-urlencoded\r\n"; 
      $header .= "Content-Length: " . strlen($data) . "\r\n\r\n"; 
      fputs($fs, $header . $data ); 
     
      // Find out what the page returns as its body 
      $reply = ''; 
      while( !feof($fs) ) { 
        $reply .= fgets($fp,8192); 
      } 
      return $reply; 
    } 
    ?>

  3. Use CURL to handle all the necessary details

    Note 1: This requires that curl libraries are installed and that curl is enabled in the PHP installations.

    Note 2: Depending on the application there might be many more options that needs to be tweaked. The one used below are just the bare necessities.

    Note 3: Using CURL is the most general way to handle POST requests and simplifies the additional complexity if we want to add encryption (i.e. HTTPS) in the connection handling.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    
    <?php
    function sendPostData_v3($url,$data)
    {
      // Initialize and get the curl handle
      $ch = curl_init();
     
      // Include possible headers in the reply from the server as well
      curl_setopt( $ch, CURLOPT_HEADER, true );
     
      // Return the reply as a string from curl_exec() instead of directly to stdout
      curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
     
      // The URI we want to send the post data to
      curl_setopt($ch, CURLOPT_URL, $url);
     
      // Use the POST method
      curl_setopt($ch, CURLOPT_POST, true);
     
      // All the data to be sent
      curl_setopt($ch, CURLOPT_POSTFIELDS,$data);
     
      $reply = curl_exec ($ch);
     
      curl_close($ch);
      return $reply;
    }
    ?>