mirror of
https://github.com/vichan-devel/vichan.git
synced 2024-11-24 07:30:10 +01:00
Initial refactor of functions.php
This commit is contained in:
parent
f45bc768fe
commit
3baa68c7b6
@ -10,6 +10,16 @@ if (realpath($_SERVER['SCRIPT_FILENAME']) == str_replace('\\', '/', __FILE__)) {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define('TINYBOARD', true);
|
||||||
|
|
||||||
|
require_once('inc/functions/error.php');
|
||||||
|
require_once('inc/functions/text.php');
|
||||||
|
require_once('inc/functions/net.php');
|
||||||
|
require_once('inc/functions/fs.php');
|
||||||
|
require_once('inc/functions/math.php');
|
||||||
|
require_once('inc/functions/encoding.php');
|
||||||
|
|
||||||
|
|
||||||
$microtime_start = microtime(true);
|
$microtime_start = microtime(true);
|
||||||
|
|
||||||
// the user is not currently logged in as a moderator
|
// the user is not currently logged in as a moderator
|
||||||
@ -38,6 +48,18 @@ function init_locale($locale, $error='error') {
|
|||||||
}
|
}
|
||||||
$current_locale = 'en';
|
$current_locale = 'en';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the key is initialized, and assigns a default value to it if it isn't.
|
||||||
|
*
|
||||||
|
* @param array Reference to the array.
|
||||||
|
* @param mixed Key in the array.
|
||||||
|
* @param mixed Default value.
|
||||||
|
*/
|
||||||
|
function init_or_default(&$array, $key, $default) {
|
||||||
|
if (!isset($array[$key])) {
|
||||||
|
$array[$key] = $default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function loadConfig() {
|
function loadConfig() {
|
||||||
global $board, $config, $__ip, $debug, $__version, $microtime_start, $current_locale, $events;
|
global $board, $config, $__ip, $debug, $__version, $microtime_start, $current_locale, $events;
|
||||||
@ -46,17 +68,14 @@ function loadConfig() {
|
|||||||
|
|
||||||
$boardsuffix = isset($board['uri']) ? $board['uri'] : '';
|
$boardsuffix = isset($board['uri']) ? $board['uri'] : '';
|
||||||
|
|
||||||
if (!isset($_SERVER['REMOTE_ADDR']))
|
init_or_default($_SERVER, 'REMOTE_ADDR', '0.0.0.0');
|
||||||
$_SERVER['REMOTE_ADDR'] = '0.0.0.0';
|
|
||||||
|
|
||||||
if (file_exists('tmp/cache/cache_config.php')) {
|
if (file_exists('tmp/cache/cache_config.php')) {
|
||||||
require_once('tmp/cache/cache_config.php');
|
require_once('tmp/cache/cache_config.php');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (isset($config['cache_config']) &&
|
if (isset($config['cache_config']) && $config['cache_config'] && $config = Cache::get('config_' . $boardsuffix)) {
|
||||||
$config['cache_config'] &&
|
|
||||||
$config = Cache::get('config_' . $boardsuffix ) ) {
|
|
||||||
$events = Cache::get('events_' . $boardsuffix );
|
$events = Cache::get('events_' . $boardsuffix );
|
||||||
|
|
||||||
define_groups();
|
define_groups();
|
||||||
@ -66,9 +85,9 @@ function loadConfig() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($config['locale'] != $current_locale) {
|
if ($config['locale'] != $current_locale) {
|
||||||
$current_locale = $config['locale'];
|
$current_locale = $config['locale'];
|
||||||
init_locale($config['locale'], $error);
|
init_locale($config['locale'], $error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$config = array();
|
$config = array();
|
||||||
@ -108,8 +127,9 @@ function loadConfig() {
|
|||||||
$config[$key] = array();
|
$config[$key] = array();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!file_exists('inc/instance-config.php'))
|
if (!file_exists('inc/instance-config.php')) {
|
||||||
$error('vichan is not configured! Create inc/instance-config.php.');
|
$error('vichan is not configured! Create inc/instance-config.php.');
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize locale as early as possible
|
// Initialize locale as early as possible
|
||||||
|
|
||||||
@ -155,14 +175,10 @@ function loadConfig() {
|
|||||||
init_locale($config['locale'], $error);
|
init_locale($config['locale'], $error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isset($config['global_message']))
|
init_or_default($config, 'global_message', false);
|
||||||
$config['global_message'] = false;
|
init_or_default($config, 'post_url', $config['root'] . $config['file_post']);
|
||||||
|
|
||||||
if (!isset($config['post_url']))
|
if (!isset($config['referer_match'])) {
|
||||||
$config['post_url'] = $config['root'] . $config['file_post'];
|
|
||||||
|
|
||||||
|
|
||||||
if (!isset($config['referer_match']))
|
|
||||||
if (isset($_SERVER['HTTP_HOST'])) {
|
if (isset($_SERVER['HTTP_HOST'])) {
|
||||||
$config['referer_match'] = '/^' .
|
$config['referer_match'] = '/^' .
|
||||||
(preg_match('@^https?://@', $config['root']) ? '' :
|
(preg_match('@^https?://@', $config['root']) ? '' :
|
||||||
@ -180,8 +196,8 @@ function loadConfig() {
|
|||||||
'(' .
|
'(' .
|
||||||
str_replace('%d', '\d+', preg_quote($config['file_page'], '/')) . '|' .
|
str_replace('%d', '\d+', preg_quote($config['file_page'], '/')) . '|' .
|
||||||
str_replace('%d', '\d+', preg_quote($config['file_page50'], '/')) . '|' .
|
str_replace('%d', '\d+', preg_quote($config['file_page50'], '/')) . '|' .
|
||||||
str_replace(array('%d', '%s'), array('\d+', '[a-z0-9-]+'), preg_quote($config['file_page_slug'], '/')) . '|' .
|
str_replace(array('%d', '%s'), array('\d+', '[a-z0-9-]+'), preg_quote($config['file_page_slug'], '/')) . '|' .
|
||||||
str_replace(array('%d', '%s'), array('\d+', '[a-z0-9-]+'), preg_quote($config['file_page50_slug'], '/')) .
|
str_replace(array('%d', '%s'), array('\d+', '[a-z0-9-]+'), preg_quote($config['file_page50_slug'], '/')) .
|
||||||
')' .
|
')' .
|
||||||
'|' .
|
'|' .
|
||||||
preg_quote($config['file_mod'], '/') . '\?\/.+' .
|
preg_quote($config['file_mod'], '/') . '\?\/.+' .
|
||||||
@ -190,67 +206,60 @@ function loadConfig() {
|
|||||||
// CLI mode
|
// CLI mode
|
||||||
$config['referer_match'] = '//';
|
$config['referer_match'] = '//';
|
||||||
}
|
}
|
||||||
if (!isset($config['cookies']['path']))
|
}
|
||||||
|
if (!isset($config['cookies']['path'])) {
|
||||||
$config['cookies']['path'] = &$config['root'];
|
$config['cookies']['path'] = &$config['root'];
|
||||||
|
|
||||||
if (!isset($config['dir']['static']))
|
|
||||||
$config['dir']['static'] = $config['root'] . 'static/';
|
|
||||||
|
|
||||||
if (!isset($config['image_blank']))
|
|
||||||
$config['image_blank'] = $config['dir']['static'] . 'blank.gif';
|
|
||||||
|
|
||||||
if (!isset($config['image_sticky']))
|
|
||||||
$config['image_sticky'] = $config['dir']['static'] . 'sticky.gif';
|
|
||||||
if (!isset($config['image_locked']))
|
|
||||||
$config['image_locked'] = $config['dir']['static'] . 'locked.gif';
|
|
||||||
if (!isset($config['image_bumplocked']))
|
|
||||||
$config['image_bumplocked'] = $config['dir']['static'] . 'sage.gif';
|
|
||||||
if (!isset($config['image_deleted']))
|
|
||||||
$config['image_deleted'] = $config['dir']['static'] . 'deleted.png';
|
|
||||||
if (!isset($config['image_cyclical']))
|
|
||||||
$config['image_cyclical'] = $config['dir']['static'] . 'cycle.png';
|
|
||||||
|
|
||||||
if (isset($board)) {
|
|
||||||
if (!isset($config['uri_thumb']))
|
|
||||||
$config['uri_thumb'] = $config['root'] . $board['dir'] . $config['dir']['thumb'];
|
|
||||||
elseif (isset($board['dir']))
|
|
||||||
$config['uri_thumb'] = sprintf($config['uri_thumb'], $board['dir']);
|
|
||||||
|
|
||||||
if (!isset($config['uri_img']))
|
|
||||||
$config['uri_img'] = $config['root'] . $board['dir'] . $config['dir']['img'];
|
|
||||||
elseif (isset($board['dir']))
|
|
||||||
$config['uri_img'] = sprintf($config['uri_img'], $board['dir']);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isset($config['uri_stylesheets']))
|
if (!isset($config['dir']['static'])) {
|
||||||
$config['uri_stylesheets'] = $config['root'] . 'stylesheets/';
|
$config['dir']['static'] = $config['root'] . 'static/';
|
||||||
|
}
|
||||||
|
|
||||||
if (!isset($config['url_stylesheet']))
|
init_or_default($config, 'image_blank', $config['dir']['static'] . 'blank.gif');
|
||||||
$config['url_stylesheet'] = $config['uri_stylesheets'] . 'style.css';
|
init_or_default($config, 'image_sticky', $config['dir']['static'] . 'sticky.gif');
|
||||||
if (!isset($config['url_javascript']))
|
init_or_default($config, 'image_locked', $config['dir']['static'] . 'locked.gif');
|
||||||
$config['url_javascript'] = $config['root'] . $config['file_script'];
|
init_or_default($config, 'image_bumplocked', $config['dir']['static'] . 'sage.gif');
|
||||||
if (!isset($config['additional_javascript_url']))
|
init_or_default($config, 'image_deleted', $config['dir']['static'] . 'deleted.png');
|
||||||
$config['additional_javascript_url'] = $config['root'];
|
init_or_default($config, 'image_cyclical', $config['dir']['static'] . 'cycle.png');
|
||||||
if (!isset($config['uri_flags']))
|
|
||||||
$config['uri_flags'] = $config['root'] . 'static/flags/%s.png';
|
|
||||||
if (!isset($config['user_flag']))
|
|
||||||
$config['user_flag'] = false;
|
|
||||||
if (!isset($config['user_flags']))
|
|
||||||
$config['user_flags'] = array();
|
|
||||||
|
|
||||||
if (!isset($__version))
|
if (isset($board)) {
|
||||||
|
if (!isset($config['uri_thumb'])) {
|
||||||
|
$config['uri_thumb'] = $config['root'] . $board['dir'] . $config['dir']['thumb'];
|
||||||
|
}
|
||||||
|
elseif (isset($board['dir'])) {
|
||||||
|
$config['uri_thumb'] = sprintf($config['uri_thumb'], $board['dir']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($config['uri_img'])) {
|
||||||
|
$config['uri_img'] = $config['root'] . $board['dir'] . $config['dir']['img'];
|
||||||
|
} elseif (isset($board['dir'])) {
|
||||||
|
$config['uri_img'] = sprintf($config['uri_img'], $board['dir']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init_or_default($config, 'uri_stylesheets', $config['root'] . 'stylesheets/');
|
||||||
|
init_or_default($config, 'url_stylesheet', $config['uri_stylesheets'] . 'style.css');
|
||||||
|
init_or_default($config, 'url_javascript', $config['root'] . $config['file_script']);
|
||||||
|
init_or_default($config, 'additional_javascript_url', $config['root']);
|
||||||
|
init_or_default($config, 'uri_flags', $config['root'] . 'static/flags/%s.png');
|
||||||
|
init_or_default($config, 'user_flag', false);
|
||||||
|
init_or_default($config, 'user_flags', array());
|
||||||
|
|
||||||
|
if (!isset($__version)) {
|
||||||
$__version = file_exists('.installed') ? trim(file_get_contents('.installed')) : false;
|
$__version = file_exists('.installed') ? trim(file_get_contents('.installed')) : false;
|
||||||
|
}
|
||||||
$config['version'] = $__version;
|
$config['version'] = $__version;
|
||||||
|
|
||||||
if ($config['allow_roll'])
|
if ($config['allow_roll']) {
|
||||||
event_handler('post', 'diceRoller');
|
event_handler('post', 'diceRoller');
|
||||||
|
}
|
||||||
|
|
||||||
if (in_array('webm', $config['allowed_ext_files']) ||
|
if (in_array('webm', $config['allowed_ext_files']) || in_array('mp4', $config['allowed_ext_files'])) {
|
||||||
in_array('mp4', $config['allowed_ext_files']))
|
|
||||||
event_handler('post', 'postHandler');
|
event_handler('post', 'postHandler');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Effectful config processing below:
|
|
||||||
|
|
||||||
|
// Effectual config processing below:
|
||||||
date_default_timezone_set($config['timezone']);
|
date_default_timezone_set($config['timezone']);
|
||||||
|
|
||||||
if ($config['root_file']) {
|
if ($config['root_file']) {
|
||||||
@ -258,12 +267,14 @@ function loadConfig() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Keep the original address to properly comply with other board configurations
|
// Keep the original address to properly comply with other board configurations
|
||||||
if (!isset($__ip))
|
if (!isset($__ip)) {
|
||||||
$__ip = $_SERVER['REMOTE_ADDR'];
|
$__ip = $_SERVER['REMOTE_ADDR'];
|
||||||
|
}
|
||||||
|
|
||||||
// ::ffff:0.0.0.0
|
// ::ffff:0.0.0.0
|
||||||
if (preg_match('/^\:\:(ffff\:)?(\d+\.\d+\.\d+\.\d+)$/', $__ip, $m))
|
if (preg_match('/^\:\:(ffff\:)?(\d+\.\d+\.\d+\.\d+)$/', $__ip, $m)) {
|
||||||
$_SERVER['REMOTE_ADDR'] = $m[2];
|
$_SERVER['REMOTE_ADDR'] = $m[2];
|
||||||
|
}
|
||||||
|
|
||||||
if ($config['verbose_errors']) {
|
if ($config['verbose_errors']) {
|
||||||
set_error_handler('verbose_error_handler');
|
set_error_handler('verbose_error_handler');
|
||||||
@ -274,15 +285,17 @@ function loadConfig() {
|
|||||||
ini_set('display_errors', false);
|
ini_set('display_errors', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($config['syslog'])
|
if ($config['syslog']) {
|
||||||
openlog('tinyboard', LOG_ODELAY, LOG_SYSLOG); // open a connection to sysem logger
|
openlog('tinyboard', LOG_ODELAY, LOG_SYSLOG); // open a connection to system logger
|
||||||
|
}
|
||||||
|
|
||||||
if ($config['cache']['enabled'])
|
if ($config['cache']['enabled']) {
|
||||||
require_once 'inc/cache.php';
|
require_once 'inc/cache.php';
|
||||||
|
}
|
||||||
|
|
||||||
if (in_array('webm', $config['allowed_ext_files']) ||
|
if (in_array('webm', $config['allowed_ext_files']) || in_array('mp4', $config['allowed_ext_files'])) {
|
||||||
in_array('mp4', $config['allowed_ext_files']))
|
|
||||||
require_once 'inc/lib/webm/posthandler.php';
|
require_once 'inc/lib/webm/posthandler.php';
|
||||||
|
}
|
||||||
|
|
||||||
event('load-config');
|
event('load-config');
|
||||||
|
|
||||||
@ -301,8 +314,9 @@ function loadConfig() {
|
|||||||
Cache::set('events_'.$boardsuffix, $events);
|
Cache::set('events_'.$boardsuffix, $events);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_array($config['anonymous']))
|
if (is_array($config['anonymous'])) {
|
||||||
$config['anonymous'] = $config['anonymous'][array_rand($config['anonymous'])];
|
$config['anonymous'] = $config['anonymous'][array_rand($config['anonymous'])];
|
||||||
|
}
|
||||||
|
|
||||||
if ($config['debug']) {
|
if ($config['debug']) {
|
||||||
if (!isset($debug)) {
|
if (!isset($debug)) {
|
||||||
@ -324,62 +338,6 @@ function loadConfig() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function basic_error_function_because_the_other_isnt_loaded_yet($message, $priority = true) {
|
|
||||||
global $config;
|
|
||||||
|
|
||||||
if ($config['syslog'] && $priority !== false) {
|
|
||||||
// Use LOG_NOTICE instead of LOG_ERR or LOG_WARNING because most error message are not significant.
|
|
||||||
_syslog($priority !== true ? $priority : LOG_NOTICE, $message);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Yes, this is horrible.
|
|
||||||
die('<!DOCTYPE html><html><head><title>Error</title>' .
|
|
||||||
'<style type="text/css">' .
|
|
||||||
'body{text-align:center;font-family:arial, helvetica, sans-serif;font-size:10pt;}' .
|
|
||||||
'p{padding:0;margin:20px 0;}' .
|
|
||||||
'p.c{font-size:11px;}' .
|
|
||||||
'</style></head>' .
|
|
||||||
'<body><h2>Error</h2>' . $message . '<hr/>' .
|
|
||||||
'<p class="c">This alternative error page is being displayed because the other couldn\'t be found or hasn\'t loaded yet.</p></body></html>');
|
|
||||||
}
|
|
||||||
|
|
||||||
function fatal_error_handler() {
|
|
||||||
if ($error = error_get_last()) {
|
|
||||||
if ($error['type'] == E_ERROR) {
|
|
||||||
if (function_exists('error')) {
|
|
||||||
error('Caught fatal error: ' . $error['message'] . ' in <strong>' . $error['file'] . '</strong> on line ' . $error['line'], LOG_ERR);
|
|
||||||
} else {
|
|
||||||
basic_error_function_because_the_other_isnt_loaded_yet('Caught fatal error: ' . $error['message'] . ' in ' . $error['file'] . ' on line ' . $error['line'], LOG_ERR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function _syslog($priority, $message) {
|
|
||||||
if (isset($_SERVER['REMOTE_ADDR'], $_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI'])) {
|
|
||||||
// CGI
|
|
||||||
syslog($priority, $message . ' - client: ' . $_SERVER['REMOTE_ADDR'] . ', request: "' . $_SERVER['REQUEST_METHOD'] . ' ' . $_SERVER['REQUEST_URI'] . '"');
|
|
||||||
} else {
|
|
||||||
syslog($priority, $message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function verbose_error_handler($errno, $errstr, $errfile, $errline) {
|
|
||||||
global $config;
|
|
||||||
|
|
||||||
if (error_reporting() == 0)
|
|
||||||
return false; // Looks like this warning was suppressed by the @ operator.
|
|
||||||
if ($errno == E_DEPRECATED && !$config['deprecation_errors'])
|
|
||||||
return false;
|
|
||||||
|
|
||||||
error(utf8tohtml($errstr), true, array(
|
|
||||||
'file' => $errfile . ':' . $errline,
|
|
||||||
'errno' => $errno,
|
|
||||||
'error' => $errstr,
|
|
||||||
'backtrace' => array_slice(debug_backtrace(), 1)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
function define_groups() {
|
function define_groups() {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
@ -395,8 +353,35 @@ function define_groups() {
|
|||||||
|
|
||||||
function create_antibot($board, $thread = null) {
|
function create_antibot($board, $thread = null) {
|
||||||
require_once dirname(__FILE__) . '/anti-bot.php';
|
require_once dirname(__FILE__) . '/anti-bot.php';
|
||||||
|
global $config, $purged_old_antispam;
|
||||||
|
|
||||||
return _create_antibot($board, $thread);
|
$antibot = new AntiBot(array($board, $thread));
|
||||||
|
|
||||||
|
if (!isset($purged_old_antispam)) {
|
||||||
|
$purged_old_antispam = true;
|
||||||
|
query('DELETE FROM ``antispam`` WHERE `expires` < UNIX_TIMESTAMP()') or error(db_error());
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($thread) {
|
||||||
|
$query = prepare('UPDATE ``antispam`` SET `expires` = UNIX_TIMESTAMP() + :expires WHERE `board` = :board AND `thread` = :thread AND `expires` IS NULL');
|
||||||
|
} else {
|
||||||
|
$query = prepare('UPDATE ``antispam`` SET `expires` = UNIX_TIMESTAMP() + :expires WHERE `board` = :board AND `thread` IS NULL AND `expires` IS NULL');
|
||||||
|
}
|
||||||
|
|
||||||
|
$query->bindValue(':board', $board);
|
||||||
|
if ($thread) {
|
||||||
|
$query->bindValue(':thread', $thread);
|
||||||
|
}
|
||||||
|
$query->bindValue(':expires', $config['spam']['hidden_inputs_expire']);
|
||||||
|
$query->execute() or error(db_error($query));
|
||||||
|
|
||||||
|
$query = prepare('INSERT INTO ``antispam`` VALUES (:board, :thread, :hash, UNIX_TIMESTAMP(), NULL, 0)');
|
||||||
|
$query->bindValue(':board', $board);
|
||||||
|
$query->bindValue(':thread', $thread);
|
||||||
|
$query->bindValue(':hash', $antibot->hash());
|
||||||
|
$query->execute() or error(db_error($query));
|
||||||
|
|
||||||
|
return $antibot;
|
||||||
}
|
}
|
||||||
|
|
||||||
function rebuildThemes($action, $boardname = false) {
|
function rebuildThemes($action, $boardname = false) {
|
||||||
@ -501,18 +486,6 @@ function themeSettings($theme) {
|
|||||||
return $settings;
|
return $settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
function sprintf3($str, $vars, $delim = '%') {
|
|
||||||
$replaces = array();
|
|
||||||
foreach ($vars as $k => $v) {
|
|
||||||
$replaces[$delim . $k . $delim] = $v;
|
|
||||||
}
|
|
||||||
return str_replace(array_keys($replaces),
|
|
||||||
array_values($replaces), $str);
|
|
||||||
}
|
|
||||||
|
|
||||||
function mb_substr_replace($string, $replacement, $start, $length) {
|
|
||||||
return mb_substr($string, 0, $start) . $replacement . mb_substr($string, $start + $length);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setupBoard($array) {
|
function setupBoard($array) {
|
||||||
global $board, $config;
|
global $board, $config;
|
||||||
@ -552,7 +525,7 @@ function openBoard($uri) {
|
|||||||
$build_pages = array();
|
$build_pages = array();
|
||||||
|
|
||||||
// And what if we don't really need to change a board we have opened?
|
// And what if we don't really need to change a board we have opened?
|
||||||
if (isset ($board) && isset ($board['uri']) && $board['uri'] == $uri) {
|
if (isset($board) && isset($board['uri']) && $board['uri'] == $uri) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -596,162 +569,6 @@ function boardTitle($uri) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function purge($uri) {
|
|
||||||
global $config, $debug;
|
|
||||||
|
|
||||||
// Fix for Unicode
|
|
||||||
$uri = rawurlencode($uri);
|
|
||||||
|
|
||||||
$noescape = "/!~*()+:";
|
|
||||||
$noescape = preg_split('//', $noescape);
|
|
||||||
$noescape_url = array_map("rawurlencode", $noescape);
|
|
||||||
$uri = str_replace($noescape_url, $noescape, $uri);
|
|
||||||
|
|
||||||
if (preg_match($config['referer_match'], $config['root']) && isset($_SERVER['REQUEST_URI'])) {
|
|
||||||
$uri = (str_replace('\\', '/', dirname($_SERVER['REQUEST_URI'])) == '/' ? '/' : str_replace('\\', '/', dirname($_SERVER['REQUEST_URI'])) . '/') . $uri;
|
|
||||||
} else {
|
|
||||||
$uri = $config['root'] . $uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($config['debug']) {
|
|
||||||
$debug['purge'][] = $uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($config['purge'] as &$purge) {
|
|
||||||
$host = &$purge[0];
|
|
||||||
$port = &$purge[1];
|
|
||||||
$http_host = isset($purge[2]) ? $purge[2] : (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost');
|
|
||||||
$request = "PURGE {$uri} HTTP/1.1\r\nHost: {$http_host}\r\nUser-Agent: Tinyboard\r\nConnection: Close\r\n\r\n";
|
|
||||||
if ($fp = fsockopen($host, $port, $errno, $errstr, $config['purge_timeout'])) {
|
|
||||||
fwrite($fp, $request);
|
|
||||||
fclose($fp);
|
|
||||||
} else {
|
|
||||||
// Cannot connect?
|
|
||||||
error('Could not PURGE for ' . $host);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function file_write($path, $data, $simple = false, $skip_purge = false) {
|
|
||||||
global $config, $debug;
|
|
||||||
|
|
||||||
if (preg_match('/^remote:\/\/(.+)\:(.+)$/', $path, $m)) {
|
|
||||||
if (isset($config['remote'][$m[1]])) {
|
|
||||||
require_once 'inc/remote.php';
|
|
||||||
|
|
||||||
$remote = new Remote($config['remote'][$m[1]]);
|
|
||||||
$remote->write($data, $m[2]);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
error('Invalid remote server: ' . $m[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$fp = fopen($path, $simple ? 'w' : 'c'))
|
|
||||||
error('Unable to open file for writing: ' . $path);
|
|
||||||
|
|
||||||
// File locking
|
|
||||||
if (!$simple && !flock($fp, LOCK_EX)) {
|
|
||||||
error('Unable to lock file: ' . $path);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Truncate file
|
|
||||||
if (!$simple && !ftruncate($fp, 0))
|
|
||||||
error('Unable to truncate file: ' . $path);
|
|
||||||
|
|
||||||
// Write data
|
|
||||||
if (($bytes = fwrite($fp, $data)) === false)
|
|
||||||
error('Unable to write to file: ' . $path);
|
|
||||||
|
|
||||||
// Unlock
|
|
||||||
if (!$simple)
|
|
||||||
flock($fp, LOCK_UN);
|
|
||||||
|
|
||||||
// Close
|
|
||||||
if (!fclose($fp))
|
|
||||||
error('Unable to close file: ' . $path);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create gzipped file.
|
|
||||||
*
|
|
||||||
* When writing into a file foo.bar and the size is larger or equal to 1
|
|
||||||
* KiB, this also produces the gzipped version foo.bar.gz
|
|
||||||
*
|
|
||||||
* This is useful with nginx with gzip_static on.
|
|
||||||
*/
|
|
||||||
if ($config['gzip_static']) {
|
|
||||||
$gzpath = "$path.gz";
|
|
||||||
|
|
||||||
if ($bytes & ~0x3ff) { // if ($bytes >= 1024)
|
|
||||||
if (file_put_contents($gzpath, gzencode($data), $simple ? 0 : LOCK_EX) === false)
|
|
||||||
error("Unable to write to file: $gzpath");
|
|
||||||
//if (!touch($gzpath, filemtime($path), fileatime($path)))
|
|
||||||
// error("Unable to touch file: $gzpath");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
@unlink($gzpath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$skip_purge && isset($config['purge'])) {
|
|
||||||
// Purge cache
|
|
||||||
if (basename($path) == $config['file_index']) {
|
|
||||||
// Index file (/index.html); purge "/" as well
|
|
||||||
$uri = dirname($path);
|
|
||||||
// root
|
|
||||||
if ($uri == '.')
|
|
||||||
$uri = '';
|
|
||||||
else
|
|
||||||
$uri .= '/';
|
|
||||||
purge($uri);
|
|
||||||
}
|
|
||||||
purge($path);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($config['debug']) {
|
|
||||||
$debug['write'][] = $path . ': ' . $bytes . ' bytes';
|
|
||||||
}
|
|
||||||
|
|
||||||
event('write', $path);
|
|
||||||
}
|
|
||||||
|
|
||||||
function file_unlink($path) {
|
|
||||||
global $config, $debug;
|
|
||||||
|
|
||||||
if ($config['debug']) {
|
|
||||||
if (!isset($debug['unlink']))
|
|
||||||
$debug['unlink'] = array();
|
|
||||||
$debug['unlink'][] = $path;
|
|
||||||
}
|
|
||||||
|
|
||||||
$ret = @unlink($path);
|
|
||||||
|
|
||||||
if ($config['gzip_static']) {
|
|
||||||
$gzpath = "$path.gz";
|
|
||||||
|
|
||||||
@unlink($gzpath);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($config['purge']) && $path[0] != '/' && isset($_SERVER['HTTP_HOST'])) {
|
|
||||||
// Purge cache
|
|
||||||
if (basename($path) == $config['file_index']) {
|
|
||||||
// Index file (/index.html); purge "/" as well
|
|
||||||
$uri = dirname($path);
|
|
||||||
// root
|
|
||||||
if ($uri == '.')
|
|
||||||
$uri = '';
|
|
||||||
else
|
|
||||||
$uri .= '/';
|
|
||||||
purge($uri);
|
|
||||||
}
|
|
||||||
purge($path);
|
|
||||||
}
|
|
||||||
|
|
||||||
event('unlink', $path);
|
|
||||||
|
|
||||||
return $ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
function hasPermission($action = null, $board = null, $_mod = null) {
|
function hasPermission($action = null, $board = null, $_mod = null) {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
@ -803,42 +620,6 @@ function listBoards($just_uri = false) {
|
|||||||
return $boards;
|
return $boards;
|
||||||
}
|
}
|
||||||
|
|
||||||
function until($timestamp) {
|
|
||||||
$difference = $timestamp - time();
|
|
||||||
switch(TRUE){
|
|
||||||
case ($difference < 60):
|
|
||||||
return $difference . ' ' . ngettext('second', 'seconds', $difference);
|
|
||||||
case ($difference < 3600): //60*60 = 3600
|
|
||||||
return ($num = round($difference/(60))) . ' ' . ngettext('minute', 'minutes', $num);
|
|
||||||
case ($difference < 86400): //60*60*24 = 86400
|
|
||||||
return ($num = round($difference/(3600))) . ' ' . ngettext('hour', 'hours', $num);
|
|
||||||
case ($difference < 604800): //60*60*24*7 = 604800
|
|
||||||
return ($num = round($difference/(86400))) . ' ' . ngettext('day', 'days', $num);
|
|
||||||
case ($difference < 31536000): //60*60*24*365 = 31536000
|
|
||||||
return ($num = round($difference/(604800))) . ' ' . ngettext('week', 'weeks', $num);
|
|
||||||
default:
|
|
||||||
return ($num = round($difference/(31536000))) . ' ' . ngettext('year', 'years', $num);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function ago($timestamp) {
|
|
||||||
$difference = time() - $timestamp;
|
|
||||||
switch(TRUE){
|
|
||||||
case ($difference < 60) :
|
|
||||||
return $difference . ' ' . ngettext('second', 'seconds', $difference);
|
|
||||||
case ($difference < 3600): //60*60 = 3600
|
|
||||||
return ($num = round($difference/(60))) . ' ' . ngettext('minute', 'minutes', $num);
|
|
||||||
case ($difference < 86400): //60*60*24 = 86400
|
|
||||||
return ($num = round($difference/(3600))) . ' ' . ngettext('hour', 'hours', $num);
|
|
||||||
case ($difference < 604800): //60*60*24*7 = 604800
|
|
||||||
return ($num = round($difference/(86400))) . ' ' . ngettext('day', 'days', $num);
|
|
||||||
case ($difference < 31536000): //60*60*24*365 = 31536000
|
|
||||||
return ($num = round($difference/(604800))) . ' ' . ngettext('week', 'weeks', $num);
|
|
||||||
default:
|
|
||||||
return ($num = round($difference/(31536000))) . ' ' . ngettext('year', 'years', $num);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function displayBan($ban) {
|
function displayBan($ban) {
|
||||||
global $config, $board;
|
global $config, $board;
|
||||||
|
|
||||||
@ -1616,7 +1397,7 @@ function mute() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function checkMute() {
|
function checkMute() {
|
||||||
global $config, $debug;
|
global $config;
|
||||||
|
|
||||||
if ($config['cache']['enabled']) {
|
if ($config['cache']['enabled']) {
|
||||||
// Cached mute?
|
// Cached mute?
|
||||||
@ -1651,36 +1432,6 @@ function checkMute() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _create_antibot($board, $thread) {
|
|
||||||
global $config, $purged_old_antispam;
|
|
||||||
|
|
||||||
$antibot = new AntiBot(array($board, $thread));
|
|
||||||
|
|
||||||
if (!isset($purged_old_antispam)) {
|
|
||||||
$purged_old_antispam = true;
|
|
||||||
query('DELETE FROM ``antispam`` WHERE `expires` < UNIX_TIMESTAMP()') or error(db_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($thread)
|
|
||||||
$query = prepare('UPDATE ``antispam`` SET `expires` = UNIX_TIMESTAMP() + :expires WHERE `board` = :board AND `thread` = :thread AND `expires` IS NULL');
|
|
||||||
else
|
|
||||||
$query = prepare('UPDATE ``antispam`` SET `expires` = UNIX_TIMESTAMP() + :expires WHERE `board` = :board AND `thread` IS NULL AND `expires` IS NULL');
|
|
||||||
|
|
||||||
$query->bindValue(':board', $board);
|
|
||||||
if ($thread)
|
|
||||||
$query->bindValue(':thread', $thread);
|
|
||||||
$query->bindValue(':expires', $config['spam']['hidden_inputs_expire']);
|
|
||||||
$query->execute() or error(db_error($query));
|
|
||||||
|
|
||||||
$query = prepare('INSERT INTO ``antispam`` VALUES (:board, :thread, :hash, UNIX_TIMESTAMP(), NULL, 0)');
|
|
||||||
$query->bindValue(':board', $board);
|
|
||||||
$query->bindValue(':thread', $thread);
|
|
||||||
$query->bindValue(':hash', $antibot->hash());
|
|
||||||
$query->execute() or error(db_error($query));
|
|
||||||
|
|
||||||
return $antibot;
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkSpam(array $extra_salt = array()) {
|
function checkSpam(array $extra_salt = array()) {
|
||||||
global $config, $pdo;
|
global $config, $pdo;
|
||||||
|
|
||||||
@ -1922,14 +1673,6 @@ function checkDNSBL() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function isIPv6() {
|
|
||||||
return strstr($_SERVER['REMOTE_ADDR'], ':') !== false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function ReverseIPOctets($ip) {
|
|
||||||
return implode('.', array_reverse(explode('.', $ip)));
|
|
||||||
}
|
|
||||||
|
|
||||||
function wordfilters(&$body) {
|
function wordfilters(&$body) {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
@ -2501,22 +2244,6 @@ function buildThread50($id, $return = false, $mod = false, $thread = null, $anti
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function rrmdir($dir) {
|
|
||||||
if (is_dir($dir)) {
|
|
||||||
$objects = scandir($dir);
|
|
||||||
foreach ($objects as $object) {
|
|
||||||
if ($object != "." && $object != "..") {
|
|
||||||
if (filetype($dir."/".$object) == "dir")
|
|
||||||
rrmdir($dir."/".$object);
|
|
||||||
else
|
|
||||||
file_unlink($dir."/".$object);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
reset($objects);
|
|
||||||
rmdir($dir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function poster_id($ip, $thread) {
|
function poster_id($ip, $thread) {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
@ -2563,35 +2290,6 @@ function generate_tripcode($name) {
|
|||||||
return array($name, $trip);
|
return array($name, $trip);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Highest common factor
|
|
||||||
function hcf($a, $b){
|
|
||||||
$gcd = 1;
|
|
||||||
if ($a>$b) {
|
|
||||||
$a = $a+$b;
|
|
||||||
$b = $a-$b;
|
|
||||||
$a = $a-$b;
|
|
||||||
}
|
|
||||||
if ($b==(round($b/$a))*$a)
|
|
||||||
$gcd=$a;
|
|
||||||
else {
|
|
||||||
for ($i=round($a/2);$i;$i--) {
|
|
||||||
if ($a == round($a/$i)*$i && $b == round($b/$i)*$i) {
|
|
||||||
$gcd = $i;
|
|
||||||
$i = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $gcd;
|
|
||||||
}
|
|
||||||
|
|
||||||
function fraction($numerator, $denominator, $sep) {
|
|
||||||
$gcf = hcf($numerator, $denominator);
|
|
||||||
$numerator = $numerator / $gcf;
|
|
||||||
$denominator = $denominator / $gcf;
|
|
||||||
|
|
||||||
return "{$numerator}{$sep}{$denominator}";
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPostByHash($hash) {
|
function getPostByHash($hash) {
|
||||||
global $board;
|
global $board;
|
||||||
$query = prepare(sprintf("SELECT `id`,`thread` FROM ``posts_%s`` WHERE `filehash` = :hash", $board['uri']));
|
$query = prepare(sprintf("SELECT `id`,`thread` FROM ``posts_%s`` WHERE `filehash` = :hash", $board['uri']));
|
||||||
@ -2631,83 +2329,6 @@ function undoImage(array $post) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function rDNS($ip_addr) {
|
|
||||||
global $config;
|
|
||||||
|
|
||||||
if ($config['cache']['enabled'] && ($host = cache::get('rdns_' . $ip_addr))) {
|
|
||||||
return $host;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$config['dns_system']) {
|
|
||||||
$host = gethostbyaddr($ip_addr);
|
|
||||||
} else {
|
|
||||||
$resp = shell_exec_error('host -W 3 ' . $ip_addr);
|
|
||||||
if (preg_match('/domain name pointer ([^\s]+)$/', $resp, $m))
|
|
||||||
$host = $m[1];
|
|
||||||
else
|
|
||||||
$host = $ip_addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
$isip = filter_var($host, FILTER_VALIDATE_IP);
|
|
||||||
|
|
||||||
if ($config['fcrdns'] && !$isip && DNS($host) != $ip_addr) {
|
|
||||||
$host = $ip_addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($config['cache']['enabled'])
|
|
||||||
cache::set('rdns_' . $ip_addr, $host);
|
|
||||||
|
|
||||||
return $host;
|
|
||||||
}
|
|
||||||
|
|
||||||
function DNS($host) {
|
|
||||||
global $config;
|
|
||||||
|
|
||||||
if ($config['cache']['enabled'] && ($ip_addr = cache::get('dns_' . $host))) {
|
|
||||||
return $ip_addr != '?' ? $ip_addr : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$config['dns_system']) {
|
|
||||||
$ip_addr = gethostbyname($host);
|
|
||||||
if ($ip_addr == $host)
|
|
||||||
$ip_addr = false;
|
|
||||||
} else {
|
|
||||||
$resp = shell_exec_error('host -W 1 ' . $host);
|
|
||||||
if (preg_match('/has address ([^\s]+)$/', $resp, $m))
|
|
||||||
$ip_addr = $m[1];
|
|
||||||
else
|
|
||||||
$ip_addr = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($config['cache']['enabled'])
|
|
||||||
cache::set('dns_' . $host, $ip_addr !== false ? $ip_addr : '?');
|
|
||||||
|
|
||||||
return $ip_addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
function shell_exec_error($command, $suppress_stdout = false) {
|
|
||||||
global $config, $debug;
|
|
||||||
|
|
||||||
if ($config['debug'])
|
|
||||||
$start = microtime(true);
|
|
||||||
|
|
||||||
$return = trim(shell_exec('PATH="' . escapeshellcmd($config['shell_path']) . ':$PATH";' .
|
|
||||||
$command . ' 2>&1 ' . ($suppress_stdout ? '> /dev/null ' : '') . '&& echo "TB_SUCCESS"'));
|
|
||||||
$return = preg_replace('/TB_SUCCESS$/', '', $return);
|
|
||||||
|
|
||||||
if ($config['debug']) {
|
|
||||||
$time = microtime(true) - $start;
|
|
||||||
$debug['exec'][] = array(
|
|
||||||
'command' => $command,
|
|
||||||
'time' => '~' . round($time * 1000, 2) . 'ms',
|
|
||||||
'response' => $return ? $return : null
|
|
||||||
);
|
|
||||||
$debug['time']['exec'] += $time;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $return === 'TB_SUCCESS' ? false : $return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Die rolling:
|
/* Die rolling:
|
||||||
* If "dice XdY+/-Z" is in the email field (where X or +/-Z may be
|
* If "dice XdY+/-Z" is in the email field (where X or +/-Z may be
|
||||||
* missing), X Y-sided dice are rolled and summed, with the modifier Z
|
* missing), X Y-sided dice are rolled and summed, with the modifier Z
|
||||||
@ -2857,24 +2478,6 @@ function prettify_textarea($s){
|
|||||||
return str_replace("\t", '	', str_replace("\n", ' ', htmlentities($s)));
|
return str_replace("\t", '	', str_replace("\n", ' ', htmlentities($s)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*class HTMLPurifier_URIFilter_NoExternalImages extends HTMLPurifier_URIFilter {
|
|
||||||
public $name = 'NoExternalImages';
|
|
||||||
public function filter(&$uri, $c, $context) {
|
|
||||||
global $config;
|
|
||||||
$ct = $context->get('CurrentToken');
|
|
||||||
|
|
||||||
if (!$ct || $ct->name !== 'img') return true;
|
|
||||||
|
|
||||||
if (!isset($uri->host) && !isset($uri->scheme)) return true;
|
|
||||||
|
|
||||||
if (!in_array($uri->scheme . '://' . $uri->host . '/', $config['allowed_offsite_urls'])) {
|
|
||||||
error('No off-site links in board announcement images.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
function purify_html($s) {
|
function purify_html($s) {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
@ -2895,84 +2498,6 @@ function markdown($s) {
|
|||||||
return $pd->text($s);
|
return $pd->text($s);
|
||||||
}
|
}
|
||||||
|
|
||||||
function generation_strategy($fun, $array=array()) { global $config;
|
|
||||||
$action = false;
|
|
||||||
|
|
||||||
foreach ($config['generation_strategies'] as $s) {
|
|
||||||
if ($action = $s($fun, $array)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ($action[0]) {
|
|
||||||
case 'immediate':
|
|
||||||
return 'rebuild';
|
|
||||||
case 'defer':
|
|
||||||
// Ok, it gets interesting here :)
|
|
||||||
get_queue('generate')->push(serialize(array('build', $fun, $array, $action)));
|
|
||||||
return 'ignore';
|
|
||||||
case 'build_on_load':
|
|
||||||
return 'delete';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function strategy_immediate($fun, $array) {
|
|
||||||
return array('immediate');
|
|
||||||
}
|
|
||||||
|
|
||||||
function strategy_smart_build($fun, $array) {
|
|
||||||
return array('build_on_load');
|
|
||||||
}
|
|
||||||
|
|
||||||
function strategy_sane($fun, $array) { global $config;
|
|
||||||
if (php_sapi_name() == 'cli') return false;
|
|
||||||
else if (isset($_POST['mod'])) return false;
|
|
||||||
// Thread needs to be done instantly. Same with a board page, but only if posting a new thread.
|
|
||||||
else if ($fun == 'sb_thread' || ($fun == 'sb_board' && $array[1] == 1 && isset ($_POST['page']))) return array('immediate');
|
|
||||||
else return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// My first, test strategy.
|
|
||||||
function strategy_first($fun, $array) {
|
|
||||||
switch ($fun) {
|
|
||||||
case 'sb_thread':
|
|
||||||
return array('defer');
|
|
||||||
case 'sb_board':
|
|
||||||
if ($array[1] > 8) return array('build_on_load');
|
|
||||||
else return array('defer');
|
|
||||||
case 'sb_api':
|
|
||||||
return array('defer');
|
|
||||||
case 'sb_catalog':
|
|
||||||
return array('defer');
|
|
||||||
case 'sb_recent':
|
|
||||||
return array('build_on_load');
|
|
||||||
case 'sb_sitemap':
|
|
||||||
return array('build_on_load');
|
|
||||||
case 'sb_ukko':
|
|
||||||
return array('defer');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function base32_decode($d) {
|
|
||||||
$charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
|
|
||||||
$d = str_split($d);
|
|
||||||
$l = array_pop($d);
|
|
||||||
$b = '';
|
|
||||||
foreach ($d as $c) {
|
|
||||||
$b .= sprintf("%05b", strpos($charset, $c));
|
|
||||||
}
|
|
||||||
$padding = 8 - strlen($b) % 8;
|
|
||||||
$b .= str_pad(decbin(strpos($charset, $l)), $padding, '0', STR_PAD_LEFT);
|
|
||||||
|
|
||||||
return implode('', array_map(function($c) { return chr(bindec($c)); }, str_split($b, 8)));
|
|
||||||
}
|
|
||||||
|
|
||||||
function base32_encode($d) {
|
|
||||||
$charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
|
|
||||||
$b = implode('', array_map(function($c) { return sprintf("%08b", ord($c)); }, str_split($d)));
|
|
||||||
return implode('', array_map(function($c) use ($charset) { return $charset[bindec($c)]; }, str_split($b, 5)));
|
|
||||||
}
|
|
||||||
|
|
||||||
function cloak_ip($ip) {
|
function cloak_ip($ip) {
|
||||||
global $config;
|
global $config;
|
||||||
$ipcrypt_key = $config['ipcrypt_key'] ?: null;
|
$ipcrypt_key = $config['ipcrypt_key'] ?: null;
|
||||||
|
24
inc/functions/encoding.php
Normal file
24
inc/functions/encoding.php
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
defined('TINYBOARD') or exit;
|
||||||
|
|
||||||
|
|
||||||
|
function base32_decode($d) {
|
||||||
|
$charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
|
||||||
|
$d = str_split($d);
|
||||||
|
$l = array_pop($d);
|
||||||
|
$b = '';
|
||||||
|
foreach ($d as $c) {
|
||||||
|
$b .= sprintf("%05b", strpos($charset, $c));
|
||||||
|
}
|
||||||
|
$padding = 8 - strlen($b) % 8;
|
||||||
|
$b .= str_pad(decbin(strpos($charset, $l)), $padding, '0', STR_PAD_LEFT);
|
||||||
|
|
||||||
|
return implode('', array_map(function($c) { return chr(bindec($c)); }, str_split($b, 8)));
|
||||||
|
}
|
||||||
|
|
||||||
|
function base32_encode($d) {
|
||||||
|
$charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
|
||||||
|
$b = implode('', array_map(function($c) { return sprintf("%08b", ord($c)); }, str_split($d)));
|
||||||
|
return implode('', array_map(function($c) use ($charset) { return $charset[bindec($c)]; }, str_split($b, 5)));
|
||||||
|
}
|
60
inc/functions/error.php
Normal file
60
inc/functions/error.php
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<?php // Error handling
|
||||||
|
|
||||||
|
defined('TINYBOARD') or exit;
|
||||||
|
|
||||||
|
|
||||||
|
function _syslog($priority, $message) {
|
||||||
|
if (isset($_SERVER['REMOTE_ADDR'], $_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI'])) {
|
||||||
|
// CGI
|
||||||
|
syslog($priority, $message . ' - client: ' . $_SERVER['REMOTE_ADDR'] . ', request: "' . $_SERVER['REQUEST_METHOD'] . ' ' . $_SERVER['REQUEST_URI'] . '"');
|
||||||
|
} else {
|
||||||
|
syslog($priority, $message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function basic_error_function_because_the_other_isnt_loaded_yet($message, $priority = true) {
|
||||||
|
global $config;
|
||||||
|
|
||||||
|
if ($config['syslog'] && $priority !== false) {
|
||||||
|
// Use LOG_NOTICE instead of LOG_ERR or LOG_WARNING because most error message are not significant.
|
||||||
|
_syslog($priority !== true ? $priority : LOG_NOTICE, $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Yes, this is horrible.
|
||||||
|
die('<!DOCTYPE html><html><head><title>Error</title>' .
|
||||||
|
'<style type="text/css">' .
|
||||||
|
'body{text-align:center;font-family:arial, helvetica, sans-serif;font-size:10pt;}' .
|
||||||
|
'p{padding:0;margin:20px 0;}' .
|
||||||
|
'p.c{font-size:11px;}' .
|
||||||
|
'</style></head>' .
|
||||||
|
'<body><h2>Error</h2>' . $message . '<hr/>' .
|
||||||
|
'<p class="c">This alternative error page is being displayed because the other couldn\'t be found or hasn\'t loaded yet.</p></body></html>');
|
||||||
|
}
|
||||||
|
|
||||||
|
function fatal_error_handler() {
|
||||||
|
if ($error = error_get_last()) {
|
||||||
|
if ($error['type'] == E_ERROR) {
|
||||||
|
if (function_exists('error')) {
|
||||||
|
error('Caught fatal error: ' . $error['message'] . ' in <strong>' . $error['file'] . '</strong> on line ' . $error['line'], LOG_ERR);
|
||||||
|
} else {
|
||||||
|
basic_error_function_because_the_other_isnt_loaded_yet('Caught fatal error: ' . $error['message'] . ' in ' . $error['file'] . ' on line ' . $error['line'], LOG_ERR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function verbose_error_handler($errno, $errstr, $errfile, $errline) {
|
||||||
|
global $config;
|
||||||
|
|
||||||
|
if (error_reporting() == 0)
|
||||||
|
return false; // Looks like this warning was suppressed by the @ operator.
|
||||||
|
if ($errno == E_DEPRECATED && !$config['deprecation_errors'])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
error(utf8tohtml($errstr), true, array(
|
||||||
|
'file' => $errfile . ':' . $errline,
|
||||||
|
'errno' => $errno,
|
||||||
|
'error' => $errstr,
|
||||||
|
'backtrace' => array_slice(debug_backtrace(), 1)
|
||||||
|
));
|
||||||
|
}
|
188
inc/functions/fs.php
Normal file
188
inc/functions/fs.php
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
defined('TINYBOARD') or exit;
|
||||||
|
|
||||||
|
|
||||||
|
function file_write($path, $data, $simple = false, $skip_purge = false) {
|
||||||
|
global $config, $debug;
|
||||||
|
|
||||||
|
if (preg_match('/^remote:\/\/(.+)\:(.+)$/', $path, $m)) {
|
||||||
|
if (isset($config['remote'][$m[1]])) {
|
||||||
|
require_once 'inc/remote.php';
|
||||||
|
|
||||||
|
$remote = new Remote($config['remote'][$m[1]]);
|
||||||
|
$remote->write($data, $m[2]);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
error('Invalid remote server: ' . $m[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$fp = fopen($path, $simple ? 'w' : 'c')) {
|
||||||
|
error('Unable to open file for writing: ' . $path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// File locking
|
||||||
|
if (!$simple && !flock($fp, LOCK_EX)) {
|
||||||
|
error('Unable to lock file: ' . $path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Truncate file
|
||||||
|
if (!$simple && !ftruncate($fp, 0)) {
|
||||||
|
error('Unable to truncate file: ' . $path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write data
|
||||||
|
if (($bytes = fwrite($fp, $data)) === false) {
|
||||||
|
error('Unable to write to file: ' . $path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unlock
|
||||||
|
if (!$simple) {
|
||||||
|
flock($fp, LOCK_UN);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close
|
||||||
|
if (!fclose($fp)) {
|
||||||
|
error('Unable to close file: ' . $path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create gzipped file.
|
||||||
|
*
|
||||||
|
* When writing into a file foo.bar and the size is larger or equal to 1
|
||||||
|
* KiB, this also produces the gzipped version foo.bar.gz
|
||||||
|
*
|
||||||
|
* This is useful with nginx with gzip_static on.
|
||||||
|
*/
|
||||||
|
if ($config['gzip_static']) {
|
||||||
|
$gzpath = "$path.gz";
|
||||||
|
|
||||||
|
// if ($bytes >= 1024)
|
||||||
|
if ($bytes & ~0x3ff) {
|
||||||
|
if (file_put_contents($gzpath, gzencode($data), $simple ? 0 : LOCK_EX) === false) {
|
||||||
|
error("Unable to write to file: $gzpath");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
@unlink($gzpath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$skip_purge && isset($config['purge'])) {
|
||||||
|
// Purge cache
|
||||||
|
if (basename($path) == $config['file_index']) {
|
||||||
|
// Index file (/index.html); purge "/" as well
|
||||||
|
$uri = dirname($path);
|
||||||
|
// root
|
||||||
|
if ($uri == '.') {
|
||||||
|
$uri = '';
|
||||||
|
} else {
|
||||||
|
$uri .= '/';
|
||||||
|
}
|
||||||
|
purge($uri);
|
||||||
|
}
|
||||||
|
purge($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($config['debug']) {
|
||||||
|
$debug['write'][] = $path . ': ' . $bytes . ' bytes';
|
||||||
|
}
|
||||||
|
|
||||||
|
event('write', $path);
|
||||||
|
}
|
||||||
|
|
||||||
|
function file_unlink($path) {
|
||||||
|
global $config, $debug;
|
||||||
|
|
||||||
|
if ($config['debug']) {
|
||||||
|
if (!isset($debug['unlink'])) {
|
||||||
|
$debug['unlink'] = array();
|
||||||
|
}
|
||||||
|
$debug['unlink'][] = $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ret = @unlink($path);
|
||||||
|
|
||||||
|
if ($config['gzip_static']) {
|
||||||
|
$gzpath = "$path.gz";
|
||||||
|
|
||||||
|
@unlink($gzpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($config['purge']) && $path[0] != '/' && isset($_SERVER['HTTP_HOST'])) {
|
||||||
|
// Purge cache
|
||||||
|
if (basename($path) == $config['file_index']) {
|
||||||
|
// Index file (/index.html); purge "/" as well
|
||||||
|
$uri = dirname($path);
|
||||||
|
// root
|
||||||
|
if ($uri == '.') {
|
||||||
|
$uri = '';
|
||||||
|
} else {
|
||||||
|
$uri .= '/';
|
||||||
|
}
|
||||||
|
purge($uri);
|
||||||
|
}
|
||||||
|
purge($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
event('unlink', $path);
|
||||||
|
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
function purge($uri) {
|
||||||
|
global $config, $debug;
|
||||||
|
|
||||||
|
// Fix for Unicode
|
||||||
|
$uri = rawurlencode($uri);
|
||||||
|
|
||||||
|
$noescape = "/!~*()+:";
|
||||||
|
$noescape = preg_split('//', $noescape);
|
||||||
|
$noescape_url = array_map("rawurlencode", $noescape);
|
||||||
|
$uri = str_replace($noescape_url, $noescape, $uri);
|
||||||
|
|
||||||
|
if (preg_match($config['referer_match'], $config['root']) && isset($_SERVER['REQUEST_URI'])) {
|
||||||
|
$uri = (str_replace('\\', '/', dirname($_SERVER['REQUEST_URI'])) == '/' ? '/' : str_replace('\\', '/', dirname($_SERVER['REQUEST_URI'])) . '/') . $uri;
|
||||||
|
} else {
|
||||||
|
$uri = $config['root'] . $uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($config['debug']) {
|
||||||
|
$debug['purge'][] = $uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($config['purge'] as &$purge) {
|
||||||
|
$host = &$purge[0];
|
||||||
|
$port = &$purge[1];
|
||||||
|
$http_host = isset($purge[2]) ? $purge[2] : (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost');
|
||||||
|
$request = "PURGE {$uri} HTTP/1.1\r\nHost: {$http_host}\r\nUser-Agent: Tinyboard\r\nConnection: Close\r\n\r\n";
|
||||||
|
if ($fp = fsockopen($host, $port, $errno, $errstr, $config['purge_timeout'])) {
|
||||||
|
fwrite($fp, $request);
|
||||||
|
fclose($fp);
|
||||||
|
} else {
|
||||||
|
// Cannot connect?
|
||||||
|
error('Could not PURGE for ' . $host);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively delete a directory with it's content.
|
||||||
|
*/
|
||||||
|
function rrmdir($dir) {
|
||||||
|
if (is_dir($dir)) {
|
||||||
|
$objects = scandir($dir);
|
||||||
|
foreach ($objects as $object) {
|
||||||
|
if ($object != "." && $object != "..") {
|
||||||
|
if (filetype($dir."/".$object) == "dir") {
|
||||||
|
rrmdir($dir."/".$object);
|
||||||
|
} else {
|
||||||
|
file_unlink($dir."/".$object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reset($objects);
|
||||||
|
rmdir($dir);
|
||||||
|
}
|
||||||
|
}
|
63
inc/functions/generation-strategy.php
Normal file
63
inc/functions/generation-strategy.php
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<?php // Vichan specific generation strategy
|
||||||
|
|
||||||
|
defined('TINYBOARD') or exit;
|
||||||
|
|
||||||
|
|
||||||
|
function generation_strategy($fun, $array=array()) { global $config;
|
||||||
|
$action = false;
|
||||||
|
|
||||||
|
foreach ($config['generation_strategies'] as $s) {
|
||||||
|
if ($action = $s($fun, $array)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($action[0]) {
|
||||||
|
case 'immediate':
|
||||||
|
return 'rebuild';
|
||||||
|
case 'defer':
|
||||||
|
// Ok, it gets interesting here :)
|
||||||
|
get_queue('generate')->push(serialize(array('build', $fun, $array, $action)));
|
||||||
|
return 'ignore';
|
||||||
|
case 'build_on_load':
|
||||||
|
return 'delete';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function strategy_immediate($fun, $array) {
|
||||||
|
return array('immediate');
|
||||||
|
}
|
||||||
|
|
||||||
|
function strategy_smart_build($fun, $array) {
|
||||||
|
return array('build_on_load');
|
||||||
|
}
|
||||||
|
|
||||||
|
function strategy_sane($fun, $array) { global $config;
|
||||||
|
if (php_sapi_name() == 'cli') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
elseif (isset($_POST['mod'])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Thread needs to be done instantly. Same with a board page, but only if posting a new thread.
|
||||||
|
elseif ($fun == 'sb_thread' || ($fun == 'sb_board' && $array[1] == 1 && isset ($_POST['page']))) {
|
||||||
|
return array('immediate');
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// My first, test strategy.
|
||||||
|
function strategy_first($fun, $array) {
|
||||||
|
switch ($fun) {
|
||||||
|
case 'sb_thread':
|
||||||
|
case 'sb_api':
|
||||||
|
case 'sb_catalog':
|
||||||
|
case 'sb_ukko':
|
||||||
|
return array('defer');
|
||||||
|
case 'sb_board':
|
||||||
|
return $array[1] > 8 ? array('build_on_load') : array('defer');
|
||||||
|
case 'sb_recent':
|
||||||
|
case 'sb_sitemap':
|
||||||
|
return array('build_on_load');
|
||||||
|
}
|
||||||
|
}
|
28
inc/functions/interop.php
Normal file
28
inc/functions/interop.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
defined('TINYBOARD') or exit;
|
||||||
|
|
||||||
|
|
||||||
|
function shell_exec_error($command, $suppress_stdout = false) {
|
||||||
|
global $config, $debug;
|
||||||
|
|
||||||
|
if ($config['debug']) {
|
||||||
|
$start = microtime(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$return = trim(shell_exec('PATH="' . escapeshellcmd($config['shell_path']) . ':$PATH";' .
|
||||||
|
$command . ' 2>&1 ' . ($suppress_stdout ? '> /dev/null ' : '') . '&& echo "TB_SUCCESS"'));
|
||||||
|
$return = preg_replace('/TB_SUCCESS$/', '', $return);
|
||||||
|
|
||||||
|
if ($config['debug']) {
|
||||||
|
$time = microtime(true) - $start;
|
||||||
|
$debug['exec'][] = array(
|
||||||
|
'command' => $command,
|
||||||
|
'time' => '~' . round($time * 1000, 2) . 'ms',
|
||||||
|
'response' => $return ? $return : null
|
||||||
|
);
|
||||||
|
$debug['time']['exec'] += $time;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $return === 'TB_SUCCESS' ? false : $return;
|
||||||
|
}
|
33
inc/functions/math.php
Normal file
33
inc/functions/math.php
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?php // Math related functions
|
||||||
|
|
||||||
|
defined('TINYBOARD') or exit;
|
||||||
|
|
||||||
|
|
||||||
|
// Highest common factor
|
||||||
|
function hcf($a, $b){
|
||||||
|
$gcd = 1;
|
||||||
|
if ($a>$b) {
|
||||||
|
$a = $a+$b;
|
||||||
|
$b = $a-$b;
|
||||||
|
$a = $a-$b;
|
||||||
|
}
|
||||||
|
if ($b == round($b / $a) * $a) {
|
||||||
|
$gcd=$a;
|
||||||
|
} else {
|
||||||
|
for ($i = round($a / 2); $i; $i--) {
|
||||||
|
if ($a == round($a / $i) * $i && $b == round($b / $i) * $i) {
|
||||||
|
$gcd = $i;
|
||||||
|
$i = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $gcd;
|
||||||
|
}
|
||||||
|
|
||||||
|
function fraction($numerator, $denominator, $sep) {
|
||||||
|
$gcf = hcf($numerator, $denominator);
|
||||||
|
$numerator = $numerator / $gcf;
|
||||||
|
$denominator = $denominator / $gcf;
|
||||||
|
|
||||||
|
return "{$numerator}{$sep}{$denominator}";
|
||||||
|
}
|
71
inc/functions/net.php
Normal file
71
inc/functions/net.php
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<?php // Networking related functions
|
||||||
|
|
||||||
|
defined('TINYBOARD') or exit;
|
||||||
|
|
||||||
|
|
||||||
|
function isIPv6() {
|
||||||
|
return strstr($_SERVER['REMOTE_ADDR'], ':') !== false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ReverseIPOctets($ip) {
|
||||||
|
return implode('.', array_reverse(explode('.', $ip)));
|
||||||
|
}
|
||||||
|
|
||||||
|
function rDNS($ip_addr) {
|
||||||
|
global $config;
|
||||||
|
|
||||||
|
if ($config['cache']['enabled'] && ($host = cache::get('rdns_' . $ip_addr))) {
|
||||||
|
return $host;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$config['dns_system']) {
|
||||||
|
$host = gethostbyaddr($ip_addr);
|
||||||
|
} else {
|
||||||
|
$resp = shell_exec_error('host -W 3 ' . $ip_addr);
|
||||||
|
if (preg_match('/domain name pointer ([^\s]+)$/', $resp, $m)) {
|
||||||
|
$host = $m[1];
|
||||||
|
} else {
|
||||||
|
$host = $ip_addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$isip = filter_var($host, FILTER_VALIDATE_IP);
|
||||||
|
|
||||||
|
if ($config['fcrdns'] && !$isip && DNS($host) != $ip_addr) {
|
||||||
|
$host = $ip_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($config['cache']['enabled']) {
|
||||||
|
cache::set('rdns_' . $ip_addr, $host);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $host;
|
||||||
|
}
|
||||||
|
|
||||||
|
function DNS($host) {
|
||||||
|
global $config;
|
||||||
|
|
||||||
|
if ($config['cache']['enabled'] && ($ip_addr = cache::get('dns_' . $host))) {
|
||||||
|
return $ip_addr != '?' ? $ip_addr : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$config['dns_system']) {
|
||||||
|
$ip_addr = gethostbyname($host);
|
||||||
|
if ($ip_addr == $host) {
|
||||||
|
$ip_addr = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$resp = shell_exec_error('host -W 1 ' . $host);
|
||||||
|
if (preg_match('/has address ([^\s]+)$/', $resp, $m)) {
|
||||||
|
$ip_addr = $m[1];
|
||||||
|
} else {
|
||||||
|
$ip_addr = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($config['cache']['enabled']) {
|
||||||
|
cache::set('dns_' . $host, $ip_addr !== false ? $ip_addr : '?');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ip_addr;
|
||||||
|
}
|
43
inc/functions/text.php
Normal file
43
inc/functions/text.php
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<?php // Text handling functions.
|
||||||
|
|
||||||
|
defined('TINYBOARD') or exit;
|
||||||
|
|
||||||
|
|
||||||
|
function sprintf3($str, $vars, $delim = '%') {
|
||||||
|
$replaces = array();
|
||||||
|
foreach ($vars as $k => $v) {
|
||||||
|
$replaces[$delim . $k . $delim] = $v;
|
||||||
|
}
|
||||||
|
return str_replace(array_keys($replaces), array_values($replaces), $str);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mb_substr_replace($string, $replacement, $start, $length) {
|
||||||
|
return mb_substr($string, 0, $start) . $replacement . mb_substr($string, $start + $length);
|
||||||
|
}
|
||||||
|
|
||||||
|
function format_timestamp($timestamp) {
|
||||||
|
switch(TRUE) {
|
||||||
|
case ($timestamp < 60):
|
||||||
|
return $timestamp . ' ' . ngettext('second', 'seconds', $timestamp);
|
||||||
|
case ($timestamp < 3600): //60*60 = 3600
|
||||||
|
return ($num = round($timestamp / 60)) . ' ' . ngettext('minute', 'minutes', $num);
|
||||||
|
case ($timestamp < 86400): //60*60*24 = 86400
|
||||||
|
return ($num = round($timestamp / 3600)) . ' ' . ngettext('hour', 'hours', $num);
|
||||||
|
case ($timestamp < 604800): //60*60*24*7 = 604800
|
||||||
|
return ($num = round($timestamp / 86400)) . ' ' . ngettext('day', 'days', $num);
|
||||||
|
case ($timestamp < 31536000): //60*60*24*365 = 31536000
|
||||||
|
return ($num = round($timestamp / 604800)) . ' ' . ngettext('week', 'weeks', $num);
|
||||||
|
default:
|
||||||
|
return ($num = round($timestamp / 31536000)) . ' ' . ngettext('year', 'years', $num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function until($timestamp) {
|
||||||
|
$difference = $timestamp - time();
|
||||||
|
return format_timestamp($difference);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ago($timestamp) {
|
||||||
|
$difference = time() - $timestamp;
|
||||||
|
return format_timestamp($difference);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user