<?php /** * The MIT License * * Copyright (c) 2009 Dustin Senos http://dustinsenos.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * * @author Dustin Senos <dustin@dustinsenos.com> * @copyright 2009 Dustin Senos * @date March 1st, 2009 * @version 1.0 * @license http://www.opensource.org/licenses/mit-license.php * @link http://dustinsenos.com * * @usage * * $linkroll = new DeliciousLinkroll('dsenos'); * echo $linkroll->getLinkroll(); * */ class DeliciousLinkroll { const DEBUG_ACTIVE = false; const LINKROLL_ID = 'deliciousLinkroll'; // Caching settings const CACHE_ENABLED = true; const CACHE_LOCATION = 'DeliciousLinkroll.cache'; const CACHE_LIFETIME = 3600; // 3600 seconds == 1 hour // Delicious constants const DELICIOUS_URL = 'http://delicious.com/'; const DELICIOUS_FEED_URL = 'http://feeds.delicious.com/v2/json/'; const DELICIOUS_COUNT_PARAM = 'count'; const DELICIOUS_JSON_URL = 'u'; const DELICIOUS_JSON_NAME = 'd'; const DELICIOUS_JSON_TAGS = 't'; // Curl settings const CURL_TIMEOUT = 2; // Errors const ERROR_CACHE_DIRECTORY = "Error: Cache directory doesn't exist"; const ERROR_CACHE_FILE = "Error: Cache file doesn't exist"; const ERROR_CACHE_PERMISSIONS = "Error: Can't write to the cache file. Please check file permissions"; const ERROR_CACHE_UNSERIALIZE = 'Error: Could not unserialize the cache file'; const ERROR_CURL_FAILED = 'Error: CURL request failed'; const ERROR_JSON_DECODE = 'Error: Could not decode JSON. Possibly malformed'; const ERROR_HTML_DATA = 'Error: No Data passed to createXhtml()'; const ERROR_NO_DATA = 'Error: No valid data to display'; // Warnings const WARNING_CACHE_DATA = 'Warning: No data passed to sendToCache(); Not writing to cache file'; // Instance variables defined in constructor private $username; private $count; private $showTags; private $listId; /** * Instantiates a new DeliciousLinkroll Object. * * @param $username The username to fetch the delicious bookmarks for * @param $count How many bookmarks to show * @param $showTags True if you want to display the tags for the bookmark * * @return void * */ public function __construct($username = '', $count = 5, $showTags = true, $listId = DeliciousLinkroll::LINKROLL_ID) { $this->username = $username; $this->count = $count; $this->showTags = $showTags; $this->listId = $listId; } /** * Fetches the linkroll from either the cache if enabled and not stale or * uses CURL to fetch it from delicious. Returns a xhtml unordered list * containing bookmarks. * * @return void * */ public function getLinkroll() { $linkroll = ''; // If we are caching the response if (DeliciousLinkroll::CACHE_ENABLED) { $linkroll = $this->getFromCache(); if ($linkroll != NULL) { return $this->createXhtml($linkroll); } } $linkroll = $this->getFromDelicious(); if ($linkroll != NULL) { $this->sendToCache($linkroll); return $this->createXhtml($linkroll); } $this->sendError(DeliciousLinkroll::ERROR_NO_DATA); return NULL; } /** * Creates the xhtml containing the bookmarks. * * @param $data Array containing the delicious bookmarks * * @return String containing Xhtml * */ private function createXhtml(array $data = NULL) { if ($data == NULL) { $this->sendError(DeliciousLinkroll::ERROR_HTML_DATA); return NULL; } $html = "\n" .'<ul id="' . $this->listId . '">'; // Loop through the bookmarks foreach ($data as $bookmark) { $url = $bookmark->{DeliciousLinkroll::DELICIOUS_JSON_URL}; $name = $bookmark->{DeliciousLinkroll::DELICIOUS_JSON_NAME}; $html .= "\n\t<li>"; $html .= '<a href="' . $url . '" title="' . $name . '">' . $name . '</a>'; // If we are showing tags if ($this->showTags) { $tags = $bookmark->{DeliciousLinkroll::DELICIOUS_JSON_TAGS}; $html .= "<span>"; foreach ($tags as $tag) { $html .= '<a href="' . DeliciousLinkroll::DELICIOUS_URL . $this->username . '/' . $tag . '" title="' . $this->username . '\'s ' . $tag . ' bookmarks">' . $tag . '</a> '; } $html .= '</span>'; } $html .= '</li>'; } $html .= '</ul>'; return $html; } /** * Fetches the JSON request from the delicious feed via curl. Returns * an array if request was successful, Null otherwise. * * @return Array containing bookmark data from the delicious feed * */ private function getFromDelicious() { $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, DeliciousLinkroll::DELICIOUS_FEED_URL . $this->username . '?' . DeliciousLinkroll::DELICIOUS_COUNT_PARAM . '=' . $this->count); curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, DeliciousLinkroll::CURL_TIMEOUT); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); $curlResponse = curl_exec($curl); curl_close($curl); // If curl failed, return NULL if (empty($curlResponse)) { $this->sendError(DeliciousLinkroll::ERROR_CURL_FAILED); return NULL; } $decoded = json_decode($curlResponse); // Make sure the JSON decoded correctly if (!$decoded) { $this->sendError(DeliciousLinkroll::ERROR_JSON_DECODE); return NULL; } return $decoded; } /** * Returns the cached data if it's parsed successfully and not stale. * * @return Cached array containing bookmark data from the delicious feed * */ private function getFromCache() { $cache = file_get_contents(DeliciousLinkroll::CACHE_LOCATION); // Confirm we were able to read the cache if (!$cache) { return NULL; } $cache = unserialize($cache); // Confirm the cache was unserialized correctly if (!is_array($cache)) { $this->sendError(DeliciousLinkroll::ERROR_CACHE_UNSERIALIZE); return NULL; } $currentTime = time(); $cachedTime = $cache[0]; // Confirm the cache isn't stale if (($currentTime - $cachedTime) < DeliciousLinkroll::CACHE_LIFETIME) { return $cache[1]; } return NULL; } /** * Stores the passed in data to a cache file. * * @param $data Array containing the data we want to cache * * @return True if cached successfully * */ private function sendToCache(array $data = NULL) { if ($data == NULL) { $this->sendError(DeliciousLinkroll::WARNING_CACHE_DATA); return false; } $fileReference = fopen(DeliciousLinkroll::CACHE_LOCATION, 'w'); // Confirm we have a valid file reference if (!$fileReference) { if (!is_dir(dirname($cache))) { $this->sendError(DeliciousLinkroll::ERROR_CACHE_DIRECTORY); } if (!is_file($cache)) { $this->sendError(DeliciousLinkroll::ERROR_CACHE_FILE); } if (!is_writable($cache)) { $this->sendError(DeliciousLinkroll::ERROR_CACHE_PERMISSIONS); } return false; } $dataForCache = serialize(array(time(), $data)); $writeSuccess = fwrite($fileReference, $dataForCache); fclose($fileReference); return true; } /** * Catches all exceptions thrown from this class. If debug mode is active * echos them as they are handled. * * @param $exception The exception object * * @return Null * */ private function sendError($error) { if (!DeliciousLinkroll::DEBUG_ACTIVE) { return; } echo "<br/>" . $error; } } ?>