Blockfrost: Print JSON data on PHP page

I understand that with Blockfrost: “All endpoints return either a JSON object or an array.”

As a newbie to JSON, how can I display JSON data on a PHP page? Using “Query the latest epoch” as an example (Get Started with Blockfrost | Cardano Developer Portal), I have the following code (for which I have entered my real Blockfrost project_id):

$headers = array(‘http’=> array(
‘method’ => ‘GET’,
‘header’ => ‘project_id: 1234567890’
)
);
$context = stream_context_create($headers);
$json = file_get_contents(‘https://cardano-mainnet.blockfrost.io/api/v0/epochs/latest’, false, $context);
$parsedJson = json_decode($json);

How do I print data from that array onto a PHP page? Blockfrost is receiving my requests because the requests tally keeps going up. Do I have to use the “blockfrost-js” SDK (Blockfrost.io ~ API Documentation) to interpret the data? I am new to the JSON data structure and do not know how to extract/show the data.

You need to look up that API in the documentation and see what it returns.

/epochs/latest >> https://docs.blockfrost.io/#tag/Cardano-Epochs/paths/~1epochs~1latest/get

As per documentation it is:

{
  "epoch": 225,
  "start_time": 1603403091,
  "end_time": 1603835086,
  "first_block_time": 1603403092,
  "last_block_time": 1603835084,
  "block_count": 21298,
  "tx_count": 17856,
  "output": "7849943934049314",
  "fees": "4203312194",
  "active_stake": "784953934049314"
}

To inspect the response you can do: print_r($parsedJson); exit(); and it’ll output to the screen the structure of the parsed data.

To print something (epoch in this case) to the HTML page, and unless you are using some templating engine, simply do:
<?php echo htmlspecialchars($parsedJson['epoch']); ?>

2 Likes

Thank you so much for getting me on the right track.

The printing of epoch to the HTML page is not working for me:
echo htmlspecialchars($parsedJson['epoch']);

I even stripped out the htmlspecialchars in case that was the issue:
echo $parsedJson['epoch'];

Do you think I need to use the “stdClass Object” somehow as mentioned below?

The print line works well:
print_r($parsedJson); exit();
It returns just like you said, but with an additional line of “stdClass Object” above it. Not sure if this is useful or not:

stdClass Object
(
    [epoch] => 296
    [start_time] => 1634075091
    [end_time] => 1634507091
    [first_block_time] => 1634075099
    [last_block_time] => 1634125764
    [block_count] => 2401
    [tx_count] => 36751
    [output] => 3155010022103231
    [fees] => 7940213768
    [active_stake] => 23445774697795279
)

I don’t mean to be offensive but the PHP manual will be your best friend if you plan to do more PHP.

echo $parsedJson['epoch']; is bad because you want to sanitize the output. You never know what you might receive from a 3rd party, be it invalid HTML characters or injected code. Unless using a templating engine htmlspecialchars is your best friend.

json_decode($json); by default transforms the json into an object. To get an associative array use json_decode($json, true);

To summarize:

  • If using json_decode($json); then try echo htmlspecialchars($parsedJson->epoch).
  • If using json_decode($json, true); then try echo htmlspecialchars($parsedJson['epoch']).
2 Likes

I agree–I need to refer to the PHP manual. I also need to learn more basic programming concepts. I do appreciate you getting me on track here. I have been able to replicate all 3 examples from this page on my server: Get Started with Blockfrost | Cardano Developer Portal.

Do you know how I can display an image from IPFS? In their example for spacecoins, I have the following code:

echo "<hr noshade><p><strong>On-Chain Metadata -> Image :</strong></p><img src=\"";
echo htmlspecialchars($parsedJson->onchain_metadata->image);
echo "\">";

The following $parsedJson->onchain_metadata->image will return:
ipfs://Qmc44D9d8oaj38TtrXKXPYyWKpyPButDQtA9pVjBtb1qYV

Since ipfs is a protocol that web browsers do not process, is there a way to convert this URL to an http or https that will actually store and display an image?

You could do it like this (simple example):

echo '<img src="https://ipfs.io/ipfs/' . htmlspecialchars($parsedJson->onchain_metadata->image) . '" />';

In case you are working on some bigger project that needs to display many such images, I would consider caching them in order not to rely on the ipfs endpoint. If it’s a simple site I guess you can use the sample above.

1 Like

Thank you! I will explore caching if my project gets larger. Do you have a reference page where I can read up on it?

Your simple example works well, but the output is:
https://ipfs.io/ipfs/ipfs:/Qmc44D9d8oaj38TtrXKXPYyWKpyPButDQtA9pVjBtb1qYV

I will have to strip out the first 7 characters (“ipfs://”) since $parsedJson->onchain_metadata->image returns ipfs://Qmc44D9d8oaj38TtrXKXPYyWKpyPButDQtA9pVjBtb1qYV.

I am looking into PHP’s str_replace to see if I can figure it out.
https://www.php.net/manual/en/function.str-replace.php

Yes str_replace will work:
htmlspecialchars(str_replace('ipfs:/', '',$parsedJson->onchain_metadata->image))

1 Like

Excellent–that worked well.

Related to the above discussion and code, do you think there might be an easy way to display the date that the asset came into the hands of the current owner? Blockfrost has transactions (Blockfrost.io ~ API Documentation), but I am not sure how I would cross-reference a transaction to an asset.

One last request. Still learning and have been reading up on PHP’s foreach (PHP: foreach - Manual). How can I take this JSON array, apply a foreach to print the “unit” value? I have anonymized the unit values below. My goal is to echo the following for each item in the array: <a href="asset.php?asset=dde...">dde...</a><br />

I am using a different Blockfrost call (with the stake anonymized):
$json = file_get_contents('https://cardano-mainnet.blockfrost.io/api/v0/accounts/stake...', false, $context);

This is my array:

Array
(
    [0] => Array
        (
            [unit] => dde...
            [quantity] => 1
        )

    [1] => Array
        (
            [unit] => dde...
            [quantity] => 1
        )

    [2] => Array
        (
            [unit] => dde...
            [quantity] => 1
        )

    [3] => Array
        (
            [unit] => dde...
            [quantity] => 1
        )

    [4] => Array
        (
            [unit] => dde...
            [quantity] => 1
        )

    [5] => Array
        (
            [unit] => dde...
            [quantity] => 1
        )

    [6] => Array
        (
            [unit] => dde...
            [quantity] => 1
        )

    [7] => Array
        (
            [unit] => dde...
            [quantity] => 1
        )

    [8] => Array
        (
            [unit] => dde...
            [quantity] => 1
        )

    [9] => Array
        (
            [unit] => dde...
            [quantity] => 1
        )

)

You can do a simple foreach loop: https://www.php.net/manual/en/control-structures.foreach.php

Example1:

foreach($json as $item) {
    echo '<a href="asset.php?asset=' .urlencode($item['unit']). '">' .htmlspecialchars($item['unit']). '</a><br />';
}

Example2 (without echoing the whole line but using php tags to close and open php sections):

// php code....
foreach($json as $item) { ?>
<a href="asset.php?asset=<?= urlencode($item['unit']) ?>"><?= htmlspecialchars($item['unit']) ?></a><br />
<?php }
// php code....

Example3 (like 2 but with echo instead of shorthand <?=):

// php code....
foreach($json as $item) { ?>
<a href="asset.php?asset=<?php echo urlencode($item['unit']);?>"><?php echo htmlspecialchars($item['unit']); ?></a><br />
<?php }
// php code....

Whenever you find a Unix timestamp in the API response you can use:
echo date('FORMAT', $jsonData['some_timestamp_field']);
where format can be something from here: https://www.php.net/manual/en/datetime.formats.date.php

1 Like

Thank you. The foreach example1 worked very well! I will practice later with example2 and example 3. Since Blockfrost has a prepackaged query, I was thinking I could embed a foreach within a foreach so I can accomplish my goal to display the token image in the list of links:

Original (list of links):

$context = stream_context_create($headers);
$json = file_get_contents('https://cardano-mainnet.blockfrost.io/api/v0/accounts/' . htmlspecialchars($_GET['staking-address']) . '/addresses/assets?order=desc', false, $context);
$parsedJson = json_decode($json,true);

echo '<ol>';

foreach($parsedJson as $item) {
    echo '<li><a href="asset-v6-url-param.php?asset=' .urlencode($item['unit']). '">' .htmlspecialchars($item['unit']). '</a></li>';
}

echo '</ol>';

Addend an image to the above (via foreach within a foreach?)
I was thinking maybe $json should become $json2 and $parsedJson should become $parsedJson2. If I can embed a foreach within a foreach, I imagine each of the foreach iterations would count toward my request tally at Blockfrost. So, if the staking address has 100 assets, I just spent 100 requests.

$context = stream_context_create($headers);
$json = file_get_contents('https://cardano-mainnet.blockfrost.io/api/v0/assets/' . htmlspecialchars($_GET['asset']), false, $context);
$parsedJson = json_decode($json);

/* <div class="frame">...</div> */

echo '<img src="https://ipfs.io/ipfs/' . str_replace('ipfs:/', '', htmlspecialchars($parsedJson->onchain_metadata->image)) . '" />';

You want to do as few requests as possible. Maybe Blockfrost has some API that can return the aggregated data? Another solution would be caching locally the data that is not changing.

$json = file_get_contents(‘https://cardano-mainnet.blockfrost.io/api/v0/assets/’ . htmlspecialchars($_GET[‘asset’]), false, $context);

When building URLs that are part of PHP (not outputted HTML) you want to use urlencode(). Use htmlspecialchars when you are outputting some content as HTML.

1 Like

Thanks so much for all of your help! This has been a fun learning project.

Blockfrost does have SDK’s for many programming languages. The only one I can even consider due to my limited experience would be Javascript. I would not know where to begin in terms of using an SDK.

Do you know how I might begin to enable caching?

There are many different caching strategies, but as you are just starting out with PHP and the project is a simple one, I guess a file cached solution would be sufficient.

What you can do is store the Blockfrost frequent API call responses in cache files. For simplicity create one file for each response. Example:

  • Assumption: the process needs to call https://cardano-mainnet.blockfrost.io/api/v0/assets/XYZ
  • Check if file exists at ./cache/assets/XYZ_SANITIZED (Google how to sanitize filenames)
  • If cache file does not exist call blockfrost API and save response in file
  • If cache file exists, check whether modification time (see filemtime()) exceeds cache lifetime you desire.
  • If cache file lifetime expired call blockfrostapi and save response to cache file
  • If cach file lifetime has not expired, load cached response from file and use it

I haven’t worked yet with blockfrost, see if you can figure it out from the API documentation or maybe post another question on the forum.

Thanks so much for getting me on track with caching. It’s up next on my list!

Another foreach follow-up question! Do you know how I can add a where clause to the foreach? I realize now that I wish to add a clause that only shows items where $parsedJson->quantity = 1. I don’t want to return/display anything where a quantity is greater than 1.

Similarly, on another PHP page that does not have a foreach clause yet, I wish to restrict the page from running any queries when $parsedJson->quantity is greater than 1. If someone manually puts an asset ID in a URL parameter and tries to force the page to run when the quantity is greater than 1, the page should show a notice: cannot run page if quantity greater than 1. Do you think this is possible?

Take a look at if else statements:
https://www.w3schools.com/php/php_if_else.asp

I highly suggest that you find some PHP introductory course on Youtube. Investing several hours into the course will pay off in the long run.

Thanks again, mcrio! I was able to utilize the if else statement. I am off to watch PHP intro courses on Youtube!

1 Like