JSON object in asynchronous HTTP request

JSON object in asynchronous HTTP request

Created:23 Feb 2020 16:24:10 , in  Web development

Most of the time when there is a need for a HTTP client, a browser for example, to exchange data with a HTTP server, like Apache with loaded PHP module, the client sends the data in the form of a URL encoded string to the server using POST or GET (asynchronous) request. The data becomes available to PHP module through its global $_GET/$_POST/S_REQUEST arrays. Nice and simple. However, this approach does not work if there is a JSON object to be sent over. Neither of the arrays is populated. Instead, the data is available to PHP module, through its standard input stream.

In this article, I look how to transfer a JSON object from a JavaScript script running in a browser to a PHP enabled backend, and how to read the data from a PHP's standard input stream.

To demonstrate the process I have written a Vue.js and PHP based utility, which encodes a string using SHA1 and md5 PHP functions. The program consists of a frontend interface, which allows to input a piece of text, and a function name (md5 or sha1) to be used to encode the text. Once both are set, they get assigned to a separate property in a JavaScript/JSON object. Then, the object is encoded to a string and sent asynchronously to a PHP powered backend script. The script decodes the string and turns it into a PHP object. In the final step, PHP encodes the text using user choose one-way encoding function (aforementioned SHA1 or md5) and returns the transformed message back to the client to be written to the screen.

You can play with the program here.

Frontend HTML and Vue.js interface


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>One way string encoder</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

</head>
<body>

<div id="vueOneWayStringEncoder">
 <!-- name of the component is hyphened and lowerscased --> 
 <sha1-md5-encoder></sha1-md5-encoder>
</div>

<script src = "vuePHPoneWayEncoder.js"></script>

</body>
</html>

Thanks to Vue.js, HTML mark-up for this program is nice and short. Almost all the JavaScript functionality is contained in a Vue.js component described below and stored in file vuePHPoneWayEncoder.js :


var url = '/vuePHPoneWayEncoder.php';
Vue.component('sha1Md5Encoder',{

  data:function(){
    return {
      error: '',
      text : '',
      textMaxLength : 500,
      encoder: 'md5',
      encoders : ['sha1','md5'],
      defaultEncoder:'sha1',
      responseHTML:''
    }
  },

  methods:{
    validate : function(){
      var valid = true;
      // quick validation on text 
      if(this.text == ''){
        this.error = 'Text is too short!'
        valid = false;
      } else { 
         if(this.text.length > this.textMaxLength){
           this.error = 'Text is too long! Maximum length is '+this.textMaxLength+'.' 
           valid = false;  
         }
      }
      return valid;
    },

    clear : function(){
      this.text = '';
      this.responseHTML = '';
    },

    encode : async function(resource){

      this.error = '';

      if(!this.validate()){
        return;
      }

      payload = {
        'text': this.text,
        'encoder': this.encoder   
      }

      // fetch function based request 
      await fetch(url, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-REQUESTED-WITH': 'XMLHttpRequest'
        },
        body: JSON.stringify(payload)
      }).then((response) => response.text()).then((data) => {
        this.responseHTML = data;
      }).catch((error) => {
        this.responseHTML = 'Error: '+ error +'!'
      });
    }
  },

  computed:{
    textLengthRemained:function(){
      return this.textMaxLength - this.text.length;
    }
  },

  template:'<div> \
    <p>{{error}}</p> \
    <div v-html="responseHTML" v-bind:style="{color:\'#99aaff\'}"></div> \
    <p>Character count: <span v-bind:style="{color:\'orange\'}">{{ textLengthRemained }}</span> left.</p> \
    <p class="plain-text-add"> \
     <label>Text:</label><br /> \
      <textarea v-model.trim="text" v-bind:maxlength="textMaxLength" rows=10 cols=40></textarea> \
    <p> \
    <p class="encoder-select"> \
      <label>Encoding function:</label><br />\
      <select v-model="encoder"> \
        <option v-for="enc in encoders" v-bind:value="enc" >{{ enc.toUpperCase() }}</option> \
      </select> \
    </p> \
      <button v-on:click="encode">Encode</button> \
      <button v-on:click="clear">Clear Text</button> \
    </p> \
  </div>'
});

new Vue({
   el: '#vueOneWayStringEncoder'
});

The code below prepares a JSON object to be sent over to a server in the for of a string, and sets data content type to application/json.


headers: {
  // let server know contnet type it is receiving  
  'Content-Type': 'application/json',
  'X-REQUESTED-WITH': 'XMLHttpRequest'
},
// turn payload into a string
body: JSON.stringify(payload)

JSON object on the backend

As mentioned earlier, data with content-type application/json will be available to PHP through its standard input stream. The code below shows how to extract it from there and turn it into a usable PHP object.


// read data from PHP's standard input
$input = file_get_contents('php://input');
if(isset($input) and !empty($input)){
  $output = '';

  $text = ''; 
  $encoder = '';

  // turn string encoded JSON object into a PHP object
  $input_obj = json_decode($input);
  if(isset($input_obj) and is_object($input_obj)){

    if(isset($input_obj -> text)){ 
      $text = trim(strip_tags($input_obj -> text));
    }
   
    if(isset($input_obj -> encoder)){
      $encoder = trim(strip_tags($input_obj -> encoder)) == 'sha1' ? 'sha1' : 'md5'; 
    }
  }

  if(!empty($text)){
    // encode
    if($encoder == 'md5'){
      $output = md5($text);
    }else{
      $output = sha1($text); 
    }
  }

  echo $output;  
  die();
} 

You use file_get_contents() to read data from PHP's standard input:


$input = file_get_contents('php://input');

and you use json_decode(data) to transform JSON encoded string into a PHP object.


$input_obj = json_decode($input);

The rest of the script makes use of the input data to produce output and return it back to frontend, where it is written to the screen.

Conclusion

An important takeaway from this article is, that if data is passed with Content-Type header set to application/json, backend script receives it through PHP's standard input stream. Once extracted from standard input, the data has to be transformed from a string to a PHP object (or associative array) to be usable.

The need for sending and receiving encoded JSON objects is very common today. Not just browsers and servers use the technique to exchange information. To employ the idea in few lines of code you might want to take a look at cURL and json_pp on the command line utilities.

This post was updated on 23 Feb 2020 20:28:09

Tags:  JavaScript ,  php ,  vue.js 


Author, Copyright and citation

Author

Sylwester Wojnowski

Author of the above article, Sylwester Wojnowski, enjoys sWWW writing computer code in PHP, JavaScript and BASH, and some other things he wrote more on on the About page of this website.

Copyrights

©Copyright, 2020 Sylwester Wojnowski. This article may not be reproduced or published as a whole or in parts without permission from the author. If you share it, please give author credit and do not remove embedded links.

Computer code, if present in the article, is excluded from the above and licensed under GPLv3.

Citation

Cite this article as:

Wojnowski, Sylwester. "JSON object in asynchronous HTTP request." From sWWW - Code For The Web . https://wojnowski.net.pl//main/index/json-object-in-asynchronous-http-request