--- /dev/null
+<?php
+/**
+ * Cache utilities
+ */
+
+/**
+ * Purges all cached pages
+ *
+ * @param string $pageCacheDir page cache directory
+ */
+function purgeCachedPages($pageCacheDir)
+{
+ if (! is_dir($pageCacheDir)) {
+ return;
+ }
+
+ // TODO: check write access to the cache directory
+
+ $handler = opendir($pageCacheDir);
+ if ($handler == false) {
+ return;
+ }
+
+ while (($filename = readdir($handler)) !== false) {
+ if (endsWith($filename, '.cache')) {
+ unlink($pageCacheDir.'/'.$filename);
+ }
+ }
+ closedir($handler);
+}
+
+/**
+ * Invalidates caches when the database is changed or the user logs out.
+ *
+ * @param string $pageCacheDir page cache directory
+ */
+function invalidateCaches($pageCacheDir)
+{
+ // Purge cache attached to session.
+ if (isset($_SESSION['tags'])) {
+ unset($_SESSION['tags']);
+ }
+
+ // Purge page cache shared by sessions.
+ purgeCachedPages($pageCacheDir);
+}
--- /dev/null
+<?php
+/**
+ * Simple cache system, mainly for the RSS/ATOM feeds
+ */
+class CachedPage
+{
+ // Directory containing page caches
+ private $cacheDir;
+
+ // Full URL of the page to cache -typically the value returned by pageUrl()
+ private $url;
+
+ // Should this URL be cached (boolean)?
+ private $shouldBeCached;
+
+ // Name of the cache file for this URL
+ private $filename;
+
+ /**
+ * Creates a new CachedPage
+ *
+ * @param string $cacheDir page cache directory
+ * @param string $url page URL
+ * @param bool $shouldBeCached whether this page needs to be cached
+ */
+ public function __construct($cacheDir, $url, $shouldBeCached)
+ {
+ // TODO: check write access to the cache directory
+ $this->cacheDir = $cacheDir;
+ $this->url = $url;
+ $this->filename = $this->cacheDir.'/'.sha1($url).'.cache';
+ $this->shouldBeCached = $shouldBeCached;
+ }
+
+ /**
+ * Returns the cached version of a page, if it exists and should be cached
+ *
+ * @return a cached version of the page if it exists, null otherwise
+ */
+ public function cachedVersion()
+ {
+ if (!$this->shouldBeCached) {
+ return null;
+ }
+ if (is_file($this->filename)) {
+ return file_get_contents($this->filename);
+ }
+ return null;
+ }
+
+ /**
+ * Puts a page in the cache
+ *
+ * @param string $pageContent XML content to cache
+ */
+ public function cache($pageContent)
+ {
+ if (!$this->shouldBeCached) {
+ return;
+ }
+ file_put_contents($this->filename, $pageContent);
+ }
+}
/**
* Saves the database from memory to disk
+ *
+ * @param string $pageCacheDir page cache directory
*/
- public function savedb()
+ public function savedb($pageCacheDir)
{
if (!$this->_loggedIn) {
// TODO: raise an Exception instead
$this->_datastore,
self::$phpPrefix.base64_encode(gzdeflate(serialize($this->_links))).self::$phpSuffix
);
- invalidateCaches();
+ invalidateCaches($pageCacheDir);
}
/**
return $linkDays;
}
}
-?>
}
// Shaarli library
+require_once 'application/Cache.php';
+require_once 'application/CachedPage.php';
require_once 'application/LinkDB.php';
require_once 'application/TimeZone.php';
require_once 'application/Utils.php';
}
-// -----------------------------------------------------------------------------------------------
-// Simple cache system (mainly for the RSS/ATOM feeds).
-
-class pageCache
-{
- private $url; // Full URL of the page to cache (typically the value returned by pageUrl())
- private $shouldBeCached; // boolean: Should this url be cached?
- private $filename; // Name of the cache file for this url.
-
- /*
- $url = URL (typically the value returned by pageUrl())
- $shouldBeCached = boolean. If false, the cache will be disabled.
- */
- public function __construct($url,$shouldBeCached)
- {
- $this->url = $url;
- $this->filename = $GLOBALS['config']['PAGECACHE'].'/'.sha1($url).'.cache';
- $this->shouldBeCached = $shouldBeCached;
- }
-
- // If the page should be cached and a cached version exists,
- // returns the cached version (otherwise, return null).
- public function cachedVersion()
- {
- if (!$this->shouldBeCached) return null;
- if (is_file($this->filename)) { return file_get_contents($this->filename); exit; }
- return null;
- }
-
- // Put a page in the cache.
- public function cache($page)
- {
- if (!$this->shouldBeCached) return;
- file_put_contents($this->filename,$page);
- }
-
- // Purge the whole cache.
- // (call with pageCache::purgeCache())
- public static function purgeCache()
- {
- if (is_dir($GLOBALS['config']['PAGECACHE']))
- {
- $handler = opendir($GLOBALS['config']['PAGECACHE']);
- if ($handler!==false)
- {
- while (($filename = readdir($handler))!==false)
- {
- if (endsWith($filename,'.cache')) { unlink($GLOBALS['config']['PAGECACHE'].'/'.$filename); }
- }
- closedir($handler);
- }
- }
- }
-
-}
-
-
// -----------------------------------------------------------------------------------------------
// Log to text file
function logm($message)
// Cache system
$query = $_SERVER["QUERY_STRING"];
- $cache = new pageCache(pageUrl(),startsWith($query,'do=rss') && !isLoggedIn());
- $cached = $cache->cachedVersion(); if (!empty($cached)) { echo $cached; exit; }
+ $cache = new CachedPage(
+ $GLOBALS['config']['PAGECACHE'],
+ pageUrl(),
+ startsWith($query,'do=rss') && !isLoggedIn()
+ );
+ $cached = $cache->cachedVersion();
+ if (! empty($cached)) {
+ echo $cached;
+ exit;
+ }
// If cached was not found (or not usable), then read the database and build the response:
$LINKSDB = new LinkDB(
// Cache system
$query = $_SERVER["QUERY_STRING"];
- $cache = new pageCache(pageUrl(),startsWith($query,'do=atom') && !isLoggedIn());
- $cached = $cache->cachedVersion(); if (!empty($cached)) { echo $cached; exit; }
- // If cached was not found (or not usable), then read the database and build the response:
+ $cache = new CachedPage(
+ $GLOBALS['config']['PAGECACHE'],
+ pageUrl(),
+ startsWith($query,'do=atom') && !isLoggedIn()
+ );
+ $cached = $cache->cachedVersion();
+ if (!empty($cached)) {
+ echo $cached;
+ exit;
+ }
-// Read links from database (and filter private links if used it not logged in).
+ // If cached was not found (or not usable), then read the database and build the response:
+ // Read links from database (and filter private links if used it not logged in).
$LINKSDB = new LinkDB(
$GLOBALS['config']['DATASTORE'],
isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI'],
function showDailyRSS() {
// Cache system
$query = $_SERVER["QUERY_STRING"];
- $cache = new pageCache(pageUrl(), startsWith($query, 'do=dailyrss') && !isLoggedIn());
+ $cache = new CachedPage(
+ $GLOBALS['config']['PAGECACHE'],
+ pageUrl(),
+ startsWith($query,'do=dailyrss') && !isLoggedIn()
+ );
$cached = $cache->cachedVersion();
if (!empty($cached)) {
echo $cached;
// -------- User wants to logout.
if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=logout'))
{
- invalidateCaches();
+ invalidateCaches($GLOBALS['config']['PAGECACHE']);
logout();
header('Location: ?');
exit;
$value['tags']=trim(implode(' ',$tags));
$LINKSDB[$key]=$value;
}
- $LINKSDB->savedb(); // Save to disk.
+ $LINKSDB->savedb($GLOBALS['config']['PAGECACHE']); // Save to disk.
echo '<script>alert("Tag was removed from '.count($linksToAlter).' links.");document.location=\'?\';</script>';
exit;
}
$value['tags']=trim(implode(' ',$tags));
$LINKSDB[$key]=$value;
}
- $LINKSDB->savedb(); // Save to disk.
+ $LINKSDB->savedb($GLOBALS['config']['PAGECACHE']); // Save to disk.
echo '<script>alert("Tag was renamed in '.count($linksToAlter).' links.");document.location=\'?searchtags='.urlencode($_POST['totag']).'\';</script>';
exit;
}
'linkdate'=>$linkdate,'tags'=>str_replace(',',' ',$tags));
if ($link['title']=='') $link['title']=$link['url']; // If title is empty, use the URL as title.
$LINKSDB[$linkdate] = $link;
- $LINKSDB->savedb(); // Save to disk.
+ $LINKSDB->savedb($GLOBALS['config']['PAGECACHE']); // Save to disk.
pubsubhub();
// If we are called from the bookmarklet, we must close the popup:
// - we are protected from XSRF by the token.
$linkdate=$_POST['lf_linkdate'];
unset($LINKSDB[$linkdate]);
- $LINKSDB->savedb(); // save to disk
+ $LINKSDB->savedb($GLOBALS['config']['PAGECACHE']); // save to disk
// If we are called from the bookmarklet, we must close the popup:
if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo '<script>self.close();</script>'; exit; }
}
}
}
- $LINKSDB->savedb();
+ $LINKSDB->savedb($GLOBALS['config']['PAGECACHE']);
echo '<script>alert("File '.json_encode($filename).' ('.$filesize.' bytes) was successfully processed: '.$import_count.' links imported.");document.location=\'?\';</script>';
}
return true;
}
-// Invalidate caches when the database is changed or the user logs out.
-// (e.g. tags cache).
-function invalidateCaches()
-{
- unset($_SESSION['tags']); // Purge cache attached to session.
- pageCache::purgeCache(); // Purge page cache shared by sessions.
-}
-
try {
mergeDeprecatedConfig($GLOBALS, isLoggedIn());
} catch(Exception $e) {
--- /dev/null
+<?php
+/**
+ * Cache tests
+ */
+
+// required to access $_SESSION array
+session_start();
+
+require_once 'application/Cache.php';
+
+/**
+ * Unitary tests for cached pages
+ */
+class CachedTest extends PHPUnit_Framework_TestCase
+{
+ // test cache directory
+ protected static $testCacheDir = 'tests/dummycache';
+
+ // dummy cached file names / content
+ protected static $pages = array('a', 'toto', 'd7b59c');
+
+
+ /**
+ * Populate the cache with dummy files
+ */
+ public function setUp()
+ {
+ if (! is_dir(self::$testCacheDir)) {
+ mkdir(self::$testCacheDir);
+ }
+
+ foreach (self::$pages as $page) {
+ file_put_contents(self::$testCacheDir.'/'.$page.'.cache', $page);
+ }
+ }
+
+ /**
+ * Purge cached pages
+ */
+ public function testPurgeCachedPages()
+ {
+ purgeCachedPages(self::$testCacheDir);
+ foreach (self::$pages as $page) {
+ $this->assertFileNotExists(self::$testCacheDir.'/'.$page.'.cache');
+ }
+ }
+
+ /**
+ * Purge cached pages and session cache
+ */
+ public function testInvalidateCaches()
+ {
+ $this->assertArrayNotHasKey('tags', $_SESSION);
+ $_SESSION['tags'] = array('goodbye', 'cruel', 'world');
+
+ invalidateCaches(self::$testCacheDir);
+ foreach (self::$pages as $page) {
+ $this->assertFileNotExists(self::$testCacheDir.'/'.$page.'.cache');
+ }
+
+ $this->assertArrayNotHasKey('tags', $_SESSION);
+ }
+}
--- /dev/null
+<?php
+/**
+ * PageCache tests
+ */
+
+require_once 'application/CachedPage.php';
+
+/**
+ * Unitary tests for cached pages
+ */
+class CachedPageTest extends PHPUnit_Framework_TestCase
+{
+ // test cache directory
+ protected static $testCacheDir = 'tests/pagecache';
+ protected static $url = 'http://shaar.li/?do=atom';
+ protected static $filename;
+
+ /**
+ * Create the cache directory if needed
+ */
+ public static function setUpBeforeClass()
+ {
+ if (! is_dir(self::$testCacheDir)) {
+ mkdir(self::$testCacheDir);
+ }
+ self::$filename = self::$testCacheDir.'/'.sha1(self::$url).'.cache';
+ }
+
+ /**
+ * Reset the page cache
+ */
+ public function setUp()
+ {
+ if (file_exists(self::$filename)) {
+ unlink(self::$filename);
+ }
+ }
+
+ /**
+ * Create a new cached page
+ */
+ public function testConstruct()
+ {
+ new CachedPage(self::$testCacheDir, '', true);
+ new CachedPage(self::$testCacheDir, '', false);
+ new CachedPage(self::$testCacheDir, 'http://shaar.li/?do=rss', true);
+ new CachedPage(self::$testCacheDir, 'http://shaar.li/?do=atom', false);
+ }
+
+ /**
+ * Cache a page's content
+ */
+ public function testCache()
+ {
+ $page = new CachedPage(self::$testCacheDir, self::$url, true);
+
+ $this->assertFileNotExists(self::$filename);
+ $page->cache('<p>Some content</p>');
+ $this->assertFileExists(self::$filename);
+ $this->assertEquals(
+ '<p>Some content</p>',
+ file_get_contents(self::$filename)
+ );
+ }
+
+ /**
+ * "Cache" a page's content - the page is not to be cached
+ */
+ public function testShouldNotCache()
+ {
+ $page = new CachedPage(self::$testCacheDir, self::$url, false);
+
+ $this->assertFileNotExists(self::$filename);
+ $page->cache('<p>Some content</p>');
+ $this->assertFileNotExists(self::$filename);
+ }
+
+ /**
+ * Return a page's cached content
+ */
+ public function testCachedVersion()
+ {
+ $page = new CachedPage(self::$testCacheDir, self::$url, true);
+
+ $this->assertFileNotExists(self::$filename);
+ $page->cache('<p>Some content</p>');
+ $this->assertFileExists(self::$filename);
+ $this->assertEquals(
+ '<p>Some content</p>',
+ $page->cachedVersion()
+ );
+ }
+
+ /**
+ * Return a page's cached content - the file does not exist
+ */
+ public function testCachedVersionNoFile()
+ {
+ $page = new CachedPage(self::$testCacheDir, self::$url, true);
+
+ $this->assertFileNotExists(self::$filename);
+ $this->assertEquals(
+ null,
+ $page->cachedVersion()
+ );
+ }
+
+ /**
+ * Return a page's cached content - the page is not to be cached
+ */
+ public function testNoCachedVersion()
+ {
+ $page = new CachedPage(self::$testCacheDir, self::$url, false);
+
+ $this->assertFileNotExists(self::$filename);
+ $this->assertEquals(
+ null,
+ $page->cachedVersion()
+ );
+ }
+}
* Link datastore tests
*/
+require_once 'application/Cache.php';
require_once 'application/LinkDB.php';
require_once 'application/Utils.php';
require_once 'tests/utils/ReferenceLinkDB.php';
'tags'=>'unit test'
);
$testDB[$link['linkdate']] = $link;
-
- // TODO: move PageCache to a proper class/file
- function invalidateCaches() {}
-
- $testDB->savedb();
+ $testDB->savedb('tests');
$testDB = new LinkDB(self::$testDatastore, true, false);
$this->assertEquals($dbSize + 1, sizeof($testDB));
);
}
}
-?>
return $this->_privateCount;
}
}
-?>