Ever needed a quick caching class for your PHP application? This is another caching class for PHP which is able to solve your quick caching needs. Now a days all major frameworks comes with a standard caching library. But, in some cases you may need only a caching class. It is also helpful when you are not using framework or if you don’t like the cache class provided by the framework. In my case, I am using CodeIgniter for last few months and I am not happy with the caching solution provided by CodeIgniter.
Since, I am a CakePHP lover, I have looked at CakePHP cache library and tried to make something similar. So, you may find similarity with CakePHP.
Features:
- Simple & Easy to use from anywhere in your application with a single line of code.
- Easily configurable & can work without any configuration.
- Support multiple cache configurations
- Support static method for caching
- Support file caching engine for now, other caching engines can be added to the class
- Support singleton pattern
- Light Weight
Class:
File: raycache.php
<?php
/* SVN FILE: $Id: raycache.php 85 2008-05-13 07:36:10Z rayhan $ */
/** Cache Object Class.
*
* Caching classes for easy and plug and play installation.
*
* PHP version 5+
*
*
* @copyright Copyright 2006-2010, Md. Rayhan Chowdhury
* @package raynux
* @subpackage raynux.labs.cache
* @version $Revision: 85 $
* @modifiedby $LastChangedBy: rayhan $
* @lastModified $Date: 2008-05-13 13:36:10 +0600 (Tue, 13 May 2008) $
* @author $Author: rayhan $
* @website www.raynux.com
* @license MIT License http://www.opensource.org/licenses/mit-license.php
*/
/**
* Cache Engine Interface
*
*/
Interface RayCacheEngineInterface{
function write($key, $data, $options = array());
function read($key, $options = array());
function delete($key, $options = array());
function clear($expired = true);
function gc();
public static function &getInstance($configs = array());
}
/**
* Cache Class
*
* Provide cache functionality for multiple configuration and engine.
* Static read-write method are helpful to call from anywhere of the script.
*
* @package raynux
* @subpackage raynux.labs.cache
*/
class RayCache{
/**
* Class Instances
*
* @var array
*/
private static $__instances = array();
/**
* Get Instance of a cache engine
*
* Factory Interface for Cache Engine.
*
* @param config $configName
* @param string $engine default file
* @param array $configs
* @return object
*/
public static function &getInstance($configName = null, $engine = null, $configs = array()){
if (empty($configName)) {
$configName = 'default';
}
if (empty($engine)) {
$engine = 'file';
}
if (isset(self::$__instances[$configName])) {
return self::$__instances[$configName];
}
if (empty(self::$__instances)) {
$default = true;
}
$engine = strtolower($engine);
switch ($engine){
case 'file':
default:
self::$__instances[$configName] = new RayFileCache($configs);
break;
}
return self::$__instances[$configName];
}
/**
* Static wrapper to cache write method
*
* @param string $key
* @param mixed $data
* @param array $options, array('expire' => 10), expire in seconds
* @param string $configName
* @return boolean
*/
public static function write($key, $data, $options = array(), $configName = 'default') {
$_this = self::getInstance($configName);
return $_this->write($key, $data, $options);
}
/**
* Static Wrapper to cache read method
*
* @param string $key
* @param array $options
* @param string $configName
* @return mixed
*/
public static function read($key, $options = array(), $configName = 'default') {
$_this = self::getInstance($configName);
return $_this->read($key, $options);
}
/**
* Static wrapper to cache delete mathod
*
* @param string $key
* @param array $options
* @param string $configName
* @return boolean
*/
public static function delete($key, $options = array(), $configName = 'default') {
$_this = self::getInstance($configName);
return $_this->delete($key, $options);
}
}
/**
* File Cache Engine
*
* @package raynux
* @subpackage raynux.labs.cache
*/
class RayFileCache implements RayCacheEngineInterface{
/**
* Class Instances
*
* @var array
*/
private static $__instance;
/**
* Runtime Configuration Data
*
* @var array
*/
protected $_configs = array();
/**
* Class Constructor
*
* @param array $configs
*/
function __construct($configs = array()) {
$this->config($configs);
// run garbage collection
if (rand(1, $this->_configs['gc']) === 1) {
$this->gc();
}
}
/**
* Get Instance of Class
*
* @param string $name
* @param array $configs
* @return object
* @static
*/
public static function &getInstance($configs = array()){
if (is_null(self::$__instance)) {
self::$__instance = new self($configs);
}
return self::$__instance;
}
/**
* Set Configuration
*
* default: array('path' => './cache/', 'prefix' => 'raycache_', 'expire' => 10, 'gc' => 100)
*
* @param array $configs
* @return object self instance
*/
function &config($configs = array()) {
// default path modified to work with ci cache
$default = array('path' => './cache/', 'prefix' => 'raycache_', 'expire' => 10, 'gc' => 100);
$this->_configs = array_merge($default, $configs);
return $this;
}
/**
* Write data to cache
*
* @param string $key
* @param mixed $data
* @param array $options
* @return boolean
*/
public function write($key, $data, $options = array()){
// check is writable
if (!is_writable($this->_configs['path'])) {
echo $this->_configs['path'];
return false;
}
// Prepare data for writing
if (!empty($options['expire'])) {
$expire = $options['expire'];
} else {
$expire = $this->_configs['expire'];
}
if (is_string($expire)) {
$expire = strtotime($expire);
} else {
$expire = time() + $expire;
}
$data = serialize(array('expire' => $expire, 'data' => $data));
$fileName = $this->_configs['path'] . $this->_configs['prefix'] . $key;
// Write data to files
if (file_put_contents($fileName, $data, LOCK_EX)) {
return true;
} else {
return false;
}
}
/**
* Read Data from cache
*
* @param string $key
* @param array $options
* @return mixed
*/
public function read($key, $options = array()) {
$fileName = $this->_configs['path'] . $this->_configs['prefix'] . $key;
if (!file_exists($fileName)) {
return false;
}
if (!is_readable($fileName)) {
return false;
}
$data = file_get_contents($fileName);
if ($data === false) {
return false;
}
$data = unserialize($data);
if ($data['expire'] < time()) {
$this->delete($key);
return false;
}
return $data['data'];
}
/**
* Delete a cache data
*
* @param string $key
* @param arrayt $options
* @return boolean
*/
function delete($key, $options = array()) {
$fileName = $this->_configs['path'] . $this->_configs['prefix'] . $key;
if (!file_exists($fileName) || !is_writable($fileName)) {
return false;
}
return unlink($fileName);
}
/**
* Clear cache data
*
* @param boolean $expired if true then only delete expired cache
* @return booelan
*/
public function clear($expired = true) {
$entries = glob($this->_configs['path'] . $this->_configs['prefix'] . "*");
if (!is_array($entries)) {
return false;
}
foreach ($entries as $item) {
if (!is_file($item) || !is_writable($item)) {
continue;
}
if ($expired) {
$expire = file_get_contents($item, null, null, 20, 11);
$strpos = strpos($expire, ';');
if ($strpos !== false) {
$expire = substr($expire, 0, $strpos);
}
if ($expire > time()) {
continue;
}
}
if (!unlink($item)) {
return false;
}
}
return true;
}
/**
* Garbage collection
*
* @return boolean
*/
public function gc() {
return $this->clear(true);
}
}
?>
Usage Example: some quick examples are given below to introduce you with the class and it’s methods.
<?php
/**
* Load the cache library
*
*/
include_once('raycache.php');
/**
* Class Example
*
* Once loaded you can use this class in two ways:
* - Using Static Methods (My Favorite)
* - Using Class Instance
*
* or, even you can mix them both
* In both ways it support multiple configuration and uses
*/
/**
* Static Method
*/
//Get default CacheInstance with one of the following methods
RayCache::getInstance();
// OR
RayCache::getInstance(null, null, array('path' => 'my_cache_path/', 'prefix' => 'my_cache_', 'expire' => '+10 seconds'));
// You can configure or reconfigure your instance anytime you like.
RayCache::getInstance()->config(array('path' => 'my_cache_path/', 'prefix' => 'my_cache_', 'expire' => '+10 seconds'));
// store data
RayCache::write('test_key', 'This data will expire in 10 seconds
');
RayCache::write('test_key2', 'This data will expire in 10 seconds
', array('expire' => '+10 seconds')); // expre value can be integer in seconds or time string supported by php strtotime method
RayCache::write('test_key3', 'This data will expire in 20 seconds
', array('expire' => '+20 seconds'));
// read data
echo RayCache::read('test_key');
echo RayCache::read('test_key2');
echo RayCache::read('test_key3');
/**
* Class Instance Method
*/
// get calss class instance
$cache = RayCache::getInstance(); // default configure
$cache2 = RayCache::getInstance('short', null, array('prefix' => 'short_', 'path' => 'my_cache_path/', 'expire' => '+20 seconds'));
$cache3 = RayCache::getInstance('long', null, array('prefix' => 'long_', 'path' => 'my_cache_path/', 'expire' => '+1 hour'));
// store data
$cache->write('test_key', 'This data will expire in 10 seconds
');
$cache2->write('test_key2', 'This data will expire in 20 seconds
');
$cache3->write('test_key3', 'This data will expire in 1 hour
');
// read data
echo $cache->read('test_key');
echo $cache2->read('test_key2');
echo $cache3->read('test_key3');
?>
Please let me know if you find this class helpful for you..
]]>First of all it’s another reinvention of wheel. This class is designed to provide quick access to any XML based RSS feed and it’s content. Usages are very simple and require only one line of code. Html rendering functionality is provided through separate pluggable widget rendering class which can be extended easily. SimpleXML is used by default to load and fetch feed url but can be used CURL using rayHttp class. All or any CURL options can be set for HTTP request. It can auto detect feed type and supports RSS 0.92, RSS 2.0 and Atom feeds.
Features:
- Read feeds content into an array
- Supports for RSS 0.92, RSS 2.0 and Atom feed
- Detect feed type automatically, also can be set manually.
- Support pluggable html widget rendering class
- Can render html widget through optional RayFeedWidget class or your own extended class.
- Easily configurable & can work without any configuration.
- Simple & Easy to use from anywhere in your application with a single line of code.
- Support Singleton pattern
- By default SimpleXML is used as http client,
- Support Custom CURL request, may be used to extends functionality through rayHttp class.
- Light Weight
Methods Available (This class provides):
- parse()
- getData()
- widget()
Class:
File: rayfeedreader.php
<?php
/**
* RayFeedReader
*
* SimpleXML based feed reader class. A very specific feed reader designed
* to working with no or little configurations.
*
* - This class can read an rss feed into array from a given url.
* - Also can render html widget with plugable RayFeedWidget Class.
*
* Supports following feed types:
* - RSS 0.92
* - RSS 2.0
* - Atom
*
* Configuration Options
* - array
* - url: (string)
* - feed url
*
* - httpClient: (string)
* - default SimpleXML
* - value rayHttp or SimpleXML
*
* - type: ([optional] string
* - auto detect
* - value rss or rss2 or atom
*
* - widget: ([optional] string)
* - feed widget class name for rendering html
*
* - rayHttp: (array)
* - only if httpClient is set to rayHttp
* - rayHttp Options if you want to modify rayHttml CURL options
* - generally not required.
*
*
*
*
* @version 1.0
* @author Md. Rayhan Chowdhury
* @package rayFeedReader
* @license GPL
*/
Class RayFeedReader{
/**
* Self Instance for Singleton Pattern
*
* @var object
* @access protected
*/
static private $__instance;
/**
* Instance of Parser Class.
*
* @var object Parser Class
* @access protected
*/
Protected $_Parser;
/**
* Feed Url
*
* @var string feed url
* @access protected
*/
protected $_url;
/**
* Runtime Options for reader
*
* @var array
* @access protected
*/
protected $_options = array('rayHttp' => array());
/**
* Type of feed to be parsed.
*
* @var string
* @access protected
*/
protected $_type = "rss";
/**
* HttpClient to be used for loading feed content.
*
* - default SimpleXML
*
* @var string 'SimpleXML' or 'rayHttp'
* @access protected
*/
protected $_httpClient = "SimpleXML";
/**
* Widget Class Name
*
* @var string
* @access protected
*/
protected $_widget;
/**
* Parsed result data
*
* @var array
* @access protected
*/
protected $_content;
/**
* Class construct
*
* @param array $options
*/
function __construct($options = array()) {
$this->setOptions($options);
}
/**
* Get Instance of the class.
*
* @param array $options
* @return object self instance.
* @access public
* @static
*/
static function &getInstance($options = array()) {
if (is_null(self::$__instance)) {
self::$__instance = new self($options);
}
return self::$__instance;
}
/**
* Set Options for the class
*
*
* @param array $options
* @return object self instance
* @access public
*/
function &setOptions($options) {
if (!empty($options['url'])) {
$this->_url = $options['url'];
}
if (!empty($options['type'])) {
$this->_type = $options['type'];
}
if (!empty($options['httpClient'])) {
$this->_httpClient = $options['httpClient'];
}
if (!empty($options['widget'])) {
$this->_widget = $options['widget'];
}
$this->_options = array_merge($this->_options, $options);
return $this;
}
/**
* Parse feed contents into an array and return self object
*
* @return object self instance
* @access public
*/
function &parse() {
/**
* Get/load content
*/
switch ($this->_httpClient) {
case 'SimpleXML':
$content = new SimpleXMLElement($this->_url, LIBXML_NOCDATA, true);
break;
case 'rayHttp':
$content = RayHttp::getInstance()->setOptions($this->_options['rayHttp'])->get($this->_url);
if (!empty($content)) {
$content = new SimpleXMLElement($content, LIBXML_NOCDATA);
}
break;
}
if (empty($content)) {
trigger_error("XML format is invalid or broken.", E_USER_ERROR);
}
/**
* Detect Feed Type
*/
if (empty($this->_type)) {
switch ($content->getName()) {
case 'rss':
foreach ($content->attributes() as $attribute) {
if ($attribute->getName() == 'version') {
if ('2.0' == $attribute) {
self::setOptions(array('type' => 'rss2'));
} elseif (in_array($attribute, array('0.92', '0.91'))) {
self::setOptions(array('type' => 'rss'));
}
}
}
break;
case 'feed':
self::setOptions(array('type' => 'atom'));
break;
}
}
if (!in_array($this->_type, array('rss', 'rss2', 'atom'))) {
trigger_error("Feed type is either invalid or not supported.", E_USER_ERROR);
return false;
}
/**
* Parse Feed Content
*/
switch ($this->_type) {
case 'rss':
$content = $this->parseRss($content);
break;
case 'rss2':
$content = $this->parseRss2($content);
break;
case 'atom':
$content = $this->parseAtom($content);
break;
}
if (empty($content)) {
trigger_error("No content is found.", E_USER_ERROR);
}
$this->_content = $content;
return $this;
}
/**
* Get Array of Parsed XML feed data.
*
* @return array parsed feed content.
* @access public
*/
function getData() {
return $this->_content;
}
/**
* Return html widget based rendered by widget class
*
*
* @param array $options for html widget class
* @return string html widget
* @access public
*/
function widget($options = array('widget' => 'brief')) {
if (!empty($this->_widget) && !empty($this->_content)) {
$Widget = new $this->_widget;
return $Widget->widget($this->_content, $options);
} else {
return false;
}
}
/**
* Parse feed xml into an array.
*
* @param object $feedXml SimpleXMLElementObject
* @return array feed content
* @access public
*/
function parseRss($feedXml) {
$data = array();
$data['title'] = $feedXml->channel->title . '';
$data['link'] = $feedXml->channel->link . '';
$data['description'] = $feedXml->channel->description . '';
$data['parser'] = __CLASS__;
$data['type'] = 'rss';
foreach ($feedXml->channel->item as $item) {
$data['items'][] = array(
'title' => $item->title . '',
'link' => $item->link . '',
'description' => $item->description . '',
);
}
return $data;
}
/**
* Parse feed xml into an array.
*
* @param object $feedXml SimpleXMLElementObject
* @return array feed content
* @access public
*/
function parseRss2($feedXml) {
$data = array();
$data['title'] = $feedXml->channel->title . '';
$data['link'] = $feedXml->channel->link . '';
$data['description'] = $feedXml->channel->description . '';
$data['parser'] = __CLASS__;
$data['type'] = 'rss2';
$namespaces = $feedXml->getNamespaces(true);
foreach ($namespaces as $namespace => $namespaceValue) {
$feedXml->registerXPathNamespace($namespace, $namespaceValue);
}
foreach ($feedXml->channel->item as $item) {
$categories = array();
foreach ($item->children() as $child) {
if ($child->getName() == 'category') {
$categories[] = (string) $child;
}
}
$author = null;
if (!empty($namespaces['dc']) && $creator = $item->xpath('dc:creator')) {
$author = (string) $creator[0];
}
$content = null;
if (!empty($namespaces['encoded']) && $encoded = $item->xpath('content:encoded')) {
$content = (string) $encoded[0];
}
$data['items'][] = array(
'title' => $item->title . '',
'link' => $item->link . '',
'date' => date('Y-m-d h:i:s A', strtotime($item->pubDate . '')),
'description' => $item->description . '',
'categories' => $categories,
'author' => array( 'name' => $author),
'content' => $content,
);
}
return $data;
}
/**
* Parse feed xml into an array.
*
* @param object $feedXml SimpleXMLElementObject
* @return array feed content
* @access public
*/
function parseAtom($feedXml) {
$data = array();
$data['title'] = $feedXml->title . '';
foreach ($feedXml->link as $link) {
$data['link'] = $link['href'] . '';
break;
}
$data['description'] = $feedXml->subtitle . '';
$data['parser'] = __CLASS__;
$data['type'] = 'atom';
foreach ($feedXml->entry as $item) {
foreach ($item->link as $link) {
$itemLink = $link['href'] . '';
break;
}
$categories = array();
foreach ($item->category as $category) {
$categories[] = $category['term'] . '';
}
$data['items'][] = array(
'title' => $item->title . '',
'link' => $itemLink . '',
'date' => date('Y-m-d h:i:s A', strtotime($item->published . '')),
'description' => $item->summary . '',
'content' => $item->content . '',
'categories' => $categories,
'author' => array('name' => $item->author->name . '', 'url' => $item->author->uri . ''),
'extra' => array('contentType' => $item->content['type'] . '', 'descriptionType' => $item->summary['type'] . '')
);
}
return $data;
}
}
?>
External feed widget class to get rendered html widget.
File: rayfeedwidget.php
<?php
/**
* Feed Widget Interface
*
* @version 1.0
* @author Md. Rayhan Chowdhury
* @package rayFeedReader
* @license GPL
*/
interface RayFeedWidget_Interface{
/**
* Public widget method
*
* @param <type> $data
* @param $options
* @return string html
*/
public function widget($data, $options = array());
}
/**
* Widget Plugin Class for RayFeedReader
*
* Render html widget for feed reader based on options
*
* config options
* - array
* - widget:
* - optional string
* - value 'brief' or 'compact' or 'detail'
* - showTitle
* - boolean
* - whether add blog title or not.
*
* @version 1.0
* @author Md. Rayhan Chowdhury
* @package rayFeedReader
* @license GPL
*/
class RayFeedWidget implements RayFeedWidget_Interface{
/**
* HTML widget structure
*
* @var array
* @access public
*/
public $html = array('brief' => "<div class=\"feed-item feed-brief\">\n
<div class=\"feed-item-title\">\n
<h3><a href='%s'>%s</a></h3>\n
<div class='feed-item-date'>%s</div>\n
</div>\n
<div class=\"feed-item-description\">%s</div>\n
</div>",
'compact' => "<div class=\"feed-item feed-compact\">\n
<div class=\"feed-item-title\">\n
<h3><a href='%s'>%s</a></h3>\n
<div class='feed-item-date'>%s</div>\n
</div>\n
</div>",
'detail' => "<div class=\"feed-item feed-detail\">\n
<div class=\"feed-item-title\">\n
<h3><a href='%s'>%s</a></h3>\n
<div class='feed-item-date'>%s</div>\n
</div>\n
<div class=\"feed-item-content\">%s</div>\n
</div>",
);
/**
* Return html widget based rendered by widget class
*
* @param $data
* @param $options
* @return
*/
function widget($data, $options = array('widget' => 'brief')) {
switch ($options['widget']) {
case 'compact':
return $this->widgetCompact($data, $options);
break;
case 'detail':
return $this->widgetDetail($data, $options);
break;
case 'brief':
default:
return $this->widgetBrief($data, $options);
break;
}
}
/**
* Render feed widget with title and date only
*
* @param $data
* @param $options
* @return
*/
function widgetCompact($data, $options = array()) {
if (empty($data['items'])) {
return false;
}
$out = array();
foreach ($data['items'] as $item) {
if (empty($item['date'])) {
$item['date'] = '';
}
$out[] = sprintf($this->html['compact'], $item['link'], $item['title'], $item['date']);
}
$title = '';
if (empty($options['showtitle'])) {
$title = sprintf("<div class='feed-title'><h2>%s</h2><hr>%s</div>\n", $data['title'], $data['description']);
}
$out = "<div class='feed-container'>\n" . $title . join(" \n", $out) . "</div>";
return $out;
}
/**
* Render feed widget with title, date & description
*
* @param $data
* @param $options
* @return
*/
function widgetBrief($data, $options = array()) {
if (empty($data['items'])) {
return false;
}
$out = array();
foreach ($data['items'] as $item) {
if (empty($item['date'])) {
$item['date'] = '';
}
if (empty($item['description'])) {
$item['description'] = $item['content'];
}
$out[] = sprintf($this->html['brief'], $item['link'], $item['title'], $item['date'], $item['description']);
}
$title = '';
if (empty($options['showtitle'])) {
$title = sprintf("<div class='feed-title'><h2>%s</h2><hr>%s</div>\n", $data['title'], $data['description']);
}
$out = "<div class='feed-container'>\n" . $title . join(" \n", $out) . "</div>";
return $out;
}
/**
* Render blog widget with title, date & content
*
* @param $data
* @param $options
* @return
*/
function widgetDetail($data, $options = array()) {
if (empty($data['items'])) {
return false;
}
$out = array();
foreach ($data['items'] as $item) {
if (empty($item['date'])) {
$item['date'] = '';
}
if (empty($item['content'])) {
$item['content'] = $item['description'];
}
$out[] = sprintf($this->html['detail'], $item['link'], $item['title'], $item['date'], $item['content']);
}
$title = '';
if (empty($options['showtitle'])) {
$title = sprintf("<div class='feed-title'><h2>%s</h2><hr>%s</div>\n", $data['title'], $data['description']);
}
$out = "<div class='feed-container'>\n" . $title . join(" \n", $out) . "</div>";
return $out;
}
}
?>
Usage Example: some quick examples are given below to introduce you with the class and it’s methods.
File: example.php
<?php
/**
* Example Usage or RayFeedReader
*/
require_once('rayfeedreader.php');
/**
* get Instance
*/
$reader1 = RayFeedReader::getInstance();
$reader2 = RayFeedReader::getInstance($options);
$reader3 = new RayFeedReader();
$reader4 = new RayFeedReader($options);
/**
* get data from a feed url
*/
$options = array('url' => 'http://example.com/feed');
$feedData = RayFeedReader::getInstance($options)->parse()->getData();
// Or options can be set anytime using setOptions method.
$feedData = RayFeedReader::getInstance()->setOptions($options)->parse()->getData();
/**
* Get html widget
*/
$options = array(
'url' => 'http://example.com/feed',
'widget' => 'RayFeedWidget',
);
/**
* Load rayFeedWidget class file
*/
require_once('rayfeedwidget.php');
$html = RayFeedReader::getInstance()->setOptions($options)->parse()->widget();
// OR with widget options.
$widgetOptions = array('widget' => 'detail', 'showTitle' => true);
$html = RayFeedReader::getInstance()->setOptions($options)->parse()->widget($widgetOptions);
/**
* Full options
*/
$options = array(
'url' => 'http://example.com/feed',
'widget' => 'RayFeedWidget',
'httpClient' => 'rayHttp',
'type' => 'atom',
);
/**
* Load rayHttp class file.
*/
require_once("rayhttp.php");
/**
* Html widget with full options
*/
$html = RayFeedReader::getInstance()->setOptions($options)->parse()->widget();
/**
* Get Feed Data with full options
*/
$feedData = RayFeedReader::getInstance($options)->parse()->getData();
?>
Please let me know if you find this class helpful for you..
]]>Class Update:
An updated version of this class and example script are posted at PHPClasses.org, http://www.phpclasses.org/browse/package/5652.html. Please use class from PHPClasses.org for bug fixed latest version.