Jump to content

Caching json response


Texan78

Recommended Posts

Hello, I am needing to cache a json response from an API so I am not making requests on each load. I have come across some code that is suppose to accomplish this but, it seems to not be working and can't figure out as to why. I created the cache file with 777 but it doesn't write or read from that file when I echo out the results. 

 

The code below is just what is suppose to get the contents and cache it. At the end I tried to print it so I can test it to see it prints the response from the cache file but, nothing and the cache file does exists. 

 

This is the first time I have tried something like this so please be gentle. 

// cachePath is name of the path and file used to store cached current conditions gathered from the API request
$cachePath  = "./cache/nowcast-cache.txt";

// URL to the API request
$url = "http://api.wunderground.com/api/XXXXXXXXXXXX/geolookup/conditions/q/TX/mesquite.json";

date_default_timezone_set('America/Chicago');

/**
* Request jobs from  API
*
* Split the request into smaller request chunks
* and then consolidate them into a single array to limit the API
* requests.
*/
function api_request()
{
    file_put_contents($cachePath,
file_get_contents($url));
}

/**
 * API Request Caching
 *
 *	Use server-side caching to store API request's as JSON at a set
 *	interval, rather than each pageload.
 *
 * @arg Argument description and usage info
 */


function json_cached_api_results( $cache_file = NULL, $expires = NULL ) {
	global $request_type, $purge_cache, $limit_reached, $request_limit;

	if( !$cache_file ) $cache_file = dirname(__FILE__) . $cachePath;
	if( !$expires) $expires = time() - 2*60*60;

	if( !file_exists($cache_file) ) die("Cache file is missing: $cache_file");

	// Check that the file is older than the expire time and that it's not empty
	if ( filectime($cache_file) < $expires || file_get_contents($cache_file)  == '' || $purge_cache && intval($_SESSION['views']) <= $request_limit ) {

		// File is too old, refresh cache
		$api_results = api_request();
		$json_results = json_encode($api_results);

		// Remove cache file on error to avoid writing wrong xml
		if ( $api_results && $json_results )
			file_put_contents($cache_file, $json_results);
		else
			unlink($cache_file);
	} else {
		// Check for the number of purge cache requests to avoid abuse
		if( intval($_SESSION['views']) >= $request_limit )
			$limit_reached = " <span class='error'>Request limit reached ($request_limit). Please try purging the cache later.</span>";
		// Fetch cache
		$json_results = file_get_contents($cache_file);
		$request_type = 'JSON';
	}

	return json_decode($json_results);
}

print_r($json_results);
Edited by Texan78
Link to comment
Share on other sites

I'll tell you how I cache my api json responses locally

I store my cache in /var/cache/api/

permissions set to 755 and owner www-data

 

Not sure how you have your api set up, but my scripts are includes through the server if passes api checks

 

I believe you are trying to cache external api requests?

Well this can cache anything, make a script that fetches and displays the data, call on that script, the cache will do the rest.

You can change the folder location to where you need it.

 

api-cache.php

<?php
      
class cache
{
    var $cache_dir = '/var/cache/api/'; //cache storage location
    var $cache_time = 86400; //cache storage time in seconds
    
    var $caching = false;
    var $file = '';

    function cache()
    {
        $this->file = $this->cache_dir . urlencode( $_SERVER['REQUEST_URI'] );
        if ( file_exists ( $this->file ) && ( fileatime ( $this->file ) + $this->cache_time ) > time() )
        {
            //read cache
            $handle = fopen( $this->file , "r");
            do {
                $data = fread($handle, 8192);
                if (strlen($data) == 0) {
                    break;
                }
                echo $data;
            } while (true);
            fclose($handle);
            exit();
        }
        else
        {
            //create cache
            $this->caching = true;
            ob_start();
        }
    }
    
	//close cache
    function close()
    {        
        if ( $this->caching )
        {
            $data = ob_get_clean();
            echo $data;
            $fp = fopen( $this->file , 'w' );
            fwrite ( $fp , $data );
            fclose ( $fp );
        }
    }
}

?>

Usage

require_once('api-cache.php');
$ch = new cache();

echo date("D M j G:i:s T Y"); //cached content area

$ch->close();
Link to comment
Share on other sites

Thanks for the suggestion. I been trying it out. I do already have the script that will read from a cache file and it works great. This issue is trying to cache the API response from a URL. A couple of questions. 

 

Should the below set to true and would the $file be the URL to the API response I want to cache? 

var $caching = false;
var $file = '';
Link to comment
Share on other sites

Those are just default defines, no need to edit those.

 

The cache is saving your scripts by address bar names.

 

Make a script with dynamic values from your address bar, the script connects to the api with the dynamic values.

 

Your script connects to external api, returns json data on the page.

 

You now would want to connect to your script as if it was the api.

Link to comment
Share on other sites

You are using a relative url for the path.

I don't where the file is relative to your script, but I would use __DIR__ or $_SERVER['DOCUMENT_ROOT']

Before I write external functions, class files, etc. I throw together a basic bare bones script and execute it.

I do this just so I know I have the path correct, that I can use file_get_contents(), that my file permissions are correct etc.

error_reporting(E_ALL);
ini_set('display_errors',1);
define('br', '<br />');

$cachePath  = $_SERVER['DOCUMENT_ROOT'] . '/cache/nowcast-cache.txt';

$url = 'http://api.wunderground.com/api/XXXXXXXXXXXX/geolookup/conditions/q/TX/mesquite.json';

if(($data = @file_get_contents($url)) === false)
{
    echo 'file_get_contents() failed as usual' . br;
    exit(); // no need to go any further until this is fixed
}

if((@file_put_contents($cachePath, $data)) === false)
{
    echo 'file_put_contents() failed' . br;
}
Link to comment
Share on other sites

I seem to have this working fairly well now. It writes and reads from it. How would I add to it so it only checks the URL X amount of times I.E. every hour?

 

 

$cache  = $_SERVER['DOCUMENT_ROOT'] . $cachePath;

 
$url = 'http://api.aerisapi.com/observations/KHQZ?client_id='. $ID .'&client_secret='. $client_secret.'';
 
if(($data = @file_get_contents($url)) === false)
{
    echo 'file_get_contents() failed as usual' . br;
    exit(); // no need to go any further until this is fixed
}
 
if((@file_put_contents($cachePath, $data)) === false)
{
    echo 'file_put_contents() failed' . br;
}

 

 

-Thanks

Link to comment
Share on other sites

You are going to have to create a cron job for that - a scheduled task on the server.

I don't have time to go over it right now, but maybe others will chime in - or you can look up how to do that.

You will need to modify your script - possibly have to add a bash command up top.

You can set it up to email you when the task is complete.

Link to comment
Share on other sites

Currently I use a cron to write to a file then the script reads from that file. I am trying to do it without having to use a cron. That is what I was trying to accomplish with the code in my original post. Otherwise it is redundant with the suggested code since wget in a cron does the same thing. 

Link to comment
Share on other sites

I am really not sure what more I could add that isn't already explained and added with the code in the orignal post. 

 

The code posted should do what I need it to do but, it doesn't write or read to the cache. 

 

That was the reason for this post. 

 

When the page is called the script will write to a cache file the response from the API. If the response is under X age then don't call the API. If it is over X age then request a new response and cache it. The script will read from the cache the response. The part of the script that reads from the cache works great. I am just having problems with writing to cache and having the code read from the cache file. 

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.