diff options
Diffstat (limited to 'inc')
-rw-r--r-- | inc/dashboard.inc.php | 7 | ||||
-rw-r--r-- | inc/database.inc.php | 15 | ||||
-rw-r--r-- | inc/dictionary.inc.php | 15 | ||||
-rw-r--r-- | inc/event.inc.php | 16 | ||||
-rw-r--r-- | inc/module.inc.php | 63 | ||||
-rw-r--r-- | inc/paginate.inc.php | 2 | ||||
-rw-r--r-- | inc/permission.inc.php | 36 | ||||
-rw-r--r-- | inc/property.inc.php | 2 | ||||
-rw-r--r-- | inc/render.inc.php | 8 | ||||
-rw-r--r-- | inc/taskmanager.inc.php | 40 | ||||
-rw-r--r-- | inc/taskmanagercallback.inc.php | 9 | ||||
-rw-r--r-- | inc/trigger.inc.php | 33 | ||||
-rw-r--r-- | inc/user.inc.php | 69 | ||||
-rw-r--r-- | inc/util.inc.php | 30 |
14 files changed, 268 insertions, 77 deletions
diff --git a/inc/dashboard.inc.php b/inc/dashboard.inc.php index 3db42efb..d576a8f1 100644 --- a/inc/dashboard.inc.php +++ b/inc/dashboard.inc.php @@ -68,7 +68,7 @@ class Dashboard 'url' => urlencode($_SERVER['REQUEST_URI']), 'langs' => Dictionary::getLanguages(true), 'user' => User::getName(), - 'warning' => User::getName() !== false && User::getLastSeenEvent() < Property::getLastWarningId(), + 'warning' => User::getName() !== false && User::hasPermission('.eventlog.*') && User::getLastSeenEvent() < Property::getLastWarningId(), 'needsSetup' => User::getName() !== false && Property::getNeedsSetup() )); } @@ -103,5 +103,10 @@ class Dashboard { self::$subMenu[] = array('url' => $url, 'name' => $name); } + + public static function getSubmenus() + { + return self::$subMenu; + } }
\ No newline at end of file diff --git a/inc/database.inc.php b/inc/database.inc.php index 082b13b6..3b2414b5 100644 --- a/inc/database.inc.php +++ b/inc/database.inc.php @@ -77,6 +77,19 @@ class Database } /** + * Fetch the first column of the query as a plain list-of-values array. + * + * @return array|bool List of values representing first column of query + */ + public static function queryColumnArray($query, $args = array(), $ignoreError = null) + { + $res = self::simpleQuery($query, $args, $ignoreError); + if ($res === false) + return false; + return $res->fetchAll(PDO::FETCH_COLUMN, 0); + } + + /** * Execute the given query and return the number of rows affected. * Mostly useful for UPDATEs or INSERTs * @@ -132,7 +145,7 @@ class Database if (!isset(self::$statements[$query])) { self::$statements[$query] = self::$dbh->prepare($query); } else { - self::$statements[$query]->closeCursor(); + //self::$statements[$query]->closeCursor(); } $start = microtime(true); if (self::$statements[$query]->execute($args) === false) { diff --git a/inc/dictionary.inc.php b/inc/dictionary.inc.php index ee196f59..935d1f4e 100644 --- a/inc/dictionary.inc.php +++ b/inc/dictionary.inc.php @@ -17,6 +17,8 @@ class Dictionary { self::$languages = array(); foreach (glob('lang/??', GLOB_ONLYDIR) as $lang) { + if (!file_exists($lang . '/name.txt') && !file_exists($lang . '/flag.png')) + continue; $lang = basename($lang); if ($lang === '..') continue; @@ -28,10 +30,15 @@ class Dictionary if ($lang !== false && in_array($lang, self::$languages)) { setcookie('lang', $lang, time() + 60 * 60 * 24 * 30 * 12); $url = Request::get('url'); - if ($url === false && isset($_SERVER['HTTP_REFERER'])) + if ($url === false && isset($_SERVER['HTTP_REFERER'])) { $url = $_SERVER['HTTP_REFERER']; - if ($url === false) - $url = '?do=Main'; + } + $parts = parse_url($url); + if ($url === false || $parts === false || empty($parts['query'])) { + $url = '?do=main'; + } else { + $url = '?' . $parts['query']; + } Util::redirect($url); } @@ -191,6 +198,8 @@ class Dictionary foreach (self::$languages as $lang) { if (file_exists("lang/$lang/name.txt")) { $name = file_get_contents("lang/$lang/name.txt"); + } else { + $name = false; } if (!isset($name) || $name === false) { $name = $lang; diff --git a/inc/event.inc.php b/inc/event.inc.php index 66601607..4e68ab6d 100644 --- a/inc/event.inc.php +++ b/inc/event.inc.php @@ -24,6 +24,17 @@ class Event Property::clearList('cron.key.status'); Property::clearList('cron.key.blocked'); + // Hooks + foreach (Hook::load('bootup') as $hook) { + // Isolate for local vars + $fun = function() use ($hook) { + include_once($hook->file); + }; + $fun(); + } + + // TODO: Modularize (hooks) + // Tasks: fire away $mountStatus = false; $mountId = Trigger::mount(); @@ -98,8 +109,7 @@ class Event public static function serverIpChanged() { error_log('Server ip changed'); - global $tidIpxe; - $tidIpxe = Trigger::ipxe(); + Trigger::ipxe(); if (Module::isAvailable('sysconfig')) { // TODO: Modularize events ConfigModule::serverIpChanged(); } @@ -111,6 +121,8 @@ class Event public static function activeConfigChanged() { $task = Trigger::ldadp(); + if ($task === false) + return; TaskmanagerCallback::addCallback($task, 'ldadpStartup'); } diff --git a/inc/module.inc.php b/inc/module.inc.php index 7610c720..6d160787 100644 --- a/inc/module.inc.php +++ b/inc/module.inc.php @@ -35,7 +35,7 @@ class Module if ($module === false) return false; if ($activate) { - $module->activate(); + $module->activate(1, true); } return !$module->hasMissingDependencies(); } @@ -139,9 +139,11 @@ class Module */ private $category = false; + private $clientPlugin = false; private $depsMissing = false; private $depsChecked = false; private $activated = false; + private $directActivation = false; private $dependencies = array(); private $name; /** @@ -165,6 +167,9 @@ class Module if (isset($json['category']) && is_string($json['category'])) { $this->category = $json['category']; } + if (isset($json['client-plugin'])) { + $this->clientPlugin = (bool)$json['client-plugin']; + } $this->name = $name; } @@ -184,21 +189,33 @@ class Module return new $class(); } - public function activate($depth = 1) + public function activate($depth, $direct) { - if ($this->activated !== false || $this->depsMissing) - return $this->activated !== false; + if ($this->depsMissing) + return false; + if ($this->activated !== false && ($this->directActivation || !$direct)) + return true; + if ($depth === null && $direct === null) { + // This is the current page, always load its scripts + $this->clientPlugin = true; + $direct = true; + } + if ($this->activated === false) { + spl_autoload_register(function ($class) { + $file = 'modules/' . $this->name . '/inc/' . preg_replace('/[^a-z0-9]/', '', strtolower($class)) . '.inc.php'; + if (!file_exists($file)) + return; + require_once $file; + }); + } $this->activated = $depth; - spl_autoload_register(function($class) { - $file = 'modules/' . $this->name . '/inc/' . preg_replace('/[^a-z0-9]/', '', strtolower($class)) . '.inc.php'; - if (!file_exists($file)) - return; - require_once $file; - }); + if ($direct) { + $this->directActivation = true; + } foreach ($this->dependencies as $dep) { $get = self::get($dep); if ($get !== false) { - $get->activate($depth + 1); + $get->activate($depth + 1, $direct && $this->clientPlugin); } } return true; @@ -263,26 +280,26 @@ class Module return 'modules/' . $this->name; } - public function getScripts($externalOnly) + public function getScripts() { - if (!$externalOnly) { - if (!isset($this->scripts['clientscript.js']) && file_exists($this->getDir() . '/clientscript.js')) { - $this->scripts['clientscript.js'] = false; + if ($this->directActivation && $this->clientPlugin) { + if (!in_array('clientscript.js', $this->scripts) && file_exists($this->getDir() . '/clientscript.js')) { + $this->scripts[] = 'clientscript.js'; } - return array_keys($this->scripts); + return $this->scripts; } - return array_keys(array_filter($this->scripts)); + return []; } - public function getCss($externalOnly) + public function getCss() { - if (!$externalOnly) { - if (!isset($this->css['style.css']) && file_exists($this->getDir() . '/style.css')) { - $this->css['style.css'] = false; + if ($this->directActivation && $this->clientPlugin) { + if (!in_array('style.css', $this->css) && file_exists($this->getDir() . '/style.css')) { + $this->css[] = 'style.css'; } - return array_keys($this->css); + return $this->css; } - return array_keys(array_filter($this->css)); + return []; } } diff --git a/inc/paginate.inc.php b/inc/paginate.inc.php index cdb4adf1..b212e252 100644 --- a/inc/paginate.inc.php +++ b/inc/paginate.inc.php @@ -65,8 +65,6 @@ class Paginate $countQuery = preg_replace('/ORDER\s+BY\s.*?(\sASC|\sDESC|$)/is', '', $this->query); $countQuery = preg_replace('/SELECT\s.*?\sFROM\s/is', 'SELECT Count(*) AS rowcount FROM ', $countQuery); $countRes = Database::queryFirst($countQuery, $args); - $args['limit_start'] = $this->currentPage; - $args['limit_count'] = $this->perPage; $query = $this->query . ' LIMIT ' . ($this->currentPage * $this->perPage) . ', ' . $this->perPage; $retval = Database::simpleQuery($query, $args); $this->totalRows = (int)$countRes['rowcount']; diff --git a/inc/permission.inc.php b/inc/permission.inc.php index d04e3c3b..aaef6ba6 100644 --- a/inc/permission.inc.php +++ b/inc/permission.inc.php @@ -15,5 +15,41 @@ class Permission return self::$permissions[$permission]; } + + // TODO: Doc/Refactor + public static function addGlobalTags(&$array, $locationid, $disabled, $noneAvailDisabled = null) + { + if (Module::get('permissionmanager') === false) + return; + $one = false; + foreach ($disabled as $perm) { + if (User::hasPermission($perm, $locationid)) { + $one = true; + continue; + } + if (strpos($perm, '.') === false) { + $array[$perm] = ['disabled' => 'disabled', 'readonly' => 'readonly']; + continue; + } + $temp =& $array; + foreach (explode('.', $perm) as $sub) { + if (empty($sub) || $sub === '*') + continue; + $temp =& $temp[$sub]; + } + $temp = ['disabled' => 'disabled', 'readonly' => 'readonly']; + } + if (!$one && !is_null($noneAvailDisabled)) { + $array[$noneAvailDisabled]['disabled'] = true; + } + } + + public static function moduleHasPermissions($moduleId) + { + if (Module::get('permissionmanager') === false) + return true; + return file_exists('modules/' . $moduleId . '/permissions/permissions.json'); + } + } diff --git a/inc/property.inc.php b/inc/property.inc.php index 56adb823..b69be1f8 100644 --- a/inc/property.inc.php +++ b/inc/property.inc.php @@ -168,7 +168,7 @@ class Property if (!Taskmanager::isFinished($task)) { $task = Taskmanager::waitComplete($task['id'], 5000); } - if ($task['statusCode'] !== TASK_FINISHED || !isset($task['data']['content'])) { + if ($task['statusCode'] !== Taskmanager::TASK_FINISHED || !isset($task['data']['content'])) { return isset($task['data']['error']) ? $task['data']['error'] : 'Timeout'; } $data = json_decode($task['data']['content'], true); diff --git a/inc/render.inc.php b/inc/render.inc.php index 0ce39dbe..4da0567e 100644 --- a/inc/render.inc.php +++ b/inc/render.inc.php @@ -84,7 +84,7 @@ class Render '; // Include any module specific styles foreach ($modules as $module) { - $files = $module->getCss($module !== $pageModule); + $files = $module->getCss(); foreach ($files as $file) { echo '<link href="', $module->getDir(), '/', $file, '" rel="stylesheet" media="screen">'; } @@ -113,7 +113,7 @@ class Render <script src="script/slx-fixes.js"></script> '; foreach ($modules as $module) { - $files = $module->getScripts($module !== $pageModule); + $files = $module->getScripts(); foreach ($files as $file) { echo '<script src="', $module->getDir(), '/', $file, '"></script>'; } @@ -213,7 +213,7 @@ class Render * @param string $module name of module to load template from; defaults to currently active module * @return string Rendered template */ - public static function parse($template, $params = false, $module = false) + public static function parse($template, $params = false, $module = false, $lang = false) { if ($module === false && class_exists('Page')) { $module = Page::getModule()->getIdentifier(); @@ -228,7 +228,7 @@ class Render } // Now find all language tags in this array if (preg_match_all('/{{\s*(lang_.+?)\s*}}/', $html, $out) > 0) { - $dictionary = Dictionary::getArray($module, 'template-tags'); + $dictionary = Dictionary::getArray($module, 'template-tags', $lang); $fallback = false; foreach ($out[1] as $tag) { if ($fallback === false && empty($dictionary[$tag])) { diff --git a/inc/taskmanager.inc.php b/inc/taskmanager.inc.php index cdc90f55..dab950ed 100644 --- a/inc/taskmanager.inc.php +++ b/inc/taskmanager.inc.php @@ -6,6 +6,13 @@ class Taskmanager { + const NO_SUCH_TASK = 'NO_SUCH_TASK'; + const TASK_FINISHED = 'TASK_FINISHED'; + const TASK_ERROR = 'TASK_ERROR'; + const TASK_WAITING = 'TASK_WAITING'; + const NO_SUCH_INSTANCE = 'NO_SUCH_INSTANCE'; + const TASK_PROCESSING = 'TASK_PROCESSING'; + /** * UDP socket used for communication with the task manager * @var resource @@ -49,7 +56,7 @@ class Taskmanager if ($async) return true; $reply = self::readReply($seq); - if ($reply === false || !is_array($reply) || !isset($reply['id']) || (isset($reply['statusCode']) && $reply['statusCode'] === NO_SUCH_TASK)) { + if ($reply === false || !is_array($reply) || !isset($reply['id']) || (isset($reply['statusCode']) && $reply['statusCode'] === Taskmanager::NO_SUCH_TASK)) { self::addErrorMessage($reply); return false; } @@ -82,15 +89,22 @@ class Taskmanager /** * Checks whether the given task id corresponds to a known task in the taskmanager. * Returns true iff the taskmanager is reachable and the status of the task - * is different from NO_SUCH_TASK. + * is different from Taskmanager::NO_SUCH_INSTANCE/_TASK. + * If you pass an array it is assumed that it was already queried and is evaluated + * directly. * - * @param string $taskid a task id + * @param string|array $taskid a task id or a task array returned by ::status or ::submit * @return boolean true if taskid exists in taskmanager */ - public static function isTask($taskid) + public static function isTask($task) { - $task = self::status($taskid); - return isset($task['statusCode']) && $task['statusCode'] !== NO_SUCH_TASK; + if ($task === false) + return false; + if (is_string($task)) { + $task = self::status($task); + } + return isset($task['statusCode']) && $task['statusCode'] !== Taskmanager::NO_SUCH_INSTANCE + && $task['statusCode'] !== Taskmanager::NO_SUCH_TASK; } /** @@ -103,7 +117,7 @@ class Taskmanager public static function waitComplete($task, $timeout = 2500) { if (is_array($task) && isset($task['id'])) { - if ($task['statusCode'] !== TASK_PROCESSING && $task['statusCode'] !== TASK_WAITING) { + if ($task['statusCode'] !== Taskmanager::TASK_PROCESSING && $task['statusCode'] !== Taskmanager::TASK_WAITING) { self::release($task['id']); return $task; } @@ -117,7 +131,7 @@ class Taskmanager $status = self::status($task); if (!isset($status['statusCode'])) break; - if ($status['statusCode'] !== TASK_PROCESSING && $status['statusCode'] !== TASK_WAITING) { + if ($status['statusCode'] !== Taskmanager::TASK_PROCESSING && $status['statusCode'] !== Taskmanager::TASK_WAITING) { $done = true; break; } @@ -140,7 +154,7 @@ class Taskmanager { if (!is_array($task) || !isset($task['statusCode']) || !isset($task['id'])) return true; - if ($task['statusCode'] !== TASK_WAITING && $task['statusCode'] !== TASK_PROCESSING && $task['statusCode'] !== TASK_FINISHED) + if ($task['statusCode'] !== Taskmanager::TASK_WAITING && $task['statusCode'] !== Taskmanager::TASK_PROCESSING && $task['statusCode'] !== Taskmanager::TASK_FINISHED) return true; return false; } @@ -156,7 +170,7 @@ class Taskmanager { if (!is_array($task) || !isset($task['statusCode']) || !isset($task['id'])) return false; - if ($task['statusCode'] !== TASK_WAITING && $task['statusCode'] !== TASK_PROCESSING) + if ($task['statusCode'] !== Taskmanager::TASK_WAITING && $task['statusCode'] !== Taskmanager::TASK_PROCESSING) return true; return false; } @@ -210,7 +224,7 @@ class Taskmanager private static function readReply($seq) { $tries = 0; - while (($bytes = socket_recvfrom(self::$sock, $buf, 90000, 0, $bla1, $bla2)) !== false || socket_last_error() === 11) { + while (($bytes = @socket_recvfrom(self::$sock, $buf, 90000, 0, $bla1, $bla2)) !== false || socket_last_error() === 11) { $parts = explode(',', $buf, 2); // Do we have compressed data? if (substr($parts[0], 0, 3) === '+z:') { @@ -237,7 +251,3 @@ class Taskmanager } } - -foreach (array('TASK_FINISHED', 'TASK_ERROR', 'TASK_WAITING', 'NO_SUCH_TASK', 'TASK_PROCESSING') as $i) { - define($i, $i); -} diff --git a/inc/taskmanagercallback.inc.php b/inc/taskmanagercallback.inc.php index ab8affac..8e253962 100644 --- a/inc/taskmanagercallback.inc.php +++ b/inc/taskmanagercallback.inc.php @@ -22,7 +22,7 @@ class TaskmanagerCallback if (is_array($task) && isset($task['id'])) $task = $task['id']; if (!is_string($task)) { - EventLog::warning("addCallback: Not a valid task id: $task"); + EventLog::warning("addCallback: Not a valid task id: $task", print_r(debug_backtrace(), true)); return; } $data = array( @@ -136,7 +136,7 @@ class TaskmanagerCallback $mod = Module::get('sysconfig'); if ($mod === false) return; - $mod->activate(); + $mod->activate(1, false); if (Taskmanager::isFailed($task)) { ConfigModule::generateFailed($task, $args); } else { @@ -155,7 +155,7 @@ class TaskmanagerCallback $mod = Module::get('sysconfig'); if ($mod === false) return; - $mod->activate(); + $mod->activate(1, false); if (Taskmanager::isFailed($task)) { ConfigTgz::generateFailed($task, $args); } else { @@ -172,7 +172,8 @@ class TaskmanagerCallback Property::setVmStoreConfig($args); return; } - if ($task['data']['exitCode'] > 0) { + // If code is 99 then the script failed to even unmount -- don't change anything + if ($task['data']['exitCode'] != 99) { // Manual mount failed with non-taskmanager related error - reset storage type to reflect situation $data = Property::getVmStoreConfig(); if (isset($data['storetype'])) { diff --git a/inc/trigger.inc.php b/inc/trigger.inc.php index 2af73872..e89a9a17 100644 --- a/inc/trigger.inc.php +++ b/inc/trigger.inc.php @@ -20,12 +20,24 @@ class Trigger */ public static function ipxe() { - $data = Property::getBootMenu(); - $data['ipaddress'] = Property::getServerIp(); - $task = Taskmanager::submit('CompileIPxe', $data); - if (!isset($task['id'])) - return false; - return $task['id']; + $hooks = Hook::load('ipxe-update'); + $taskId = false; + foreach ($hooks as $hook) { + $ret = function($taskId) use ($hook) { + $ret = include_once($hook->file); + if (is_string($ret)) + return $ret; + return isset($taskId) ? $taskId : false; + }; + $ret = $ret($taskId); + if (is_string($ret)) { + $taskId = $ret; + } elseif (is_array($ret) && isset($ret['id'])) { + $taskId = $ret['id']; + } + } + Property::set('ipxe-task-id', $taskId, 15); + return $taskId; } /** @@ -127,14 +139,23 @@ class Trigger } if ($storetype === 'nfs') { $addr = $vmstore['nfsaddr']; + $opts = 'nfsopts'; } elseif ($storetype === 'cifs') { $addr = $vmstore['cifsaddr']; + $opts = 'cifsopts'; } else { + $opts = null; $addr = 'null'; } + if (isset($vmstore[$opts])) { + $opts = $vmstore[$opts]; + }else { + $opts = null; + } return Taskmanager::submit('MountVmStore', array( 'address' => $addr, 'type' => 'images', + 'opts' => $opts, 'username' => $vmstore['cifsuser'], 'password' => $vmstore['cifspasswd'] )); diff --git a/inc/user.inc.php b/inc/user.inc.php index 81091e1b..20e8cd3d 100644 --- a/inc/user.inc.php +++ b/inc/user.inc.php @@ -31,8 +31,19 @@ class User if (!self::isLoggedIn()) return false; if (Module::isAvailable("permissionmanager")) { - $module = Page::getModule(); - $permission = $module ? $module->getIdentifier().".".$permission : $permission; + if ($permission{0} === '.') { + $permission = substr($permission, 1); + } else { + if (class_exists('Page')) { + $module = Page::getModule(); + if ($module !== false) { + $module = $module->getIdentifier(); + } + } else { + $module = strtolower(Request::any('do')); + } + $permission = $module ? $module . "." . $permission : $permission; + } return PermissionUtil::userHasPermission(self::$user['userid'], $permission, $locationid); } if (self::$user['permissions'] & Permission::get('superadmin')) @@ -40,15 +51,60 @@ class User return (self::$user['permissions'] & Permission::get($permission)) != 0; } + /** + * Confirm current user has the given permission, stop execution and show error message + * otherwise. + * @param string $permission Permission to check for + * @param null|int $locationid location this permission has to apply to, NULL if any location is sufficient + * @param null|string $redirect page to redirect to if permission is not given, NULL defaults to main page + */ + public static function assertPermission($permission, $locationid = NULL, $redirect = NULL) + { + if (User::hasPermission($permission, $locationid)) + return; + if (AJAX) { + Message::renderList(); + exit; + } + if (!is_null($redirect)) { + Message::addError('main.no-permission'); + Util::redirect($redirect); + } elseif (Module::isAvailable('permissionmanager')) { + if ($permission{0} !== '.') { + $module = Page::getModule(); + if ($module !== false) { + $permission = '.' . $module->getIdentifier() . '.' . $permission; + } + } + Util::redirect('?do=permissionmanager&show=denied&permission=' . urlencode($permission)); + } else { + Message::addError('main.no-permission'); + Util::redirect('?do=main'); + } + } + public static function getAllowedLocations($permission) { + if (!self::isLoggedIn()) + return []; if (Module::isAvailable("permissionmanager")) { - $module = Page::getModule(); - $permission = $module ? $module->getIdentifier().".".$permission : $permission; + if ($permission{0} === '.') { + $permission = substr($permission, 1); + } else { + $module = Page::getModule(); + $permission = $module ? $module->getIdentifier() . "." . $permission : $permission; + } return PermissionUtil::getAllowedLocations(self::$user['userid'], $permission); } - if (self::$user['permissions'] & Permission::get('superadmin')) - return array_keys(Location::getLocationsAssoc()); + if (self::$user['permissions'] & Permission::get('superadmin')) { + if (Module::isAvailable('locations')) { + $a = array_keys(Location::getLocationsAssoc()); + $a[] = 0; + } else { + $a = [0]; + } + return $a; + } return array(); } @@ -63,6 +119,7 @@ class User self::$user = Database::queryFirst('SELECT * FROM user WHERE userid = :uid LIMIT 1', array(':uid' => $uid)); if (self::$user === false) self::logout(); + settype(self::$user['userid'], 'int'); return true; } return false; diff --git a/inc/util.inc.php b/inc/util.inc.php index 69eaf941..e459cc46 100644 --- a/inc/util.inc.php +++ b/inc/util.inc.php @@ -179,6 +179,13 @@ SADFACE; $location .= '&' . implode('&', self::$redirectParams); } } + if (CONFIG_DEBUG) { + global $global_start; + $duration = microtime(true) - $global_start; + error_log('Redirect: ' . round($duration, 3) . 's, ' + . Database::getQueryCount() . ' queries, ' + . round(Database::getQueryTime(), 3) . 's query time total'); + } Header('Location: ' . $location); exit(0); } @@ -227,18 +234,23 @@ SADFACE; * * @param float|int $bytes numeric value of the filesize to make readable * @param int $decimals number of decimals to show, -1 for automatic - * @return string human readable string representing the given filesize + * @param int $shift how many units to skip, i.e. if you pass in KiB or MiB + * @return string human readable string representing the given file size */ - public static function readableFileSize($bytes, $decimals = -1) + public static function readableFileSize($bytes, $decimals = -1, $shift = 0) { + $bytes = round($bytes); static $sz = array('Byte', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB'); $factor = (int)floor((strlen($bytes) - 1) / 3); - if ($factor == 0) { + if ($factor === 0) { $decimals = 0; - } elseif ($decimals === -1) { - $decimals = 2 - floor((strlen($bytes) - 1) % 3); + } else { + $bytes = $bytes / pow(1024, $factor); + if ($decimals === -1) { + $decimals = 2 - floor(strlen((int)$bytes) - 1); + } } - return sprintf("%.{$decimals}f ", $bytes / pow(1024, $factor)) . $sz[$factor]; + return sprintf("%.{$decimals}f", $bytes) . "\xe2\x80\x89" . $sz[$factor + $shift]; } public static function sanitizeFilename($name) @@ -484,7 +496,7 @@ SADFACE; settype($ts, 'int'); if ($ts === 0) return '???'; - static $TODAY = false, $ETODAY = false, $YESTERDAY = false, $YEAR = false; + static $TODAY = false, $ETODAY = false, $YESTERDAY = false, $YEARCUTOFF = false; if (!$ETODAY) $ETODAY = strtotime('today 23:59:59'); if ($ts > $ETODAY) // TODO: Do we need strings for future too? return date('d.m.Y H:i', $ts); @@ -494,8 +506,8 @@ SADFACE; if (!$YESTERDAY) $YESTERDAY = strtotime('yesterday 0:00'); if ($ts >= $YESTERDAY) return Dictionary::translate('lang_yesterday') . ' ' . date('H:i', $ts); - if (!$YEAR) $YEAR = strtotime('this year 1/1'); - if ($ts >= $YEAR) + if (!$YEARCUTOFF) $YEARCUTOFF = min(strtotime('-3 month'), strtotime('this year 1/1')); + if ($ts >= $YEARCUTOFF) return date('d.m. H:i', $ts); return date('d.m.Y', $ts); } |