mirror of
https://github.com/pierre42100/comunic
synced 2025-07-12 13:02:59 +00:00
First commit
This commit is contained in:
97
3rdparty/luminous/src/cache/cache.class.php
vendored
Executable file
97
3rdparty/luminous/src/cache/cache.class.php
vendored
Executable file
@ -0,0 +1,97 @@
|
||||
<?php
|
||||
/// @cond ALL
|
||||
|
||||
/**
|
||||
* Cache superclass provides a skeleton for implementations using the filesystem
|
||||
* or SQL, or anything else.
|
||||
*/
|
||||
abstract class LuminousCache {
|
||||
|
||||
protected $gz = true;
|
||||
protected $id = null;
|
||||
protected $timeout = 0;
|
||||
protected $cache_hit = false;
|
||||
private $use_cache = true;
|
||||
private $creation_check = false;
|
||||
|
||||
private $errors = array();
|
||||
|
||||
public function __construct($id) {
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
public function set_purge_time($seconds) {
|
||||
$this->timeout = $seconds;
|
||||
}
|
||||
|
||||
private function _compress($data) {
|
||||
return $this->gz? gzcompress($data) : $data;
|
||||
}
|
||||
private function _decompress($data) {
|
||||
return $this->gz? gzuncompress($data) : $data;
|
||||
}
|
||||
|
||||
protected function log_error($msg) {
|
||||
$this->errors[] = $msg;
|
||||
}
|
||||
|
||||
public function has_errors() { return !empty($this->errrors); }
|
||||
public function errors() { return $this->errors; }
|
||||
|
||||
protected abstract function _create();
|
||||
protected abstract function _read();
|
||||
protected abstract function _write($data);
|
||||
protected abstract function _update();
|
||||
|
||||
protected abstract function _purge();
|
||||
|
||||
private function purge() {
|
||||
assert($this->creation_check);
|
||||
if ($this->use_cache)
|
||||
$this->_purge();
|
||||
}
|
||||
|
||||
private function create() {
|
||||
if ($this->creation_check) return;
|
||||
$this->creation_check = true;
|
||||
if (!$this->_create()) {
|
||||
$this->use_cache = false;
|
||||
} else {
|
||||
$this->purge();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Reads from the cache
|
||||
* @returns the cached string or @c null
|
||||
*/
|
||||
public function read() {
|
||||
$this->create();
|
||||
if (!$this->use_cache) return null;
|
||||
|
||||
$contents = $this->_read();
|
||||
if ($contents !== false) {
|
||||
$this->cache_hit = true;
|
||||
$contents = $this->_decompress($contents);
|
||||
$this->_update();
|
||||
return $contents;
|
||||
} else return null;
|
||||
}
|
||||
/**
|
||||
* @brief Writes into the cache
|
||||
* @param $data the data to write
|
||||
*/
|
||||
public function write($data) {
|
||||
$this->create();
|
||||
$this->purge();
|
||||
if (!$this->cache_hit && $this->use_cache)
|
||||
$this->_write($this->_compress($data));
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @endcond
|
||||
// ends 'ALL'
|
150
3rdparty/luminous/src/cache/fscache.class.php
vendored
Executable file
150
3rdparty/luminous/src/cache/fscache.class.php
vendored
Executable file
@ -0,0 +1,150 @@
|
||||
<?php
|
||||
/// @cond ALL
|
||||
|
||||
/**
|
||||
* File system cache driver
|
||||
* @brief The FS cache driver handles storing the cache on the filesystem
|
||||
*
|
||||
* The general structure of the cache is as follows:
|
||||
* @c /cache_dir/prefix/cache_id
|
||||
*
|
||||
* @c cache_dir is the root cache directory (normally luminous/cache),
|
||||
* @c prefix is used to separate things out into multiple locations - we take
|
||||
* the first two characters of the @c cache_id just to reduce the number of
|
||||
* files in any one directory (and maybe on some filesystems this allows
|
||||
* slightly faster lookups?).
|
||||
* @c cache_id is the unique identifier of the input string (with its first
|
||||
* two character missing, for @c prefix).
|
||||
*
|
||||
* This driver implements necessary functions for reading/writing the cache
|
||||
* and performing maintenance.
|
||||
*
|
||||
*/
|
||||
class LuminousFileSystemCache extends LuminousCache {
|
||||
|
||||
/// root cache directory
|
||||
private $dir = null;
|
||||
|
||||
/// full path to the cached file (for convenience)
|
||||
private $path = null;
|
||||
|
||||
/// subdir within the cache - we factor out the first two
|
||||
/// characters of the filename, this reduces the number of files in
|
||||
/// any one folder.
|
||||
private $subdir = null;
|
||||
|
||||
/// the base filename of the cached file
|
||||
private $filename = null;
|
||||
|
||||
public function __construct($id) {
|
||||
$this->dir = luminous::root() . '/cache/';
|
||||
$this->subdir = substr($id, 0, 2);
|
||||
$this->filename = substr($id, 2);
|
||||
|
||||
$this->path = rtrim($this->dir, '/') . '/' .
|
||||
$this->subdir . '/' . $this->filename;
|
||||
|
||||
parent::__construct($id);
|
||||
}
|
||||
|
||||
protected function _log_error($file, $msg) {
|
||||
$this->log_error( str_replace('%s', "\"$file\"", $msg) . "\n"
|
||||
. "File exists: " . var_export(file_exists($file), true) . "\n"
|
||||
. "Readable?: " . var_export(is_readable($file), true) . "\n"
|
||||
. "Writable?: " . var_export(is_writable($file), true) . "\n"
|
||||
. (!file_exists($this->dir)?
|
||||
"Your cache dir (\"{$this->dir}\") does not exist! \n" : '' )
|
||||
. (file_exists($this->dir) && !is_writable($this->dir)?
|
||||
"Your cache dir (\"{$this->dir}\") is not writable! \n" : '' )
|
||||
);
|
||||
}
|
||||
|
||||
protected function _create() {
|
||||
$target = $this->dir . '/' . $this->subdir;
|
||||
if (!@mkdir($target, 0777, true) && !is_dir($target)) {
|
||||
$this->_log_error($target, "%s does not exist, and cannot create.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function _update() {
|
||||
if (!(@touch($this->path))) {
|
||||
$this->_log_error($this->path, "Failed to update (touch) %s");
|
||||
}
|
||||
}
|
||||
|
||||
protected function _read() {
|
||||
$contents = false;
|
||||
if (file_exists($this->path)) {
|
||||
$contents = @file_get_contents($this->path);
|
||||
if ($contents === false)
|
||||
$this->_log_error($this->path, 'Failed to read %s"');
|
||||
}
|
||||
return $contents;
|
||||
}
|
||||
|
||||
protected function _write($data) {
|
||||
if (@file_put_contents($this->path, $data, LOCK_EX) === false) {
|
||||
$this->_log_error($this->path, "Error writing to %s");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Purges the contents of a directory recursively
|
||||
*/
|
||||
private function _purge_recurse($dir) {
|
||||
$base = $dir . '/';
|
||||
$time = time();
|
||||
if (substr($dir, 0, strlen($this->dir)) !== $this->dir) {
|
||||
// uh oh, we somehow tried to escape from the cache directory
|
||||
assert(0);
|
||||
return;
|
||||
}
|
||||
foreach(scandir($dir) as $f) {
|
||||
$fn = $base . $f;
|
||||
|
||||
if ($f[0] === '.') continue;
|
||||
|
||||
if (is_dir($fn)) {
|
||||
$this->_purge_recurse($fn);
|
||||
}
|
||||
else {
|
||||
$update = filemtime($fn);
|
||||
if ($time - $update > $this->timeout) {
|
||||
unlink($fn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function _purge() {
|
||||
if ($this->timeout <= 0) return;
|
||||
$purge_file = $this->dir . '/.purgedata';
|
||||
if (!file_exists($purge_file)) @touch($purge_file);
|
||||
$last = 0;
|
||||
$fh = @fopen($purge_file, 'r+');
|
||||
if (!$fh) {
|
||||
$this->_log_error($purge_file,
|
||||
"Error encountered opening %s for writing");
|
||||
return;
|
||||
}
|
||||
$time = time();
|
||||
if (flock($fh, LOCK_EX)) {
|
||||
if (filesize($purge_file))
|
||||
$last = (int)fread($fh, filesize($purge_file));
|
||||
else $last = 0;
|
||||
if ($time - $last > 60*60*24) {
|
||||
rewind($fh);
|
||||
ftruncate($fh, 0);
|
||||
rewind($fh);
|
||||
fwrite($fh, $time);
|
||||
$this->_purge_recurse($this->dir);
|
||||
}
|
||||
flock($fh, LOCK_UN);
|
||||
fclose($fh);
|
||||
}
|
||||
}
|
||||
}
|
||||
/// @endcond
|
20
3rdparty/luminous/src/cache/sql/cache.mysql
vendored
Executable file
20
3rdparty/luminous/src/cache/sql/cache.mysql
vendored
Executable file
@ -0,0 +1,20 @@
|
||||
CREATE TABLE IF NOT EXISTS `luminous_cache`
|
||||
(
|
||||
id INT NOT NULL AUTO_INCREMENT,
|
||||
-- this is the cache ID, it's the hex representation of an MD5sum.
|
||||
cache_id CHAR(32) NOT NULL UNIQUE,
|
||||
-- cached output
|
||||
output MEDIUMTEXT NOT NULL,
|
||||
-- date of insertion
|
||||
insert_date INT NOT NULL,
|
||||
-- date of most recent hit
|
||||
hit_date INT NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
-- we create an index on cache ID because it's what's most interesting, but in reality, we don't
|
||||
-- usually need to worry about many bytes. 6 chars gives us 3 bytes,
|
||||
-- or roughly 16 million combinations
|
||||
INDEX(cache_id(6)),
|
||||
INDEX(hit_date)
|
||||
) ENGINE = MYISAM;
|
||||
|
||||
-- we explictly set MyISAM because at least on my Xampp installation, innodb is painfully slow
|
149
3rdparty/luminous/src/cache/sqlcache.class.php
vendored
Executable file
149
3rdparty/luminous/src/cache/sqlcache.class.php
vendored
Executable file
@ -0,0 +1,149 @@
|
||||
<?php
|
||||
/// @cond ALL
|
||||
class LuminousSQLSafetyException extends Exception {}
|
||||
|
||||
/*
|
||||
* A note regarding escaping:
|
||||
* Escaping is hard because we don't want to rely on an RBDMS specific escaping
|
||||
* function.
|
||||
* Therefore:
|
||||
* All the data and queries are specifically designed such that escaping is
|
||||
* unnecessary. String types are either b64 or b16, which means no inconvenient
|
||||
* characters, and integer types are, well, integers.
|
||||
*/
|
||||
class LuminousSQLCache extends LuminousCache {
|
||||
static $table_name = 'luminous_cache';
|
||||
static $queries = array(
|
||||
|
||||
// FIXME: INSERT IGNORE is MySQL specific.
|
||||
// we do need an ignore on duplicate because there's a race condition
|
||||
// between reading from the cache and then writing into it if the
|
||||
// read failed
|
||||
'insert' => 'INSERT IGNORE INTO `%s` (cache_id, output, insert_date, hit_date)
|
||||
VALUES("%s", "%s", %d, %d);',
|
||||
'update' => 'UPDATE `%s` SET hit_date=%d WHERE cache_id="%s";',
|
||||
'select' => 'SELECT output FROM `%s` WHERE cache_id="%s";',
|
||||
'purge' => 'DELETE FROM `%s` WHERE hit_date <= %d AND cache_id != "last_purge";',
|
||||
'get_purge_time' => 'SELECT hit_date FROM `%s` WHERE cache_id="last_purge" LIMIT 1;',
|
||||
'set_purge_time' => 'UPDATE `%s` SET hit_date = %d WHERE cache_id="last_purge";',
|
||||
'set_purge_time_initial' => 'INSERT IGNORE INTO `%s` (cache_id, hit_date)
|
||||
VALUES ("last_purge", %d);'
|
||||
);
|
||||
|
||||
private $sql_function = null;
|
||||
|
||||
public function set_sql_function($func) {
|
||||
$this->sql_function = $func;
|
||||
}
|
||||
|
||||
private static function _safety_check($string) {
|
||||
// we should only be handling very restricted data in queries.
|
||||
// http://en.wikipedia.org/wiki/Base64#Variants_summary_table
|
||||
if (is_int($string)
|
||||
|| (is_string($string)
|
||||
&& preg_match('@^[a-zA-Z0-9\-\+=_/\.:!]*$@i', $string)))
|
||||
return $string;
|
||||
else {
|
||||
throw new LuminousSQLSafetyException();
|
||||
}
|
||||
}
|
||||
|
||||
private function _query($sql) {
|
||||
|
||||
return call_user_func($this->sql_function, $sql);
|
||||
}
|
||||
|
||||
protected function _create() {
|
||||
try {
|
||||
if (!is_callable($this->sql_function))
|
||||
throw new Exception('LuminousSQLCache does not have a callable SQL function');
|
||||
$r = $this->_query(file_get_contents(dirname(__FILE__) . '/sql/cache.mysql'));
|
||||
if ($r === false)
|
||||
throw new Exception('Creation of cache table failed (query returned false)');
|
||||
} catch(Exception $e) {
|
||||
$this->log_error($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function _update() {
|
||||
$this->_query(
|
||||
sprintf(self::$queries['update'],
|
||||
self::_safety_check(self::$table_name),
|
||||
time(),
|
||||
self::_safety_check($this->id)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
protected function _read() {
|
||||
$ret = false;
|
||||
try {
|
||||
$ret = $this->_query(
|
||||
sprintf(self::$queries['select'],
|
||||
self::_safety_check(self::$table_name),
|
||||
self::_safety_check($this->id)
|
||||
)
|
||||
);
|
||||
if (!empty($ret) && isset($ret[0]) && isset($ret[0]['output'])) {
|
||||
return base64_decode($ret[0]['output']);
|
||||
}
|
||||
} catch (LuminousSQLSafetyException $e) {}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function _write($data) {
|
||||
$data = base64_encode($data);
|
||||
$time = time();
|
||||
// try {
|
||||
$this->_query(sprintf(self::$queries['insert'],
|
||||
self::_safety_check(self::$table_name),
|
||||
self::_safety_check($this->id),
|
||||
self::_safety_check($data),
|
||||
self::_safety_check($time),
|
||||
self::_safety_check($time)
|
||||
));
|
||||
// } catch(LuminousSQLSafetyException $e) {}
|
||||
}
|
||||
|
||||
protected function _purge() {
|
||||
if ($this->timeout <= 0) return;
|
||||
$purge_time_ = $this->_query(
|
||||
sprintf(self::$queries['get_purge_time'],
|
||||
self::_safety_check(self::$table_name),
|
||||
self::_safety_check(time())
|
||||
)
|
||||
);
|
||||
$purge_time = 0;
|
||||
if ($purge_time_ !== false
|
||||
&& !empty($purge_time_) && isset($purge_time_[0]['hit_date'])) {
|
||||
$purge_time = $purge_time_[0]['hit_date'];
|
||||
} else {
|
||||
// we need to insert the record
|
||||
$this->_query(
|
||||
sprintf(self::$queries['set_purge_time_initial'],
|
||||
self::_safety_check(self::$table_name),
|
||||
self::_safety_check(time())
|
||||
)
|
||||
);
|
||||
}
|
||||
if ($purge_time < time() - 60*60*24) {
|
||||
// XXX: does this need to be in a try block?
|
||||
try {
|
||||
$this->_query(
|
||||
sprintf(self::$queries['purge'],
|
||||
self::_safety_check(self::$table_name),
|
||||
self::_safety_check(time() - $this->timeout)));
|
||||
} catch(LuminousSQLSafetyException $e) {}
|
||||
$this->_query(
|
||||
sprintf(self::$queries['set_purge_time'],
|
||||
self::_safety_check(self::$table_name),
|
||||
self::_safety_check(time())
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @endcond
|
Reference in New Issue
Block a user