First commit

This commit is contained in:
Pierre Hubert
2016-11-19 12:08:12 +01:00
commit 990540b2b9
4706 changed files with 931207 additions and 0 deletions

97
3rdparty/luminous/src/cache/cache.class.php vendored Executable file
View 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
View 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
View 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
View 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