980

I want to return JSON from a PHP script.

Do I just echo the result? Do I have to set the Content-Type header?

dakab
  • 4,576
  • 8
  • 38
  • 56
Scott Nicol
  • 10,038
  • 3
  • 13
  • 8

19 Answers19

1780

While you're usually fine without it, you can and should set the Content-Type header:

<?php
$data = /** whatever you're serializing **/;
header('Content-Type: application/json');
echo json_encode($data);

If I'm not using a particular framework, I usually allow some request params to modify the output behavior. It can be useful, generally for quick troubleshooting, to not send a header, or sometimes print_r the data payload to eyeball it (though in most cases, it shouldn't be necessary).

D. Schreier
  • 1,462
  • 1
  • 17
  • 29
timdev
  • 57,660
  • 6
  • 74
  • 90
  • 10
    just in case: you should use header() commands only in addition with output buffering to avoid "headers already sent" warnings – Kevin Jul 02 '14 at 16:51
  • 1
    It's good practice to always put your header() statements as far to the top of the page as possible so that when you add more code, you aren't tempted to insert code before the header() statement which could break things if you start outputting. – Mikepote Oct 13 '14 at 13:17
  • 6
    The php file have to be encoded in UTF-8 without BOM :) – Krzysztof Kalinowski Nov 20 '14 at 14:57
  • 252
    `header('Content-type:application/json;charset=utf-8');` – Timo Huovinen Aug 20 '15 at 12:46
  • 17
    @mikepote I actually don't think it's necessary to have the header command at the top of the PHP file. If you're inadvertently spitting out stuff and that's tripping up your header command, you just need to fix your code because it's broken. – Halfstop Sep 10 '15 at 18:02
  • @Halfstop sure, it's just recommended for ease of debugging, but I dont always do it either. – Mikepote Sep 12 '15 at 16:45
  • 1
    Adding a `header` to a PHP script is the correct way to do things, You do not want to pass a HTML type document to something expecting JSON/JS... Simple.... While something like jQuery will auto parse, not everything does... If you supply dynamic content via PHP, always post the headers if you can.. Debugging, i normally use a `isset($_REQUEST['debug'])` and do something like `echo "
    ".print_r($oRET,true)."
    ";`
    – Angry 84 Nov 20 '15 at 05:15
  • Routinely, the last two lines of my action page that returns a json string is the header statement, followed by the `echo json_encode($data);`, exactly as @timdev shows it. The only thing I do differently (and it's inconsequential to the problem) is I put my `$data = array();` at the top of my php page. I actually want my Ajax return to break. If you use something like `.fail(function( jqXHR, textStatus ) { alert( "Request failed: " + jqXHR + ", " + textStatus ); });` in your ajax block, it will tell you what went wrong, and even where. Eventually you will make your action page bullet proof. – TARKUS Jun 14 '16 at 18:40
  • 10
    @KrzysztofKalinowski no, the PHP file doesn't need to be UTF-8 encoded. the output MUST be UTF-8 encoded. Those wrong statements doesn't help non-experienced users to learn how to avoid things from breaking, but it helps to grow myths on them and never learning which role does encodings play on streams and how they work. – Áxel Costas Pena Oct 26 '16 at 11:58
  • 2
    @timdev don't forget to call `exit();` of `die();` right after `echo json_encode($data);`, otherwise random data from your script (e.g profiling) might get appended to your json response. – Binar Web Jun 16 '18 at 08:59
  • @TimoHuovinen the default encoding is UTF8, always. – Yousha Aleayoub Feb 06 '20 at 19:33
  • 1
    @YoushaAleayoub You are right, the charset is redundant and ignored. – Timo Huovinen Feb 06 '20 at 20:20
  • 1
    "doesn't need to be UTF-8 encoded". This is **not true** if you have literal strings with special characters in your PHP file. Without your PHP file being encoded in UTF-8, the following code will return incorrect characters: ` – RWC May 24 '20 at 16:00
  • Works like a calm. Thank you – Anjana Silva Oct 24 '20 at 13:45
133

A complete piece of nice and clear PHP code returning JSON is:

$option = $_GET['option'];

if ( $option == 1 ) {
    $data = [ 'a', 'b', 'c' ];
    // will encode to JSON array: ["a","b","c"]
    // accessed as example in JavaScript like: result[1] (returns "b")
} else {
    $data = [ 'name' => 'God', 'age' => -1 ];
    // will encode to JSON object: {"name":"God","age":-1}  
    // accessed as example in JavaScript like: result.name or result['name'] (returns "God")
}

header('Content-type: application/json');
echo json_encode( $data );
Áxel Costas Pena
  • 4,754
  • 5
  • 26
  • 53
aesede
  • 5,006
  • 2
  • 32
  • 32
52

According to the manual on json_encode the method can return a non-string (false):

Returns a JSON encoded string on success or FALSE on failure.

When this happens echo json_encode($data) will output the empty string, which is invalid JSON.

json_encode will for instance fail (and return false) if its argument contains a non UTF-8 string.

This error condition should be captured in PHP, for example like this:

<?php
header("Content-Type: application/json");

// Collect what you need in the $data variable.

$json = json_encode($data);
if ($json === false) {
    // Avoid echo of empty string (which is invalid JSON), and
    // JSONify the error message instead:
    $json = json_encode(["jsonError" => json_last_error_msg()]);
    if ($json === false) {
        // This should not happen, but we go all the way now:
        $json = '{"jsonError":"unknown"}';
    }
    // Set HTTP response status code to: 500 - Internal Server Error
    http_response_code(500);
}
echo $json;
?>

Then the receiving end should of course be aware that the presence of the jsonError property indicates an error condition, which it should treat accordingly.

In production mode it might be better to send only a generic error status to the client and log the more specific error messages for later investigation.

Read more about dealing with JSON errors in PHP's Documentation.

Timo Huovinen
  • 46,329
  • 33
  • 128
  • 127
trincot
  • 211,288
  • 25
  • 175
  • 211
  • 2
    There's no `charset` parameter for JSON; see the note at the end of https://tools.ietf.org/html/rfc8259#section-11: "No 'charset' parameter is defined for this registration. Adding one really has no effect on compliant recipients." (JSON must be transmitted as UTF-8 per https://tools.ietf.org/html/rfc8259#section-8.1, so specifying that it's encoded as UTF-8 is a bit redundant.) – Patrick Dark Feb 10 '18 at 06:26
  • 1
    Thanks for highlighting that, @PatrickDark. Redundant `charset` parameter removed from HTTP header string. – trincot Feb 10 '18 at 07:53
40

Try json_encode to encode the data and set the content-type with header('Content-type: application/json');.

HumbleOne
  • 150
  • 9
thejh
  • 41,293
  • 15
  • 89
  • 105
17

Set the content type with header('Content-type: application/json'); and then echo your data.

Brad Mace
  • 26,280
  • 15
  • 94
  • 141
17

It is also good to set the access security - just replace * with the domain you want to be able to reach it.

<?php
header('Access-Control-Allow-Origin: *');
header('Content-type: application/json');
    $response = array();
    $response[0] = array(
        'id' => '1',
        'value1'=> 'value1',
        'value2'=> 'value2'
    );

echo json_encode($response); 
?>

Here is more samples on that: how to bypass Access-Control-Allow-Origin?

Dr. Aaron Dishno
  • 1,609
  • 1
  • 25
  • 23
  • What does it mean if this doesn't work? For example, to restrict only to calls from CodePen, I tried `header('Access-Control-Allow-Origin: https://cdpn.io');`, but I can still load the page from my own browser. – ashleedawg Jul 02 '20 at 13:56
  • it is used for blocking cross scripting (one script calling another page). So you will be able to load it directly from your browser, but you cant load it from another domain using script. – Dr. Aaron Dishno Jul 08 '20 at 18:46
15

This question got many answers but none cover the entire process to return clean JSON with everything required to prevent the JSON response to be malformed.


/*
 * returnJsonHttpResponse
 * @param $success: Boolean
 * @param $data: Object or Array
 */
function returnJsonHttpResponse($success, $data)
{
    // remove any string that could create an invalid JSON 
    // such as PHP Notice, Warning, logs...
    ob_clean();

    // this will clean up any previously added headers, to start clean
    header_remove(); 

    // Set the content type to JSON and charset 
    // (charset can be set to something else)
    header("Content-type: application/json; charset=utf-8");

    // Set your HTTP response code, 2xx = SUCCESS, 
    // anything else will be error, refer to HTTP documentation
    if ($success) {
        http_response_code(200);
    } else {
        http_response_code(500);
    }
    
    // encode your PHP Object or Array into a JSON string.
    // stdClass or array
    echo json_encode($data);

    // making sure nothing is added
    exit();
}

References:

response_remove

ob_clean

Content-type JSON

HTTP Codes

http_response_code

json_encode

sonique
  • 3,402
  • 2
  • 20
  • 33
  • 1
    thnx for the ob_clean reference. I had a leading line that was jacking up my fetch response.json() calls. – Chris Love Aug 20 '20 at 18:47
10

A simple function to return a JSON response with the HTTP status code.

function json_response($data=null, $httpStatus=200)
{
    header_remove();

    header("Content-Type: application/json");

    http_response_code($httpStatus);

    echo json_encode($data);

    exit();
}
Dan
  • 1,799
  • 19
  • 18
  • 1
    `header_remove`, and explicitly setting the http response is a good idea; although setting status and then http_response seems redundant. Might also want to add an `exit` statement to the end. I combined your function with @trincot 's: https://stackoverflow.com/a/35391449/339440 – Stephen R Nov 18 '19 at 17:25
9
<?php
$data = /** whatever you're serializing **/;
header("Content-type: application/json; charset=utf-8");
echo json_encode($data);
?>
Joyal
  • 2,119
  • 2
  • 26
  • 34
7

As said above:

header('Content-Type: application/json');

will make the job. but keep in mind that :

  • Ajax will have no problem to read json even if this header is not used, except if your json contains some HTML tags. In this case you need to set the header as application/json.

  • Make sure your file is not encoded in UTF8-BOM. This format add a character in the top of the file, so your header() call will fail.

Tom Ah
  • 499
  • 5
  • 4
3

If you need to get json from php sending custom information you can add this header('Content-Type: application/json'); before to print any other thing, So then you can print you custome echo '{"monto": "'.$monto[0]->valor.'","moneda":"'.$moneda[0]->nombre.'","simbolo":"'.$moneda[0]->simbolo.'"}';

jacr1614
  • 1,040
  • 2
  • 12
  • 22
3

The answer to your question is here,

It says.

The MIME media type for JSON text is application/json.

so if you set the header to that type, and output your JSON string, it should work.

Community
  • 1
  • 1
Codemwnci
  • 51,224
  • 10
  • 90
  • 127
1

Yeah, you'll need to use echo to display output. Mimetype: application/json

Nev Stokes
  • 6,578
  • 3
  • 35
  • 40
1

This is a simple PHP script to return male female and user id as json value will be any random value as you call the script json.php .

Hope this help thanks

<?php
header("Content-type: application/json");
$myObj=new \stdClass();
$myObj->user_id = rand(0, 10);
$myObj->male = rand(0, 5);
$myObj->female = rand(0, 5);
$myJSON = json_encode($myObj);
echo $myJSON;
?>
A.A.
  • 347
  • 1
  • 12
1

If you query a database and need the result set in JSON format it can be done like this:

<?php

$db = mysqli_connect("localhost","root","","mylogs");
//MSG
$query = "SELECT * FROM logs LIMIT 20";
$result = mysqli_query($db, $query);
//Add all records to an array
$rows = array();
while($row = $result->fetch_array()){
    $rows[] = $row;
}
//Return result to jTable
$qryResult = array();
$qryResult['logs'] = $rows;
echo json_encode($qryResult);

mysqli_close($db);

?>

For help in parsing the result using jQuery take a look at this tutorial.

Sᴀᴍ Onᴇᴌᴀ
  • 7,491
  • 8
  • 27
  • 56
Eyece
  • 21
  • 2
0

An easy way to format your domain objects to JSON is to use the Marshal Serializer. Then pass the data to json_encode and send the correct Content-Type header for your needs. If you are using a framework like Symfony, you don't need to take care of setting the headers manually. There you can use the JsonResponse.

For example the correct Content-Type for dealing with Javascript would be application/javascript.

Or if you need to support some pretty old browsers the safest would be text/javascript.

For all other purposes like a mobile app use application/json as the Content-Type.

Here is a small example:

<?php
...
$userCollection = [$user1, $user2, $user3];

$data = Marshal::serializeCollectionCallable(function (User $user) {
    return [
        'username' => $user->getUsername(),
        'email'    => $user->getEmail(),
        'birthday' => $user->getBirthday()->format('Y-m-d'),
        'followers => count($user->getFollowers()),
    ];
}, $userCollection);

header('Content-Type: application/json');
echo json_encode($data);
Kingson
  • 149
  • 5
0

Whenever you are trying to return JSON response for API or else make sure you have proper headers and also make sure you return a valid JSON data.

Here is the sample script which helps you to return JSON response from PHP array or from JSON file.

PHP Script (Code):

<?php

// Set required headers
header('Content-Type: application/json; charset=utf-8');
header('Access-Control-Allow-Origin: *');

/**
 * Example: First
 *
 * Get JSON data from JSON file and retun as JSON response
 */

// Get JSON data from JSON file
$json = file_get_contents('response.json');

// Output, response
echo $json;

/** =. =.=. =.=. =.=. =.=. =.=. =.=. =.=. =.=. =.=. =.  */

/**
 * Example: Second
 *
 * Build JSON data from PHP array and retun as JSON response
 */

// Or build JSON data from array (PHP)
$json_var = [
  'hashtag' => 'HealthMatters',
  'id' => '072b3d65-9168-49fd-a1c1-a4700fc017e0',
  'sentiment' => [
    'negative' => 44,
    'positive' => 56,
  ],
  'total' => '3400',
  'users' => [
    [
      'profile_image_url' => 'http://a2.twimg.com/profile_images/1285770264/PGP_normal.jpg',
      'screen_name' => 'rayalrumbel',
      'text' => 'Tweet (A), #HealthMatters because life is cool :) We love this life and want to spend more.',
      'timestamp' => '{{$timestamp}}',
    ],
    [
      'profile_image_url' => 'http://a2.twimg.com/profile_images/1285770264/PGP_normal.jpg',
      'screen_name' => 'mikedingdong',
      'text' => 'Tweet (B), #HealthMatters because life is cool :) We love this life and want to spend more.',
      'timestamp' => '{{$timestamp}}',
    ],
    [
      'profile_image_url' => 'http://a2.twimg.com/profile_images/1285770264/PGP_normal.jpg',
      'screen_name' => 'ScottMili',
      'text' => 'Tweet (C), #HealthMatters because life is cool :) We love this life and want to spend more.',
      'timestamp' => '{{$timestamp}}',
    ],
    [
      'profile_image_url' => 'http://a2.twimg.com/profile_images/1285770264/PGP_normal.jpg',
      'screen_name' => 'yogibawa',
      'text' => 'Tweet (D), #HealthMatters because life is cool :) We love this life and want to spend more.',
      'timestamp' => '{{$timestamp}}',
    ],
  ],
];

// Output, response
echo json_encode($json_var);

JSON File (JSON DATA):

{
    "hashtag": "HealthMatters", 
    "id": "072b3d65-9168-49fd-a1c1-a4700fc017e0", 
    "sentiment": {
        "negative": 44, 
        "positive": 56
    }, 
    "total": "3400", 
    "users": [
        {
            "profile_image_url": "http://a2.twimg.com/profile_images/1285770264/PGP_normal.jpg", 
            "screen_name": "rayalrumbel", 
            "text": "Tweet (A), #HealthMatters because life is cool :) We love this life and want to spend more.", 
            "timestamp": "{{$timestamp}}"
        }, 
        {
            "profile_image_url": "http://a2.twimg.com/profile_images/1285770264/PGP_normal.jpg", 
            "screen_name": "mikedingdong", 
            "text": "Tweet (B), #HealthMatters because life is cool :) We love this life and want to spend more.", 
            "timestamp": "{{$timestamp}}"
        }, 
        {
            "profile_image_url": "http://a2.twimg.com/profile_images/1285770264/PGP_normal.jpg", 
            "screen_name": "ScottMili", 
            "text": "Tweet (C), #HealthMatters because life is cool :) We love this life and want to spend more.", 
            "timestamp": "{{$timestamp}}"
        }, 
        {
            "profile_image_url": "http://a2.twimg.com/profile_images/1285770264/PGP_normal.jpg", 
            "screen_name": "yogibawa", 
            "text": "Tweet (D), #HealthMatters because life is cool :) We love this life and want to spend more.", 
            "timestamp": "{{$timestamp}}"
        }
    ]
}

JSON Screeshot:

enter image description here

Neeraj Singh
  • 5,808
  • 2
  • 33
  • 33
0

In case you're doing this in WordPress, then there is a simple solution:

add_action( 'parse_request', function ($wp) {
    $data = /* Your data to serialise. */
    wp_send_json_success($data); /* Returns the data with a success flag. */
    exit(); /* Prevents more response from the server. */
})

Note that this is not in the wp_head hook, which will always return most of the head even if you exit immediately. The parse_request comes a lot earlier in the sequence.

Paul F. Wood
  • 802
  • 10
  • 14
-1

You can use this little PHP library. It sends the headers and give you an object to use it easily.

It looks like :

<?php
// Include the json class
include('includes/json.php');

// Then create the PHP-Json Object to suits your needs

// Set a variable ; var name = {}
$Json = new json('var', 'name'); 
// Fire a callback ; callback({});
$Json = new json('callback', 'name'); 
// Just send a raw JSON ; {}
$Json = new json();

// Build data
$object = new stdClass();
$object->test = 'OK';
$arraytest = array('1','2','3');
$jsonOnly = '{"Hello" : "darling"}';

// Add some content
$Json->add('width', '565px');
$Json->add('You are logged IN');
$Json->add('An_Object', $object);
$Json->add("An_Array",$arraytest);
$Json->add("A_Json",$jsonOnly);

// Finally, send the JSON.

$Json->send();
?>
Alexis Paques
  • 1,496
  • 12
  • 25