Devmix
Devmix

Reputation: 1868

How to get JSON value from PHP?

I'm trying to get JSON value from PHP but if one of the property values contains a forward slash "/" it fails (I'm using GET to send data for this particular scenario).

Here's how I'm sending the data (This works just fine when I don't send "/").

UI side

const dataObj = {
      description: 'my / description',
      buyer: 'Mike Brown'
    };

const dataString = JSON.stringify(dataObj);

fetch(`http://localhost:8000/clients/${dataString}`)
    .then((response) => response.text())
      .then((responseData) => {
         ......
      });

PHP side:

Route::get('/clients/{data}', function($data) {
   // This line below fails ONLY if value of description property contains "/"
   // otherwise it works just fine
   $dataToBeSaved = json_decode($data, true); 

});

Yes, I did some research on json_decode, but nothing very clear. Can anyone point me on the right direction? Thanks a lot in advance!

Upvotes: 0

Views: 111

Answers (1)

Cully
Cully

Reputation: 6975

It's not really a good idea to pass JSON data in a URL, and you can't do it directly because it will contain characters that have meaning in URLs (e.g. /, ?, =, etc.). But if you must you have a couple options:

  1. You can URL encode the string and pass it as a parameter. This wouldn't work with the route you have, but it has the benefit of not needing to do anything else. You can just get the value from the parameter.

const dataObj = {
  description: 'my / description',
  buyer: 'Mike Brown'
};

const dataString = encodeURIComponent(JSON.stringify(dataObj));

console.log(`https://example.com/clients?data=${dataString}`);

  1. Or you can base64 encode it. This doesn't by default create URL safe strings, so you'll have to replace a few characters to make it URL safe. That also means you'll have to do the reverse on the server. This solution will work with your route.

const base64UrlEncode = function(str) {
  return btoa(str)
    // this character have meaning in URLs so we need to replace them
    // with something else. we'll have to reverse this on the server.
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=+$/, '');
};

const dataObj = {
  description: 'my / description',
  buyer: 'Mike Brown'
};

const dataString = base64UrlEncode(JSON.stringify(dataObj));

console.log(`https://example.com/clients/${dataString}`);

And to decode on the server:

function base64UrlDecode($encodedStr) {
  // undo the character replacements we did when encoding the string
  $unreplace1 = str_replace('-', '+', $encodedStr);
  $unreplace2 = str_replace('_', '/', $unreplace1);

  return base64_decode($unreplace2);
}

Route::get('/clients/{data}', function($data) {
   $dataToBeSaved = json_decode(base64UrlDecode($data), true); 
});

One thing to note with this solution is that web servers usually have a limit for the length of URLs (e.g. Apache's default is 8,177 characters). Also, there is usually a limit to the size of the "filename" in the URL (the last component in the path). Apache's default is 255 bytes/characters. So if your base64 encoded JSON is longer than 255 characters, it won't work. A better solution is to pass the data as part of the request body (i.e. as a POST request). That way you won't have a limit and you won't need to encode it beyond converting it to JSON.

Upvotes: 1

Related Questions