PHP - Posting JSON via file_get_contents

This is the code I always use and it looks pretty similar (though this is of course for x-www-form-urlencoded). Perhaps your username:key needs to be base64_encode'd.

function file_post_contents($url, $data, $username = null, $password = null)
{
    $postdata = http_build_query($data);

    $opts = array('http' =>
        array(
            'method'  => 'POST',
            'header'  => 'Content-type: application/x-www-form-urlencoded',
            'content' => $postdata
        )
    );
    
    if($username && $password)
    {
        $opts['http']['header'] .= ("Authorization: Basic " . base64_encode("$username:$password"));
    }

    $context = stream_context_create($opts);
    return file_get_contents($url, false, $context);
}

The question was about json, why the accepted answer is about x-www-form?

Json has many cool stuff to struggle about, like utf8_encode

function my_utf8_encode(array $in): array
{
    foreach ($in as $key => $record) {
        if (is_array($record)) {
            $in[$key] = my_utf8_encode($record);
        } else {
            $in[$key] = utf8_encode($record);
        }
    }

    return $in;
}


function file_post_contents(string $url, array $data, string $username = null, string $password = null)
{
    $data     = my_utf8_encode($data);
    $postdata = json_encode($data);
    if (is_null($postdata)) {
        throw new \Exception('decoding params');
    }

    $opts = array('http' =>
        array(
            'method'  => 'POST',
            'header'  => 'Content-type: application/json',
            'content' => $postdata
        )
    );

    if (!is_null($username) && !is_null($password)) {
        $opts['http']['header'] .= "Authorization: Basic " . base64_encode("$username:$password");
    }

    $context = stream_context_create($opts);

    try {
        $response = file_get_contents($url, false, $context);
    } catch (\ErrorException $ex) {

        throw new \Exception($ex->getMessage(), $ex->getCode(), $ex->getPrevious());
    }
    if ($response === false) {

        throw new \Exception();
    }

    return $response;
}

The earlier response of

function file_post_contents($url, $data, $username = null, $password = null) {
$postdata = http_build_query($data);

$opts = array('http' =>
    array(
        'method'  => 'POST',
        'header'  => 'Content-type: application/x-www-form-urlencoded',
        'content' => $postdata
    )
);

if($username && $password)
{
    $opts['http']['header'] = ("Authorization: Basic " . base64_encode("$username:$password"));
}

$context = stream_context_create($opts);
return file_get_contents($url, false, $context);}

is incorrect. This function works sometimes, but it is inaccurate and will fail if you're not using the Content-type of application/x-www-form-urlencoded and you pass in a username and password.

It's working for the writer because application/x-www-form-urlencoded is the default Content-type, but his handling of the username and password is overwriting the earlier declaration of content type.

Here is the corrected function:

function file_post_contents($url, $data, $username = null, $password = null){
$postdata = http_build_query($data);

$opts = array('http' =>
    array(
        'method'  => 'POST',
        'header'  => "Content-type: application/x-www-form-urlencoded\r\n",
        'content' => $postdata
    )
);

if($username && $password)
{
    $opts['http']['header'] .= ("Authorization: Basic " . base64_encode("$username:$password")); // .= to append to the header array element
}

$context = stream_context_create($opts);
return file_get_contents($url, false, $context);}

Note the line: $opts['http']['header' .= (dot equals to append to the array element.)