Files
exoplasim/web/lib/filebase.class.php
T

287 lines
8.9 KiB
PHP

<?php
class Filebase
{
static function hash($s = false)
{
if($s === false) $s = time().random_int(0, 2147483647);
return hash('sha256', strtolower(trim((string)$s)));
}
static function validate_path_part($value, $label, $allow_slash = false)
{
$value = (string)$value;
if($value === '')
throw new InvalidArgumentException($label.' must not be empty');
if(strpos($value, "\0") !== false || strpos($value, "\\") !== false)
throw new InvalidArgumentException($label.' contains an unsafe path character');
$segments = $allow_slash ? explode('/', $value) : array($value);
foreach($segments as $segment)
{
if($segment === '' || $segment === '.' || $segment === '..')
throw new InvalidArgumentException($label.' contains an unsafe path segment');
if(!$allow_slash && strpos($segment, '/') !== false)
throw new InvalidArgumentException($label.' must be a single path segment');
}
return($value);
}
static function make_bucket_path($p)
{
$p = self::validate_path_part($p, 'bucket', true);
if(stristr($p, '/') !== false)
{
$seg = explode('/', $p);
$p = array_shift($seg);
return(substr($p, -2).'/'.$p.'/'.implode('/', $seg));
}
return(substr($p, -2).'/'.$p);
}
static function storage_path($class, $bucket)
{
$class = self::validate_path_part($class, 'class');
return(first($GLOBALS['config']['filebase']['path'], 'data/').$class.'/'.self::make_bucket_path($bucket));
}
static function data_filename($class, $bucket, $type)
{
$type = self::validate_path_part($type, 'type');
return(self::storage_path($class, $bucket).'/'.$type.'.json');
}
static function write_file($filename, $data)
{
$directory = dirname($filename);
if (!is_dir($directory) && !@mkdir($directory, 0700, true)) return false;
$fp = @fopen($filename, "c+");
if(!$fp)
{
Log::text('<ERR>', 'file_put_contents_ex('.$filename.') could not write file');
return;
}
if (flock($fp, LOCK_EX))
{
ftruncate($fp, 0);
rewind($fp);
$written = fwrite($fp, $data);
fflush($fp);
@chmod($filename, 0600);
flock($fp, LOCK_UN);
fclose($fp);
return $written === strlen($data);
}
else
{
Log::text('<ERR>', 'file_put_contents_ex('.$filename.') could not acquire lock');
}
fclose($fp);
return false;
}
static function delete_file($file_name)
{
unlink($file_name);
}
static function read_file($file_name)
{
if(!file_exists($file_name))
return('');
$fsz = filesize($file_name);
if($fsz == 0)
return('');
$fp = fopen($file_name, "rb+");
if(!$fp)
return('');
if (flock($fp, LOCK_SH)) {
$content = fread($fp, $fsz);
flock($fp, LOCK_UN);
} else {
Log::text('<ERR>', 'read_file('.$file_name.') could not acquire lock');
}
fclose($fp);
return($content);
}
static function write_data($class, $bucket, $type, $data)
{
$storage_path = self::storage_path($class, $bucket);
if(!file_exists($storage_path)) @mkdir($storage_path, 0774, true);
if(!file_exists($storage_path)) @mkdir($storage_path, 0700, true);
$json = json_encode($data);
if ($json === false) return false;
return self::write_file(self::data_filename($class, $bucket, $type), $json);
}
static function read_data($class, $bucket, $type)
{
return(json_decode(self::read_file(self::data_filename($class, $bucket, $type)), true));
}
static function delete_data($class, $bucket, $type)
{
return(self::delete_file(self::data_filename($class, $bucket, $type)));
}
static function get_data_filename($class, $bucket, $type)
{
return(self::data_filename($class, $bucket, $type));
}
static function list_bucket($class, $bucket)
{
$items = array();
$storage_path = self::storage_path($class, $bucket);
if(!is_dir($storage_path))
return($items);
foreach(scandir($storage_path) as $name)
{
if(substr($name, 0, 1) != '_' && trim($name) != '' && $name !== '.' && $name !== '..')
$items[] = $name;
}
return($items);
}
static function search_bucket($class, $bucket, $q)
{
$items = array();
$storage_path = self::storage_path($class, $bucket);
if(!is_dir($storage_path))
return($items);
foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($storage_path, FilesystemIterator::SKIP_DOTS)) as $file)
{
if(!$file->isFile())
continue;
if(substr($file->getFilename(), -5) !== '.json')
continue;
$content = @file_get_contents($file->getPathname());
if($content === false || strpos($content, $q) === false)
continue;
$name = substr($file->getPathname(), strlen($storage_path)+1, -5);
if(substr($name, 0, 1) != '_' && trim($name) != '')
$items[] = $name;
}
return($items);
}
static function delete_directory($dir)
{
if(!is_dir($dir))
return('');
foreach(scandir($dir) as $entry)
{
if($entry === '.' || $entry === '..')
continue;
$path = $dir.'/'.$entry;
if(is_dir($path) && !is_link($path))
{
$error = self::delete_directory($path);
if($error !== '') return($error);
}
else if(!@unlink($path))
{
return('could not delete '.$path);
}
}
if(!@rmdir($dir))
return('could not delete '.$dir);
return('');
}
static function delete_bucket($class, $bucket)
{
return(self::delete_directory(self::storage_path($class, $bucket)));
}
static function write_log($class, $bucket, $type, $data)
{
$storage_path = self::storage_path($class, $bucket);
if(!file_exists($storage_path)) @mkdir($storage_path, 0774, true);
WriteToFile($storage_path.'/'.self::validate_path_part($type, 'type').'.log', json_encode($data).chr(10));
}
static function read_log($class, $bucket, $type, $line_count = 8, $offset = false)
{
$storage_path = self::storage_path($class, $bucket);
return(get_json_tail($storage_path.'/'.self::validate_path_part($type, 'type').'.log', $line_count, $offset));
}
static function line_count($class, $bucket, $type)
{
$storage_path = self::storage_path($class, $bucket);
return(intval(trim(shell_exec('wc -l '.escapeshellarg($storage_path.'/'.self::validate_path_part($type, 'type').'.log')))));
}
static function get_json_tail($from_file, $line_count = 8, $offset = false)
{
if($offset > 0)
{
$lines = trim(shell_exec(
'tail -n '.escapeshellarg($offset+$line_count).' '.escapeshellarg($from_file).' | head -n '.escapeshellarg($line_count)));
}
else
{
$lines = trim(shell_exec(
'tail -n '.escapeshellarg($line_count).' '.escapeshellarg($from_file)));
}
return(json_lines($lines));
}
static function get_tail($from_file, $line_count = 8, $offset = false)
{
$line_count = intval($line_count);
if($offset > 0)
{
$lines = trim(shell_exec(
'tail -n '.escapeshellarg($offset+$line_count).' '.escapeshellarg($from_file).' | head -n '.escapeshellarg($line_count)));
}
else
{
$lines = trim(shell_exec(
'tail -n '.escapeshellarg($line_count).' '.escapeshellarg($from_file)));
}
return(explode(chr(10), $lines));
}
static function get_all_lines($from_file)
{
return(explode(chr(10), trim(file_get_contents($from_file))));
}
static function truncate_log($from_file, $lines = 128)
{
$lines = intval($lines);
$tmp = tempnam(sys_get_temp_dir(), 'trunc_');
shell_exec('tail -n '.$lines.' '.escapeshellarg($from_file).' > '.escapeshellarg($tmp).' && cp '.escapeshellarg($tmp).' '.escapeshellarg($from_file));
@unlink($tmp);
return true;
}
static function json_lines($lines)
{
if($lines == '')
{
return(array());
}
else
{
$result = array();
foreach(explode(chr(10), $lines) as $line)
$result[] = json_decode($line, true);
return($result);
}
}
}