<?php
/*
The WebAPI
https://webapi.bookit.co.nz/
// ============================================================================================
This file contains two classes that are used to reference the WebAPI. The webapi class, and a Cache class.
You don't need to manually use the Cache class, it it used by the webapi class.
We highly recommend this be run on a server with Memcache, as it is a very efficient cache method.
Failing that, the Cache class implements a simple filesystem cache to keep the WebAPI calls to a minimum
as they can take some time, and would cause your page to load more slowly.
To use this class, for example to build an operator page:
// Create an instance of the WebAPI class with the visitor centre ID required
$api = new webapi(3, 'INSERT-WEBAPI-KEY-HERE');
// Set the state for the WebAPI call, in this case, set the operator ID
$api->set_state(array(
'operators'=>'53667'
));
// Fetch the accommodation operator details data
$api->fetch('accommodation','operator_details');
// To use the returned data, check your instance's 'data' member
// In this case, we refence the first entry in the data array
$operator = $api->data[0];
// Try var_dump or print_r on this data object - it should contain all the members and data you
// need to build a detail operator page. For example:
<h1><?=strip_tags($operator->TradingName);?></h1>
<p class="description">
<?=strip_tags($operator->Description);?>
</p>
<div class="map">
<!--
The map method accepts width, height and zoom
You need to have a webapi class instantiated and data fetched
-->
<img src="/<?=$api->mapURL(300,300,10);?>" alt="Map" />
</div>
<div class="images">
<?php
foreach($operator->Pictures as $pic) {
echo '<img src="'.$pic.'" />'."\n";
}
?>
</div>
// You'll note that we've included strip_tags in each text output call. We generally recommend this,
// as you may receive HTML tags you don't want in the data output.
// webapi Class usage notes ======================================================================
1. Create an instance of the class
2. Use the set_state method to set any parameters you want for the WebAPI call, refer to documentation for
specific details, but some common ones are:
a. date (str - date formatted as YYYY-MM-DD)
b. period (int)
c. adults (int)
d. children (int)
e. infants (int)
f. operators (str - comma separated list of operator IDs)
3. Run the fetch method of the instance to fetch data for the product type and data you want
from cache, or the WebAPI.
4. Use the output data to create your html page
// webapi Class fetch methods ====================================================================
The webapi class fetch method accepts to parameters:
1. the product type - 'accommodation', or 'tours'
2. the specific message to call
For accommodation, there are three messages included:
1. 'operator_details'
2. 'room_details'
3. 'rates_grid'
for tours, there are two messages included:
1. 'tours_details'
2. 'rates_grid'
*/
// Config =====================================================================================
// WebAPI Location
define('WEBAPI_URL','https://webapi.bookit.co.nz');
// Cache prefix, to ensure no cache clashes - keep unique to each implementation/website
define('CACHE_PREFIX','webapi-handle-class');
// Location to use in the filesystem if memcache is unavailable
define('FILE_SYSTEM_CACHE','/tmp');
// Hostname of the memcache server, if available
define('MEMCACHE_HOST','localhost');
// Memcache port on memcache server
define('MEMCACHE_PORT',11211);
// Default cache expiry for static-ish data (should be large - 4 hours-ish) [seconds]
define('LONG_CACHE',4*60*60);
// Default cache expiry for rates data (shouldn't be more than a few minutes) [seconds]
define('SHORT_CACHE',60);
// The primary WebAPI class ======================================================================
class webapi {
// Members
private $webapi_calls = array(
'accommodation' => array(
'operator_details' => array(
'url'=>'/be/getOperatorsDetailsShort',
'exp'=>LONG_CACHE
),
'room_details' => array(
'url'=>'/be/getAccomRoomsDetails',
'exp'=>LONG_CACHE
),
'rates_grid' => array(
'url'=>'/be/getAccomRatesGrid',
'exp'=>SHORT_CACHE
)
),
'tours' => array(
'tours_details' => array(
'url'=>'/be/getToursOperatorTourDetails',
'exp'=>LONG_CACHE
),
'rates_grid' => array(
'url'=>'/be/getToursRatesGrid',
'exp'=>SHORT_CACHE
)
)
);
// Pointer to the cache handler
private $cache_handle;
// Internal state storage
private $state = array();
private $vcID;
private $webapiKey;
public $data;
// Constructor
public function __construct($vcID, $webapiKey) {
// Set cache handler
$this->cache_handle = new Cache();
// Set the vcID
$this->vcID = $vcID;
// Set the webapi key
$this->webapiKey = $webapiKey;
}
// Primary call - fetches from cache or WebAPI
public function fetch($type,$method) {
$q_str = $this->build_string();
$cache_id = $type.$method.$q_str;
// Attempt to get from cache
$data = $this->cache_handle->get($cache_id);
if($data == null || $data == false || $data == '') {
$webapiURL = WEBAPI_URL . $this->webapi_calls[$type][$method]['url'].$q_str;
$header = array('apiKey: '.$this->webapiKey);
$curl_handle = curl_init();
curl_setopt($curl_handle, CURLOPT_HEADER, false);
curl_setopt($curl_handle, CURLOPT_HTTPHEADER, $header);
curl_setopt($curl_handle, CURLOPT_URL, $webapiURL);
curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, true);
$data = curl_exec($curl_handle);
curl_close($curl_handle);
$this->cache_handle->set($cache_id, $data, $this->webapi_calls[$type][$method]['exp']);
}
$this->data = json_decode($data);
}
// Build a URL for a google static map
public function mapURL($w=200,$h=200,$z=12) {
if(count($this->data) < 1) {
return '';
}
$op = $this->data[0];
// If lat/lng is zero
if($op->Latitude == 0 && $op->Longitude == 0) {
return '';
}
return '//maps.googleapis.com/maps/api/staticmap?sensor=false¢er='.$op->Latitude.','.$op->Longitude.'&size='.$w.'x'.$h.'&zoom='.$z;
}
// Set state - for use to set params
public function set_state($arr) {
foreach($arr as $key=>$val) {
$this->state[$key] = $val;
}
}
// Reset state to empty array
public function clear_state() {
$this->state = array();
}
// Build query string from state
private function build_string() {
// Build query string
$q_str = '?q=' . $this->vcID;
foreach($this->state as $key=>$val) {
$q_str .= '&'.$key.'='.$val;
}
return $q_str;
}
}
// Cache class used by WebAPI ====================================================================
class Cache {
// Members
private $is_memcache = false;
private $handle;
// Constructor
public function __construct() {
// Check if memcache exists
if(class_exists('Memcache')) {
$this->handle = new Memcache();
try {
$this->handle->connect(MEMCACHE_HOST,MEMCACHE_PORT);
$this->is_memcache = true;
} catch(Exception $e) {
$this->setup_fs_cache();
}
} else {
// Create the fs cache structure
$this->setup_fs_cache();
}
}
// Get from cache method
public function get($id) {
$ref = $this->makeID($id);
if ($this->is_memcache) {
return $this->handle->get($ref);
} else {
$filepath = $this->fs_path.'/'.$ref;
if (file_exists($filepath)) {
$expires = file_get_contents($filepath.'.expires');
if (time() < $expires) {
return file_get_contents($filepath);
} else {
unlink($filepath);
unlink($filepath.'.expires');
return null;
}
} else {
return null;
}
}
}
// Set to cache method
public function set($id,$data,$expiry=LONG_CACHE) {
$ref = $this->makeID($id);
if ($this->is_memcache) {
$this->handle->set($ref,$data,$expiry);
} else {
file_put_contents($this->fs_path.'/'.$ref, $data, LOCK_EX);
file_put_contents($this->fs_path.'/'.$ref.'.expires', time() + $expiry, LOCK_EX);
}
}
// Make ID
private function makeID($string) {
return md5(CACHE_PREFIX.$string);
}
// Setup the filesystem cache
private function setup_fs_cache() {
// Check directory is there
$path = FILE_SYSTEM_CACHE.'/'.CACHE_PREFIX;
$this->fs_path = $path;
$error = 'Couldn\'t setup FS cache - disabled';
// Try to create the dir
if(!file_exists($path) || !is_dir($path)) {
try {
mkdir($path,0775,true);
} catch(Exception $e) {
echo $error;
exit();
}
}
// Can we save things?
if(!is_dir($path) && !is_writable($path)) {
echo $error;
exit();
}
}
}
?>