Skip to content
5643 lines (5219 sloc) 141 KB
<?php
/**
* Main function library.
*
* @package API - Functions
* @copyright (c) Cotonti Team
* @license https://github.com/Cotonti/Cotonti/blob/master/License.txt
*/
defined('COT_CODE') or die('Wrong URL');
// System requirements check
if (!defined('COT_INSTALL'))
{
(function_exists('version_compare') && version_compare(PHP_VERSION, '5.3.3', '>=')) or die('Cotonti system requirements: PHP 5.3.3 or above.'); // TODO: Need translate
extension_loaded('mbstring') or die('Cotonti system requirements: mbstring PHP extension must be loaded.'); // TODO: Need translate
}
// Group constants
define('COT_GROUP_DEFAULT', 0);
define('COT_GROUP_GUESTS', 1);
define('COT_GROUP_INACTIVE', 2);
define('COT_GROUP_BANNED', 3);
define('COT_GROUP_MEMBERS', 4);
define('COT_GROUP_SUPERADMINS', 5);
define('COT_GROUP_MODERATORS', 6);
/* ======== Pre-sets ========= */
$out = array();
$plu = array();
$sys = array();
$usr = array();
$env = array();
$L = array();
$R = array();
$i = explode(' ', microtime());
$sys['starttime'] = $i[1] + $i[0];
$cfg['version'] = '0.9.19';
$cfg['dbversion'] = '0.9.19';
// Set default file permissions if not present in config
if (!isset($cfg['file_perms']))
{
$cfg['file_perms'] = 0664;
}
if (!isset($cfg['dir_perms']))
{
$cfg['dir_perms'] = 0777;
}
/**
* Registry for captcha functions
*/
$cot_captcha = array();
/**
* Registry for extra fields
* @var array
*/
$cot_extrafields = null;
/**
* Registry for hash functions
*/
$cot_hash_funcs = array('md5', 'sha1', 'sha256');
/**
* Array of custom cot_import() filter callbacks
*/
$cot_import_filters = array();
/**
* Custom e-mail send callbacks
*/
$cot_mail_senders = array();
/**
* Custom parser functions registry
*/
$cot_parsers = array();
/**
* Parameters to be automatically appended to all URLs if present
*/
$cot_url_appendix = array();
/**
* Structure tree
* @var array
*/
$structure = array();
/**
* Facade class to access key Cotonti globals regardless of scope
*/
class cot
{
/**
* Cotonti cache
* @var Cache
*/
public static $cache;
/**
* Cotonti configuration
* @var array
*/
public static $cfg;
/**
* Database connection
* @var CotDB
*/
public static $db;
/**
* Database table name prefix
*/
public static $db_x;
/**
* Environment settings
* @var array
*/
public static $env;
/**
* Extra fields
* @var array
*/
public static $extrafields;
/**
* Language strings
* @var array
*/
public static $L;
/**
* Pre-rendered output strings
* @var array
*/
public static $out;
/**
* Resource strings
* @var array
*/
public static $R;
/**
* Structure tree and properties array
* @var array
*/
public static $structure;
/**
* Temporary system variables
* @var array
*/
public static $sys;
/**
* Current user object
* @var array
*/
public static $usr;
/**
* Initializes static members. Call this function once all globals are defined.
*/
public static function init()
{
global $cache, $cfg, $cot_extrafields, $db, $db_x, $env, $L, $out, $R, $structure, $sys, $usr;
self::$cache =& $cache;
self::$cfg =& $cfg;
self::$db =& $db;
self::$db_x =& $db_x;
self::$env =& $env;
self::$extrafields =& $cot_extrafields;
self::$L =& $L;
self::$out =& $out;
self::$R =& $R;
self::$structure =& $structure;
self::$sys =& $sys;
self::$usr =& $usr;
// Register core DB tables
$db->registerTable('auth');
$db->registerTable('cache');
$db->registerTable('cache_bindings');
$db->registerTable('core');
$db->registerTable('config');
$db->registerTable('groups');
$db->registerTable('groups_users');
$db->registerTable('logger');
$db->registerTable('online');
$db->registerTable('extra_fields');
$db->registerTable('plugins');
$db->registerTable('structure');
$db->registerTable('updates');
$db->registerTable('users');
}
}
/*
* =========================== System Functions ===============================
*/
/**
* Strips everything but alphanumeric, hyphens and underscores
*
* @param string $text Input
* @return string
*/
function cot_alphaonly($text)
{
return(preg_replace('/[^a-zA-Z0-9\-_]/', '', $text));
}
/**
* Generic autoloader function to be used with spl_autoload_register
*
* @param string $class Class name
*/
function cot_autoload($class)
{
global $cfg, $env;
if ($env['type'] == 'module')
{
$paths[] = "{$cfg['modules_dir']}/{$env['ext']}/classes/$class.php";
}
elseif ($env['type'] == 'plug')
{
$paths[] = "{$cfg['plugins_dir']}/{$env['ext']}/classes/$class.php";
}
$paths[] = "{$cfg['system_dir']}/classes/$class.php";
foreach ($paths as $path)
{
if (file_exists($path))
{
require $path;
return;
}
}
}
/**
* Truncates a string
*
* @param string $res Source string
* @param int $l Length
* @return string
*/
function cot_cutstring($res, $l)
{
if (mb_strlen($res)>$l)
{
$res = mb_substr($res, 0, ($l-3)).'...';
}
return $res;
}
/**
* Returns name part of the caller file. Use this in plugins to detect from which file
* current hook part was included. Example:
* <code>
* if (cot_get_caller() == 'users.details')
* {
* // We are called from users.details
* }
* else if (cot_get_caller() == 'header')
* {
* // We are called from header
* }
* </code>
* @return string Caller file basename without .php suffix on success, 'unknown' or error
*/
function cot_get_caller()
{
$bt = debug_backtrace();
if (isset($bt[1]) && in_array($bt[1]['function'], array('include', 'require_once', 'require', 'include_once')))
{
return preg_replace('#\.php$#', '', basename($bt[1]['file']));
}
else
{
return 'unknown';
}
}
/**
* Returns a list of plugins registered for a hook
*
* @param string $hook Hook name
* @param string $cond Permissions
* @return array
* @global Cache $cache
*/
function cot_getextplugins($hook, $cond='R')
{
global $cot_plugins, $cache, $cfg, $cot_hooks_fired;
if ($cfg['debug_mode'])
{
$cot_hooks_fired[] = $hook;
}
$extplugins = array();
if (isset($cot_plugins[$hook]) && is_array($cot_plugins[$hook]))
{
foreach($cot_plugins[$hook] as $k)
{
if ($k['pl_module'])
{
$dir = $cfg['modules_dir'];
$cat = $k['pl_code'];
$opt = 'a';
}
else
{
$dir = $cfg['plugins_dir'];
$cat = 'plug';
$opt = $k['pl_code'];
}
if (cot_auth($cat, $opt, $cond))
{
$extplugins[] = $dir . '/' . $k['pl_file'];
}
}
}
// Trigger cache handlers
$cache && $cache->trigger($hook);
return $extplugins;
}
/**
* Imports data from the outer world
*
* @param string $name Variable name
* @param string $source Source type: G/GET, P/POST, C/COOKIE, R/REQUEST, PUT, DELETE or D/DIRECT (variable filtering)
* @param string $filter Filter type
* @param int $maxlen Length limit
* @param bool $dieonerror Die with fatal error on wrong input
* @param bool $buffer Try to load from input buffer (previously submitted) if current value is empty
* @return mixed
*/
function cot_import($name, $source, $filter, $maxlen = 0, $dieonerror = false, $buffer = false)
{
global $cot_import_filters, $_PUT, $_PATCH, $_DELETE;
if(isset($_SERVER['REQUEST_METHOD']))
{
if ($_SERVER['REQUEST_METHOD'] == 'PUT' && is_null($_PUT))
{
parse_str(file_get_contents('php://input'), $_PUT);
}
elseif ($_SERVER['REQUEST_METHOD'] == 'PATCH' && is_null($_PATCH))
{
parse_str(file_get_contents('php://input'), $_PATCH);
}
elseif ($_SERVER['REQUEST_METHOD'] == 'DELETE' && is_null($_DELETE))
{
parse_str(file_get_contents('php://input'), $_DELETE);
}
}
$v = NULL;
switch($source)
{
case 'G':
case 'GET':
$v = (isset($_GET[$name])) ? $_GET[$name] : NULL;
$log = TRUE;
break;
case 'P':
case 'POST':
$v = (isset($_POST[$name])) ? $_POST[$name] : NULL;
$log = TRUE;
break;
case 'PUT':
$v = (isset($_PUT[$name])) ? $_PUT[$name] : NULL;
$log = TRUE;
break;
case 'PATCH':
$v = (isset($_PATCH[$name])) ? $_PATCH[$name] : NULL;
$log = TRUE;
break;
case 'DELETE':
$v = (isset($_DELETE[$name])) ? $_DELETE[$name] : NULL;
$log = TRUE;
break;
case 'R':
case 'REQUEST':
$v = (isset($_REQUEST[$name])) ? $_REQUEST[$name] : NULL;
$log = TRUE;
break;
case 'C':
case 'COOKIE':
$v = (isset($_COOKIE[$name])) ? $_COOKIE[$name] : NULL;
$log = TRUE;
break;
case 'D':
case 'DIRECT':
$v = $name;
$log = FALSE;
break;
default:
cot_diefatal('Unknown source for a variable : <br />Name = '.$name.'<br />Source = '.$source.' ? (must be G, P, C or D)');
break;
}
if (is_array($v))
{
if ($filter == 'NOC') $filter = 'ARR';
if ($filter != 'ARR') return null;
}
else
{
if ($filter == 'ARR') return array();
}
if (MQGPC && ($source=='G' || $source=='P' || $source=='C') && $v != NULL && $filter != 'ARR')
{
$v = stripslashes($v);
}
if (($v === '' || $v === NULL || $filter == 'ARR') && $buffer)
{
$v = cot_import_buffered($name, $v, null);
return $v;
}
if ($v === null)
{
return null;
}
if ($maxlen>0)
{
$v = mb_substr($v, 0, $maxlen);
}
$pass = FALSE;
$defret = NULL;
// Custom filter support
if (is_array($cot_import_filters[$filter]))
{
foreach ($cot_import_filters[$filter] as $func)
{
$v = $func($v, $name);
}
return $v;
}
switch($filter)
{
case 'INT':
if (is_numeric($v) && floor($v)==$v)
{
$pass = TRUE;
$v = (int) $v;
}
break;
case 'NUM':
if (is_numeric($v))
{
$pass = TRUE;
$v = (float) $v;
}
break;
case 'TXT':
$v = trim($v);
if (mb_strpos($v, '<')===FALSE)
{
$pass = TRUE;
}
else
{
$defret = str_replace('<', '&lt;', $v);
}
break;
case 'ALP':
$v = trim($v);
$f = cot_alphaonly($v);
if ($v == $f)
{
$pass = TRUE;
}
else
{
$defret = $f;
}
break;
case 'PSW':
$v = trim($v);
$f = preg_replace('#[\'"&<>]#', '', $v);
$f = mb_substr($f, 0 ,32);
if ($v == $f)
{
$pass = TRUE;
}
else
{
$defret = $f;
}
break;
case 'HTM':
$v = trim($v);
$pass = TRUE;
break;
case 'ARR':
$pass = TRUE;
break;
case 'BOL':
if ($v == '1' || $v == 'on')
{
$pass = TRUE;
$v = TRUE;
}
elseif ($v=='0' || $v=='off')
{
$pass = TRUE;
$v = FALSE;
}
else
{
$defret = FALSE;
}
break;
case 'NOC':
$pass = TRUE;
break;
default:
cot_diefatal('Unknown filter for a variable : <br />Var = '.$v.'<br />Filter = &quot;'.$filter.'&quot; ?');
break;
}
if (!$pass || !in_array($filter, array('INT', 'NUM', 'BOL', 'ARR')))
{
$v = preg_replace('/(&#\d+)(?![\d;])/', '$1;', $v);
}
if ($pass)
{
return $v;
}
else
{
if ($log)
{
cot_log_import($source, $filter, $name, $v);
}
if ($dieonerror)
{
cot_diefatal('Wrong input.');
}
else
{
return $defret;
}
}
}
/**
* Imports data from the outer world by list of Variable names
* Relies on `cot_import` function
*
* @param mixed $nameslist List of Variables names to import, can be:<br />
* string 'name1, name2 , ...' - list of variable names comma separated.<br />
* array('name1', 'name2', ...) - list of variable names only.
* In that case $filter parameter must be specified.<br />
* array('name1' => 'TYPE1', 'name2' => 'TYPE2' ,...) - list of variable names with their filter types
* @param string $source Source type: G/GET, P/POST, C/COOKIE, R/REQUEST, PUT, DELETE or D/DIRECT (variable filtering)
* @param array $origindata Array with origin data that will be extended with imported one
* @param string $nameprefix Unified prefix for Variables names
* @param string $filter Filter type, can be set as:<br />
* string 'FLT' - single filter string for all Variables<br />
* string 'FLT1, FLT2, ...' - comma separated string with filters corresponding to Variable names<br />
* array('FLT1', 'FLT2', ...) - array of filters<br />
* Overrides Filter types specified in $nameslist. If passed as list - number of Filters must be equal to count of
* variables names in $nameslist.
*
* @param bool $arrayprefix Use $nameprefix for array fields
* @param int $maxlen Length limit
* @param bool $dieonerror Die with fatal error on wrong input
* @param bool $buffer Try to load from input buffer (previously submitted) if current value is empty
* @return boolean|array Returns combined array of data or FALSE if wrong parameters set
*/
function cot_import_list($nameslist=array(), $source='P', $origindata=array(), $nameprefix='', $filter=null, $arrayprefix=false, $maxlen=0, $dieonerror=false, $buffer=false)
{
$direct = ($source == 'D' || $source == 'DIRECT');
$filter = empty($filter) ? null : $filter;
$nameslist = empty($nameslist) ? array() : $nameslist;
$origindata = !is_array($origindata) ? array() : $origindata;
if (!is_array($nameslist) && !empty($nameslist))
{
$nameslist = array_map('trim', explode(',',$nameslist));
}
if (!is_array($filter) && strpos($filter, ',') !== false)
{
$filter = array_map('trim', explode(',',$filter));
}
elseif (!is_array($filter) && !is_null($filter))
{
$filter = array_fill(0,sizeof($direct && empty($nameslist) ? $origindata : $nameslist),$filter);
}
if (!$direct && sizeof($nameslist) == 0)
{
return false; // no proper name list
}
elseif (sizeof($nameslist) == 0)
{ // direct by origin
if (is_null($filter)) return false;
foreach ($origindata as $key => $value) {
$origindata[$key] = cot_import($value, 'D', array_shift($filter), $maxlen, $dieonerror);
}
}
else
{ // namelist exists
$index = array_keys($nameslist);
$index = array_pop($index);
$types_not_defined = (is_numeric($index) && is_int($index));
if ((is_array($filter) && sizeof($filter) != sizeof($nameslist))
|| ($types_not_defined && is_null($filter)))
{
return false; // can't rely on filter or no filter exists
}
elseif (is_array($filter))
{
$nameslist = array_combine($types_not_defined ? $nameslist : array_keys($nameslist), $filter);
}
foreach ($nameslist as $name => $filtertype) {
$origindata[($arrayprefix) ? $nameprefix.$name : $name] = cot_import($direct ? $origindata[$nameprefix.$name] : $nameprefix.$name, $source, $filtertype, $maxlen, $dieonerror, $buffer);
}
}
return $origindata;
}
/**
* Imports data from the outer world as indexed array of records imported by cot_import_list.
* Used to import table editing data as one array ordered by index (IDs) of table lines.
*
* @param For parameters see `cot_import_list`:
*
* @return boolean|array Returns indexed array of data or FALSE if wrong parameters setted
*/
function cot_import_tabledata($nameslist=array(), $source='P', $nameprefix='', $origindata=array(), $maxlen=0, $dieonerror=false, $buffer=false)
{
$imported_arrays = cot_import_list($nameslist, $source, $origindata, $nameprefix,'ARR', $maxlen, $dieonerror, $buffer);
if (!$imported_arrays) return false;
$result = array();
$na_data = array();
foreach ($imported_arrays as $name => $data)
{
if (!is_array($data))
{
$na_data[$name] = $data;
unset($imported_arrays[$name]);
}
}
foreach ($imported_arrays as $name => $data)
{
if (is_array($data))
{
foreach ($data as $index => $value)
{
$result[$index][$name] = $value;
foreach ($na_data as $k => $v) {
$result[$index][$k] = $v;
}
}
}
}
return $result;
}
/**
* Puts POST data into the cross-request buffer
*/
function cot_import_buffer_save()
{
// Referer contains an original form link
if (cot_url_check($_SERVER['HTTP_REFERER']))
{
// Extract the server-relative part
$url = parse_url($_SERVER['HTTP_REFERER']);
// Strip ajax param from the query
$url['query'] = str_replace('&_ajax=1', '', $url['query']);
$path = empty($url['query']) ? $url['path'] : $url['path'] . '?' . $url['query'];
$hash = md5($path);
// Save the buffer
$_SESSION['cot_buffer'][$hash] = $_POST;
}
}
/**
* Attempts to fetch a buffered value for a variable previously imported
* if the currently imported value is empty
*
* @param string $name Input name
* @param mixed $value Currently imported value
* @param mixed $null null import
* @return mixed Input value or NULL if the variable is not in the buffer
*/
function cot_import_buffered($name, $value, $null = '')
{
// Params hash for current form
$uri = str_replace('&_ajax=1', '', $_SERVER['REQUEST_URI']);
$hash = md5($uri);
if ($value === '' || $value === null
|| isset($_SESSION['cot_buffer'][$hash][$name]) && !empty($_SESSION['cot_buffer'][$hash][$name]))
{
if (isset($_SESSION['cot_buffer'][$hash][$name]))
{
return $_SESSION['cot_buffer'][$hash][$name];
}
else
{
return $null;
}
}
else
{
return $value;
}
}
/**
* Imports date stamp
*
* @param string $name Variable name preffix
* @param bool $usertimezone Use user timezone
* @param bool $returnarray Return Date Array
* @param string $source Source type: P (POST), C (COOKIE) or D (variable filtering)
* @return mixed
*/
function cot_import_date($name, $usertimezone = true, $returnarray = false, $source = 'P')
{
global $usr;
//$name = preg_match('#^(\w+)\[(.*?)\]$#', $name, $mt) ? $mt[1] : $name;
$date = cot_import($name, $source, 'ARR');
$year = cot_import($date['year'], 'D', 'INT');
$month = cot_import($date['month'], 'D', 'INT');
$day = cot_import($date['day'], 'D', 'INT');
$hour = cot_import($date['hour'], 'D', 'INT');
$minute = cot_import($date['minute'], 'D', 'INT');
if (count($date) > 0 && is_null($year) && is_null($month) && is_null($day) && is_null($hour) && is_null($minute))
{
// Datetime field is present in form but it is set to zero date (empty)
return NULL;
}
if (($month && $day && $year) || ($day && $minute))
{
$timestamp = cot_mktime($hour, $minute, 0, $month, $day, $year);
}
else
{
$string = cot_import($date['string'], 'D', 'TXT');
$format = cot_import($date['format'], 'D', 'TXT');
if ($string && $format)
{
$timestamp = cot_date2stamp($string, $format);
}
else
{
return NULL;
}
}
if ($usertimezone)
{
$timestamp -= $usr['timezone'] * 3600;
}
if ($returnarray)
{
$result = array();
$result['stamp'] = $timestamp;
$result['year'] = (int)date('Y', $timestamp);
$result['month'] = (int)date('m', $timestamp);
$result['day'] = (int)date('d', $timestamp);
$result['hour'] = (int)date('H', $timestamp);
$result['minute'] = (int)date('i', $timestamp);
return $result;
}
return $timestamp;
}
/**
* Imports pagination indexes
*
* @param string $var_name URL parameter name, e.g. 'pg' or 'd'
* @param int $max_items Max items per page
* @return array Array containing 3 items: page number, database offset and argument for URLs
*/
function cot_import_pagenav($var_name, $max_items = 0)
{
global $cfg;
if($max_items <= 0)
{
$max_items = $cfg['maxrowsperpage'];
}
if($max_items <= 0)
{
throw new Exception('Invalid $max_items ('.$max_items.') for pagination.');
}
if ($cfg['easypagenav'])
{
$page = (int) cot_import($var_name, 'G', 'INT');
if ($page < 0)
{
cot_die_message(404);
}
elseif ($page == 0)
{
$page = 1;
}
$offset = ($page - 1) * $max_items;
$urlnum = $page <= 1 ? null : $page;
}
else
{
$offset = (int) cot_import($var_name, 'G', 'INT');
if ($offset < 0)
{
cot_die_message(404);
}
if ($offset % $max_items != 0)
{
$offset -= $offset % $max_items;
}
$page = floor($offset / $max_items) + 1;
$urlnum = $offset;
$urlnum = ($urlnum > 0) ? $urlnum : null;
}
return array($page, $offset, $urlnum);
}
/**
* Checks the email
*
* @param string $res input string
* @return bool True if email valid
*/
function cot_check_email($res)
{
return mb_strlen($res) > 4 && preg_match('#^[\w\p{L}][\.\w\p{L}\-]*@[\w\p{L}\.\-]+\.[\w\p{L}]+$#u', $res);
}
/**
* Sends mail with standard PHP mail().
* If cot_mail_custom() function exists, it will be called instead of the PHP
* function. This way custom mail delivery methods, such as SMTP, are
* supported.
*
* @global $cfg
* @param string $fmail Recipient
* @param string $subject Subject
* @param string $body Message body
* @param string $headers Message headers
* @param bool $customtemplate Use custom template
* @param string $additional_parameters Additional parameters passed to sendmail
* @return bool
*/
function cot_mail($fmail, $subject, $body, $headers='', $customtemplate = false, $additional_parameters = null, $html = false)
{
global $cfg, $cot_mail_senders;
if (function_exists('cot_mail_custom'))
{
return cot_mail_custom($fmail, $subject, $body, $headers, $customtemplate, $additional_parameters, $html);
}
if (is_array($cot_mail_senders) && count($cot_mail_senders) > 0)
{
foreach ($cot_mail_senders as $func)
{
$ret &= $func($fmail, $subject, $body, $headers, $additional_parameters, $html);
}
return $ret;
}
if (empty($fmail))
{
return false;
}
else
{
$sitemaintitle = mb_encode_mimeheader($cfg['maintitle'], 'UTF-8', 'B', "\n");
$headers = (empty($headers)) ? "From: \"" . $sitemaintitle . "\" <" . $cfg['adminemail'] . ">\n" . "Reply-To: <" . $cfg['adminemail'] . ">\n"
: $headers;
$headers .= "Message-ID: <" . md5(uniqid(microtime())) . "@" . $_SERVER['SERVER_NAME'] . ">\n";
$type_body = $html ? "html" : "plain";
$headers .= "Content-Type: text/".$type_body."; charset=UTF-8\n";
$headers .= "Content-Transfer-Encoding: 8bit\n";
if (!$customtemplate)
{
$body_params = array(
'SITE_TITLE' => $cfg['maintitle'],
'SITE_URL' => $cfg['mainurl'],
'SITE_DESCRIPTION' => $cfg['subtitle'],
'ADMIN_EMAIL' => $cfg['adminemail'],
'MAIL_SUBJECT' => $subject,
'MAIL_BODY' => $body
);
$subject_params = array(
'SITE_TITLE' => $cfg['maintitle'],
'SITE_DESCRIPTION' => $cfg['subtitle'],
'MAIL_SUBJECT' => $subject
);
$subject = cot_title($cfg['subject_mail'], $subject_params, false);
$body = cot_title(str_replace("\r\n", "\n", $cfg['body_mail']), $body_params, false);
}
$subject = mb_encode_mimeheader($subject, 'UTF-8', 'B', "\n");
if (ini_get('safe_mode'))
{
mail($fmail, $subject, $body, $headers);
}
else
{
mail($fmail, $subject, $body, $headers, $additional_parameters);
}
return true;
}
}
/**
* Checks if a module is currently installed and active
*
* @global array $cot_modules Module registry
* @param string $name Module name
* @return bool
*/
function cot_module_active($name)
{
global $cot_modules;
return isset($cot_modules[$name]);
}
/**
* Applies output filters, adds XSS protection to POST forms
* Note: XSS can be switched off by adding "xp-off" class to form
*
* @param string $output
* @return string
*/
function cot_outputfilters($output)
{
/* === Hook === */
foreach (cot_getextplugins('output') as $pl)
{
include realpath(dirname(__FILE__).'/..') . '/' . $pl;
}
/* ==== */
$output = preg_replace_callback('#<form\s+[^>]*method=["\']?post["\']?[^>]*>#i', 'cot_outputfilters_callback', $output);
return($output);
}
/**
* Used with cot_outputfilters
* It is needed because php 5.2 does not support anonymous functions. So during the installation we can not even show
* an error message.
* @param $m
* @return string
*/
function cot_outputfilters_callback($m)
{
return $m[0] . (preg_match('/class\s*=\s*["\']?.*?[\s"\']xp-off[\s"\'].*?["\']?/i', $m[0]) ? '' : cot_xp());
}
/**
* Checks if a plugin is currently installed and active
*
* @global array $cot_plugins_active Active plugins registry
* @param string $name Plugin name
* @return bool
*/
function cot_plugin_active($name)
{
global $cot_plugins_active;
return is_array($cot_plugins_active) && isset($cot_plugins_active[$name]);
}
/**
* Removes a directory recursively
* @param string $dir Directory path
* @return int Number of files and folders removed
*/
function cot_rmdir($dir)
{
if(empty($dir) && $dir != '0') return false;
static $cnt = 0;
if (is_dir($dir)) {
$objects = scandir($dir);
foreach ($objects as $f) {
$path = $dir . DIRECTORY_SEPARATOR . $f;
if ($f != "." && $f != "..")
{
if (filetype($path) == "dir")
{
cot_rmdir($path);
}
else
{
unlink($path);
$cnt++;
}
}
}
reset($objects);
rmdir($dir);
$cnt++;
}
return $cnt;
}
/**
* Sends standard HTTP headers and disables browser cache
*
* @param string $content_type Content-Type value (without charset)
* @param string $response_code HTTP response code, e.g. '404 Not Found'
* @param int $last_modified Last modified time
* @return bool
*/
function cot_sendheaders($content_type = 'text/html', $response_code = '200 OK', $last_modified = 0)
{
global $sys;
$protocol = (isset($_SERVER['SERVER_PROTOCOL'])) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1';
$last_modified = (int)$last_modified > 0 ? (int)$last_modified : 0;
if ($last_modified > 0)
{
$modified_since = (isset($_ENV['HTTP_IF_MODIFIED_SINCE'])) ? strtotime(substr($_ENV['HTTP_IF_MODIFIED_SINCE'], 5)) : false;
$modified_since = (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) ? strtotime(substr($_SERVER['HTTP_IF_MODIFIED_SINCE'], 5)) : $modified_since;
if ($modified_since && $modified_since >= $last_modified)
{
header($protocol . ' 304 Not Modified');
exit;
}
}
else
{
$last_modified = $sys['now'] - 3600*12;
}
header($protocol . ' ' . $response_code);
header('Expires: Mon, Apr 01 1974 00:00:00 GMT');
header('Last-Modified: '.gmdate('D, d M Y H:i:s', $last_modified).' GMT');
header('Content-Type: '.$content_type.'; charset=UTF-8');
header('Cache-Control: no-store,no-cache,must-revalidate');
header('Cache-Control: post-check=0,pre-check=0', FALSE);
header('Pragma: no-cache');
return TRUE;
}
/**
* Set cookie with optional HttpOnly flag
* @param string $name The name of the cookie
* @param string $value The value of the cookie
* @param int $expire The time the cookie expires in unixtime
* @param string $path The path on the server in which the cookie will be available on.
* @param string $domain The domain that the cookie is available.
* @param bool $secure Indicates that the cookie should only be transmitted over a secure HTTPS connection. When set to TRUE, the cookie will only be set if a secure connection exists.
* @param bool $httponly HttpOnly flag
* @return bool
*/
function cot_setcookie($name, $value, $expire = '', $path='', $domain='', $secure = false, $httponly = true)
{
global $cfg;
if (mb_strpos($domain, '.') === FALSE)
{
// Some browsers don't support cookies for local domains
$domain = '';
}
$domain = (empty($domain)) ? $cfg['cookiedomain'] : $domain;
$path = (empty($path)) ? $cfg['cookiepath'] : $path;
$expire = (empty($expire)) ? time()+$cfg['cookielifetime'] : $expire;
if ($domain != '' && $domain != 'localhost')
{
// Make sure www. is stripped and leading dot is added for subdomain support on some browsers
if (mb_strtolower(mb_substr($domain, 0, 4)) == 'www.')
{
$domain = mb_substr($domain, 4);
}
if ($domain[0] != '.')
{
$domain = '.'.$domain;
}
}
else
{
$domain = false;
}
return setcookie($name, $value, $expire, $path, $domain, $secure, $httponly);
}
/**
* Performs actions required right before shutdown
* @global CotDB $db
* @global Cache $cache
*/
function cot_shutdown()
{
global $cache, $db;
// Clear import buffer if everything's OK on POST
if ($_SERVER['REQUEST_METHOD'] == 'POST' && !cot_error_found())
{
unset($_SESSION['cot_buffer']);
}
while (ob_get_level() > 0)
{
ob_end_flush();
}
// Need to destroy cache before DB connection is lost
$cache && $cache->db && $cache->db->flush();
$cache = null;
$db = null;
}
/**
* Generates a title string by replacing submasks with assigned values
*
* @param string $area Area maskname or actual mask
* @param array $params An associative array of available parameters
* @param bool $escape Escape HTML special characters
* @return string
*/
function cot_title($mask, $params = array(), $escape = true)
{
global $cfg;
$res = (!empty($cfg[$mask])) ? $cfg[$mask] : $mask;
is_array($params) ? $args = $params : mb_parse_str($params, $args);
if (preg_match_all('#\{(.+?)\}#', $res, $matches, PREG_SET_ORDER))
{
foreach($matches as $m)
{
$var = $m[1];
$val = $escape ? htmlspecialchars($args[$var], ENT_COMPAT, 'UTF-8', false) : $args[$var];
$res = str_replace($m[0], $val, $res);
}
}
return $res;
}
/**
* Generates random string within hexadecimal range
*
* @param int $length Length
* @return string
*/
function cot_unique($length = 16)
{
$string = sha1(mt_rand());
if ($length > 40)
{
for ($i=0; $i < floor($length / 40); $i++)
{
$string .= sha1(mt_rand());
}
}
return(substr($string, 0, $length));
}
/**
* Generates random string within specified charlist
*
* @param int $length String length
* @param string $charlist Allowed characters, defaults to alphanumeric chars
* @return string and numbers ($pass)
*/
function cot_randomstring($length = 8, $charlist = null)
{
if (!is_string($charlist))
$charlist = 'ABCDEFGHIJKLMNOPRSTUVYZabcdefghijklmnoprstuvyz0123456789';
$max = strlen($charlist) - 1;
for ($i=0; $i < $length; $i++)
{
$string .= $charlist[mt_rand(0, $max)];
}
return $string;
}
/*
* =========================== Structure functions ===========================
*/
/**
* Loads comlete category structure into array
* @global CotDB $db
*/
function cot_load_structure()
{
global $db, $db_structure, $cfg, $cot_extrafields, $structure;
if (function_exists('cot_load_structure_custom'))
{
return cot_load_structure_custom();
}
$structure = array();
if (defined('COT_UPGRADE'))
{
$sql = $db->query("SELECT * FROM $db_structure ORDER BY structure_path ASC");
$row['structure_area'] = 'page';
}
else
{
$sql = $db->query("SELECT * FROM $db_structure ORDER BY structure_area ASC, structure_path ASC");
}
/* == Hook: Part 1 ==*/
$extp = cot_getextplugins('structure');
/* ================= */
$path = array(); // code path tree
$tpath = array(); // title path tree
$tpls = array(); // tpl codes tree
foreach ($sql->fetchAll() as $row)
{
$last_dot = mb_strrpos($row['structure_path'], '.');
$row['structure_tpl'] = empty($row['structure_tpl']) ? $row['structure_code'] : $row['structure_tpl'];
if ($last_dot > 0)
{
$path1 = mb_substr($row['structure_path'], 0, $last_dot);
$path[$row['structure_path']] = $path[$path1] . '.' . $row['structure_code'];
$separaror = ($cfg['separator'] == strip_tags($cfg['separator'])) ? ' ' . $cfg['separator'] . ' ' : ' \ ';
$tpath[$row['structure_path']] = $tpath[$path1] . $separaror . $row['structure_title'];
$parent_dot = mb_strrpos($path[$path1], '.');
$parent = ($parent_dot > 0) ? mb_substr($path[$path1], $parent_dot + 1) : $path[$path1];
}
else
{
$path[$row['structure_path']] = $row['structure_code'];
$tpath[$row['structure_path']] = $row['structure_title'];
$parent = $row['structure_code']; // self
}
if ($row['structure_tpl'] == 'same_as_parent')
{
$row['structure_tpl'] = $tpls[$parent];
}
$tpls[$row['structure_code']] = $row['structure_tpl'];
$structure[$row['structure_area']][$row['structure_code']] = array(
'path' => $path[$row['structure_path']],
'tpath' => $tpath[$row['structure_path']],
'rpath' => $row['structure_path'],
'id' => $row['structure_id'],
'tpl' => $row['structure_tpl'],
'title' => $row['structure_title'],
'desc' => $row['structure_desc'],
'icon' => $row['structure_icon'],
'locked' => $row['structure_locked'],
'count' => $row['structure_count']
);
if (is_array($cot_extrafields[$db_structure]))
{
foreach ($cot_extrafields[$db_structure] as $exfld)
{
$structure[$row['structure_area']][$row['structure_code']][$exfld['field_name']] = $row['structure_'.$exfld['field_name']];
}
}
/* == Hook: Part 2 ==*/
foreach ($extp as $pl)
{
include $pl;
}
/* ================= */
}
}
/**
* Gets an array of category children
*
* @param string $area Area code
* @param string $cat Cat code
* @param bool $allsublev All sublevels array
* @param bool $firstcat Add main cat
* @param bool $userrights Check userrights
* @param bool $sqlprep use $db->prep function
* @return array
* @global CotDB $db
*/
function cot_structure_children($area, $cat, $allsublev = true, $firstcat = true, $userrights = true, $sqlprep = true)
{
global $structure, $db;
$mtch = '';
$mtchlen = $mtchlvl = 0;
if ($cat != '')
{
$mtch = $structure[$area][$cat]['path'] . '.';
$mtchlen = mb_strlen($mtch);
$mtchlvl = mb_substr_count($mtch, ".");
}
$catsub = array();
if ($cat != '' && $firstcat && (($userrights && cot_auth($area, $cat, 'R') || !$userrights)))
{
$catsub[] = $cat;
}
foreach ($structure[$area] as $i => $x)
{
if (($cat == '' || mb_substr($x['path'], 0, $mtchlen) == $mtch) && (($userrights && cot_auth($area, $i, 'R') || !$userrights)))
{
//$subcat = mb_substr($x['path'], $mtchlen + 1);
if ($allsublev || (!$allsublev && mb_substr_count($x['path'],".") == $mtchlvl))
{
$i = ($sqlprep) ? $db->prep($i) : $i;
$catsub[] = $i;
}
}
}
return($catsub);
}
/**
* Gets an array of category parents
*
* @param string $area Area code
* @param string $cat Cat code
* @param string $type Type 'full', 'first', 'last'
* @return mixed
*/
function cot_structure_parents($area, $cat, $type = 'full')
{
global $structure;
$pathcodes = explode('.', $structure[$area][$cat]['path']);
if ($type == 'first')
{
return $pathcodes[0];
}
elseif ($type == 'last')
{
return (count($pathcodes) > 1) ? $pathcodes[count($pathcodes) - 2] : null;
}
return $pathcodes;
}
/*
* ================================= Authorization Subsystem ==================================
*/
/**
* Returns specific access permissions
*
* @param string $area Cotonti area
* @param string $option Option to access
* @param string $mask Access mask
* @return mixed
*/
function cot_auth($area, $option, $mask = 'RWA')
{
global $sys, $usr;
$mn['R'] = 1;
$mn['W'] = 2;
$mn['1'] = 4;
$mn['2'] = 8;
$mn['3'] = 16;
$mn['4'] = 32;
$mn['5'] = 64;
$mn['A'] = 128;
$masks = str_split($mask);
$res = array();
foreach ($masks as $k => $ml)
{
if (empty($mn[$ml]))
{
$sys['auth_log'][] = $area.'.'.$option.'.'.$ml.'=0';
$res[] = FALSE;
}
elseif ($option == 'any')
{
$cnt = 0;
if (is_array($usr['auth'][$area]))
{
foreach ($usr['auth'][$area] as $k => $g)
{
$cnt += (($g & $mn[$ml]) == $mn[$ml]);
}
}
$cnt = ($cnt == 0 && $usr['auth']['admin']['a'] && $ml == 'A') ? 1 : $cnt;
$sys['auth_log'][] = ($cnt > 0) ? $area.'.'.$option.'.'.$ml.'=1' : $area.'.'.$option.'.'.$ml.'=0';
$res[] = ($cnt > 0) ? TRUE : FALSE;
}
else
{
$sys['auth_log'][] = (($usr['auth'][$area][$option] & $mn[$ml]) == $mn[$ml]) ? $area.'.'.$option.'.'.$ml.'=1' : $area.'.'.$option.'.'.$ml.'=0';
$res[] = (($usr['auth'][$area][$option] & $mn[$ml]) == $mn[$ml]) ? TRUE : FALSE;
}
}
return (count($res) == 1) ? $res[0] : $res;
}
/**
* Builds Access Control List (ACL) for a specific user
*
* @param int $userid User ID
* @param int $maingrp User main group
* @return array
* @global CotDB $db
*/
function cot_auth_build($userid, $maingrp = 0)
{
global $db, $db_auth, $db_groups_users;
$groups = array();
$authgrid = array();
if ($userid == 0 || $maingrp == 0)
{
$groups[] = 1;
}
else
{
$groups[] = $maingrp;
$sql = $db->query("SELECT gru_groupid FROM $db_groups_users WHERE gru_userid=$userid");
while ($row = $sql->fetch())
{
$groups[] = $row['gru_groupid'];
}
$sql->closeCursor();
}
$sql_groups = implode(',', $groups);
$sql = $db->query("SELECT auth_code, auth_option, auth_rights FROM $db_auth WHERE auth_groupid IN (".$sql_groups.") ORDER BY auth_code ASC, auth_option ASC");
while ($row = $sql->fetch())
{
$authgrid[$row['auth_code']][$row['auth_option']] |= $row['auth_rights'];
}
$sql->closeCursor();
return $authgrid;
}
/**
* Block user if he is not allowed to access the page
*
* @param bool $allowed Authorization result
* @return bool
*/
function cot_block($allowed)
{
if (!$allowed)
{
global $sys, $env;
$env['status'] = '403 Forbidden';
cot_redirect(cot_url('message', 'msg=930&'.$sys['url_redirect'], '', true));
}
return FALSE;
}
/**
* Block guests from viewing the page
*
* @return bool
*/
function cot_blockguests()
{
global $env, $usr, $sys;
if ($usr['id'] < 1)
{
$env['status'] = '403 Forbidden';
cot_redirect(cot_url('message', "msg=930&".$sys['url_redirect'], '', true));
}
return FALSE;
}
/*
* =========================== Output forming functions ===========================
*/
/**
* Renders breadcrumbs string from array of path crumbs
*
* @param array $crumbs Path crumbs as an array: { {$url1, $title1}, {$url2, $title2},..}
* @param bool $home Whether to include link to home page in the root
* @param bool $nolast If TRUE, last crumb will be rendered as plain text rather than hyperlink
* @param bool $plain If TRUE plain titles will be rendered instead of hyperlinks
* @param string $inrc Item template
* @param string $separator Items separator
* @return string
*/
function cot_breadcrumbs($crumbs, $home = true, $nolast = false, $plain = false, $inrc = '', $separator = '')
{
global $cfg, $L;
$tmp = array();
if ($home)
{
$maintitle = (empty($L['breadcrumbmaintitle'])) ? $cfg['maintitle'] : $L['breadcrumbmaintitle'];
array_unshift($crumbs, array($cfg['mainurl'], $maintitle));
}
$cnt = count($crumbs);
for ($i = 0; $i < $cnt; $i++)
{
$elem = '';
$params = is_array($crumbs[$i]) ? array(
'url' => (!empty($crumbs[$i][0])) ? $crumbs[$i][0] : '#',
'title' => htmlspecialchars($crumbs[$i][1], ENT_COMPAT, 'UTF-8', false)
) : $params = array('title' => $crumbs[$i]);
if ($plain || ($nolast && $i === $cnt - 1) || !isset($params['url']))
{
$crumb = cot_rc('breadcrumbs_plain', $params);
if ($crumb == 'breadcrumbs_plain')
{
$crumb = cot_rc('string_catpath', $params);
}
}
else
{
$crumb = cot_rc('breadcrumbs_link', $params);
if ($crumb == 'breadcrumbs_link')
{
$crumb = cot_rc('link_catpath', $params);
}
}
if ($i == 0)
{
$elem = cot_rc('breadcrumbs_first', array('crumb' => $crumb));
}
if ($i == $cnt - 1)
{
$elem = cot_rc('breadcrumbs_last', array('crumb' => $crumb));
}
if (!$elem || $elem == 'breadcrumbs_first' || $elem == 'breadcrumbs_last')
{
$elem = cot_rc('breadcrumbs_crumb', array('crumb' => $crumb));
}
if ($elem == 'breadcrumbs_crumb')
{
$elem = $crumb;
}
if(!empty($inrc))
{
$elem = cot_rc($inrc, array('elem' => $elem));
}
$tmp[] = $elem;
}
$separator = (!empty($separator) || !empty($inrc)) ? $separator : cot_rc('breadcrumbs_separator');
$separator = ($separator == 'breadcrumbs_separator') ? $cfg['separator'] : $separator;
$separator = (!empty($inrc) && (mb_strlen($separator) > 2 || empty($separator))) ? $separator : ' '.$separator.' ';
$breadcrumbs = implode($separator, $tmp);
$container = cot_rc('breadcrumbs_container', array('crumbs' => $breadcrumbs));
return ($container == 'breadcrumbs_container') ? $breadcrumbs : $container;
}
/**
* Calculates age out of date of birth.
*
* @param int $birthdate Timestamp or a string according to format 'YYYY-MM-DD'
* @return int Age in years or NULL on failure
*/
function cot_build_age($birthdate)
{
if (is_string($birthdate))
{
$birthdate = strtotime($birthdate);
}
if (is_null($birthdate) || $birthdate === false || $birthdate === -1)
{
return null;
}
list($birth_y, $birth_m, $birth_d) = explode('-', cot_date('Y-m-d', $birthdate));
list($now_y, $now_m, $now_d) = explode('-', cot_date('Y-m-d'));
$age = $now_y - $birth_y - 1;
if ($birth_m < $now_m || ($birth_m == $now_m && $birth_d <= $now_d))
{
$age += 1;
}
return ($age < 0) ? $age + 136 : $age;
}
/**
* Builds category path for cot_breadcrumbs()
*
* @param string $area Area code
* @param string $cat Category code
* @return array
* @see cot_breadcrumbs()
*/
function cot_structure_buildpath($area, $cat)
{
global $structure;
$tmp = array();
$pathcodes = explode('.', $structure[$area][$cat]['path']);
foreach ($pathcodes as $x)
{
if ($x != 'system')
{
$tmp[] = array(cot_url($area, 'c='.$x), $structure[$area][$x]['title']);
}
}
return $tmp;
}
/**
* Returns country text button
*
* @param string $flag Country code
* @return string
*/
function cot_build_country($flag)
{
global $cot_countries;
if (!$cot_countries) include_once cot_langfile('countries', 'core');
$flag = (empty($flag)) ? '00' : $flag;
return cot_rc_link(cot_url('users', 'f=country_'.$flag), $cot_countries[$flag], array(
'title' => $cot_countries[$flag]
));
}
/**
* Returns user email link
*
* @param string $email E-mail address
* @param bool $hide Hide email option
* @return string
*/
function cot_build_email($email, $hide = false)
{
global $L;
if ($hide)
{
return $L['Hidden'];
}
elseif (!empty($email) && cot_check_email($email))
{
$link = cot_rc('link_email', array('email' => $email));
return function_exists('cot_obfuscate') ? cot_obfuscate($link) : $link;
}
}
/**
* Generate human-readable filesize.
*
* @param float $bytes
* Filesize in bytes
* @param int $decimals
* Number of decimals to show.
* @param mixed $round
* Round up to this number of decimals.
* Set false to disable or null to inherit from $decimals.
* @param bool $binary Use binary instead of decimal calculation.
* Set TRUE for the IEC binary standard where 1 Kibibyte = 1024 bytes
* Set FALSE for the SI/IEEE decimal standard where 1 Kilobyte = 1000 bytes
* @param string $smallestunit
* Key of the smallest unit to show. Any number smaller than this will return 'Less than 1 ...'.
* Effectively its a way to cut off $units at a certain key.
* @return string
*/
function cot_build_filesize($bytes, $decimals = 0, $round = null, $binary = false, $smallestunit = null)
{
global $Ls;
$units = $binary ? array(
'1099511627776' => $Ls['Tebibytes'],
'1073741824' => $Ls['Gibibytes'],
'1048576' => $Ls['Mebibytes'],
'1024' => $Ls['Kibibytes'],
'1' => $Ls['Bytes']
) : array(
'1000000000000' => $Ls['Terabytes'],
'1000000000' => $Ls['Gigabytes'],
'1000000' => $Ls['Megabytes'],
'1000' => $Ls['Kilobytes'],
'1' => $Ls['Bytes']
);
return cot_build_friendlynumber($bytes, $units, 1, $decimals, $round, $smallestunit);
}
/**
* Returns country flag button
*
* @param string $flag Country code
* @return string
*/
function cot_build_flag($flag)
{
global $cot_countries;
if (!$cot_countries) include_once cot_langfile('countries', 'core');
$flag = (empty($flag)) ? '00' : $flag;
return cot_rc_link(cot_url('users', 'f=country_'.$flag),
cot_rc('icon_flag', array('code' => $flag, 'alt' => $flag)),
array('title' => $cot_countries[$flag])
);
}
/**
* Generic function for generating a human-readable number with localized units.
*
* @param float $number
* Input number to convert, based on the unit with size (key) 1.
* @param array $units
* Array of units as $relativesize => $unit.
* Example: array('3600' => 'hours', '60' => 'minutes', '1' => 'seconds').
* Where 'seconds' is the base unit, since it has a value of 1. Hours has a value of
* 3600, since one hour contains 3600 seconds. Values can be given as strings or integers.
* @param int $levels
* Number of levels to return.
* "3 hours 45 minutes" = 2 levels.
* @param int $decimals
* Number of decimals to show in last level.
* "2 minutes 20.5 seconds" = 2 levels, 1 decimals.
* @param mixed $round
* Number of decimals to round the last level up to, can also be negative, see round().
* Set false to disable or null to inherit from $decimals.
* @param string $smallestunit
* Key of the smallest unit to show. Any number smaller than this will return 'Less than 1 ...'.
* Effectively its a way to cut off $units at a certain key.
* @return string
*/
function cot_build_friendlynumber($number, $units, $levels = 1, $decimals = 0, $round = null, $smallestunit = null)
{
global $L;
if (!is_array($units)) return '';
$pieces = array();
// First sort from big to small
ksort($units, SORT_NUMERIC);
$units = array_reverse($units, true);
// Trim units after $smallestunit
if (array_key_exists($smallestunit, $units))
{
$offset = array_search($smallestunit, array_keys($units));
$units = array_slice($units, 0, $offset+1, true);
}
if ($number == 0)
{
// Return smallest possible unit
$units = array_reverse(array_values($units));
return cot_declension(0, $units[0]);
}
foreach ($units as $size => $expr)
{
$size = floatval($size);
if ($number >= $size)
{
$levels--;
$num = $number / $size;
$number -= floor($num) * $size;
if ($number > 0 && $levels > 0)
{
// There's more to come, so no decimals yet.
$pieces[] = cot_declension(floor($num), $expr);
}
else
{
// Last item gets decimals and rounding.
if($decimals > 0)
{
$pieces[] = cot_build_number($num, $decimals, $round). ' ' .
cot_declension($num, $expr, true, true);
}
else
{
$pieces[] = floor($num). ' ' .
cot_declension(floor($num), $expr, true, true);
}
break;
}
if ($levels == 0)
{
break;
}
}
}
if (count($pieces) == 0)
{
// Smaller than smallest possible unit
$expr = array_reverse(array_values($units));
return $L['LessThan'] . ' ' . cot_declension(1, $expr[0]);
}
return implode(' ', $pieces);
}
/**
* Returns IP Search link
*
* @param string $ip IP mask
* @return string
*/
function cot_build_ipsearch($ip)
{
global $sys;
if (!empty($ip))
{
if(cot_plugin_active('ipsearch'))
{
return cot_rc_link(cot_url('admin', 'm=other&p=ipsearch&a=search&id='.$ip.'&x='.$sys['xk']), $ip);
}
else
{
return $ip;
}
}
return '';
}
/**
* Wrapper for number_format() using locale number formatting and optional rounding.
*
* @param float $number
* Number to format
* @param int $decimals
* Number of decimals to return
* @param mixed $round
* Round up to this number of decimals.
* Set false to disable or null to inherit from $decimals.
* @return string
*/
function cot_build_number($number, $decimals = 0, $round = null)
{
global $Ln;
if ($round === null) $round = $decimals;
if ($round !== false)
{
$number = round($number, $round);
}
return number_format($number, $decimals, $Ln['decimal_point'], $Ln['thousands_separator']);
}
/**
* Odd/even class choser for row
*
* @param int $number Row number
* @return string
*/
function cot_build_oddeven($number)
{
return ($number % 2 == 0 ) ? 'even' : 'odd';
}
/**
* Returns stars image for user level
*
* @param int $level User level
* @return unknown
*/
function cot_build_stars($level)
{
if ($level > 0 and $level < 100)
{
$stars = floor($level / 10) + 1;
return cot_rc('icon_stars', array('val' => $stars));
}
else
{
return '';
}
}
/**
* Returns readable time difference or 'Just now'.
*
* @param int $time Timestamp
* @param int $recently Seconds during which to show 'Just now'
* @return string
*/
function cot_build_timeago($time, $recently = 60)
{
global $L, $sys;
if ($sys['now'] - $time < $recently)
{
return $L['JustNow'];
}
return cot_build_timegap($time) . ' ' . $L['Ago'];
}
/**
* Returns time gap between two timestamps
*
* @param int $t1
* Timestamp 1 (oldest, smallest value).
* @param int $t2
* Timestamp 2 (latest, largest value).
* @param int $levels
* Number of concatenated units to return.
* @param int $decimals
* Number of decimals to show on last level.
* @param mixed $round
* Round up last level to this number of decimals.
* Set false to disable or null to inherit from $decimals.
* @param string $smallestunit
* Key of the smallest unit to show. Any number smaller than this will return 'Less than 1 ...'.
* Effectively its a way to cut off $units at a certain key.
* @return string
*/
function cot_build_timegap($t1, $t2 = null, $levels = 1, $decimals = 0, $round = null, $smallestunit = null)
{
global $Ls, $sys;
$units = array(
'31536000' => $Ls['Years'],
'2592000' => $Ls['Months'],
'604800' => $Ls['Weeks'],
'86400' => $Ls['Days'],
'3600' => $Ls['Hours'],
'60' => $Ls['Minutes'],
'1' => $Ls['Seconds'],
'0.001' => $Ls['Milliseconds']
);
if ($t2 === null)
{
$t2 = $sys['now'];
}
$gap = $t2 - $t1;
return cot_build_friendlynumber($gap, $units, $levels, $decimals, $round, $smallestunit);
}
/**
* Returns timezone offset formatted according to ISO 8601
*
* @param float $offset Timezone offset in seconds or hours. Set NULL for unknown timezone.
* @param bool $withgmt Include 'GMT' in the returned string.
* @param bool $short Use format without minutes, like GMT+1
* @return string Textual timezone like GMT+1:00
*/
function cot_build_timezone($offset, $withgmt = true, $short = false)
{
$gmt = $withgmt ? 'GMT' : '';
if (is_null($offset))
{
return $short ? "$gmt-00" : "$gmt-00:00";
}
if ($offset == 0)
{
return $short ? "$gmt+00" : "$gmt+00:00";
}
$format = $short ? 'H' : 'H:i';
$abs = abs($offset);
$seconds = $abs < 100 ? $abs * 3600 : $abs; // detect hours or seconds
$time = gmdate($format, $seconds);
return ($offset > 0) ? "$gmt+$time" : "$gmt-$time";
}
/**
* Returns link for URL
*
* @param string $text URL
* @param int $maxlen Max. allowed length
* @return unknown
*/
function cot_build_url($text, $maxlen=64)
{
if (!empty($text))
{
if (mb_strpos($text, 'http://') !== 0)
{
$text='http://'. $text;
}
$text = htmlspecialchars($text);
$text = cot_rc_link($text, cot_cutstring($text, $maxlen));
}
return $text;
}
/**
* Returns link to user profile
*
* @param int $id User ID
* @param string $user User name
* @param mixed $extra_attrs Extra link tag attributes as a string or associative array,
* e.g. array('class' => 'usergrp_admin')
* @return string
*/
function cot_build_user($id, $user, $extra_attrs = '')
{
if (function_exists('cot_build_user_custom'))
{
return cot_build_user_custom($id, $user, $extra_attrs);
}
if (!$id)
{
return empty($user) ? '' : $user;
}
else
{
return empty($user) ? '?' : cot_rc_link(cot_url('users', 'm=details&id='.$id.'&u='.$user), $user, $extra_attrs);
}
}
/**
* Displays User full name
*
* Format of full name is language specific and defined by $R['users_full_name']
* resource string.
*
* @param array|int $user User Data or User ID
* @return string
*/
function cot_user_full_name($user)
{
if (empty($user)) return '';
if (is_int($user) && $user > 0 || ctype_digit($user))
{
require_once cot_incfile('users', 'module');
$user = cot_user_data($user);
}
if (empty($user)) return '';
$user_fname = $user['user_firstname'] ? $user['user_firstname'] : $user['user_first_name'];
$user_mname = $user['user_middlename'] ? $user['user_middlename'] : $user['user_middle_name'];
$user_lname = $user['user_lastname'] ? $user['user_lastname'] : $user['user_last_name'];
$full_name = trim(cot_rc('users_full_name',
array(
'firstname' => $user_fname,
'middlename' => $user_mname,
'lastname' => $user_lname,
'name' => $user['user_name']
)
));
return $full_name ? $full_name : $user['user_name'];
}
/**
* Returns group link (button)
*
* @param int $grpid Group ID
* @param bool $title Return group title instead of name
* @return string
*/
function cot_build_group($grpid, $title = false)
{
if (empty($grpid))
return '';
global $cot_groups, $L;
$type = ($title) ? 'title' : 'name';
if ($cot_groups[$grpid]['hidden'])
{
if (cot_auth('users', 'a', 'A'))
{
return cot_rc_link(cot_url('users', 'gm=' . $grpid), $cot_groups[$grpid][$type] . ' (' . $L['Hidden'] . ')');
}
else
{
return $L['Hidden'];
}
}
else
{
if ($type == 'title' && isset($L['users_grp_' . $grpid . '_title']))
{
return cot_rc_link(cot_url('users', 'gm=' . $grpid), $L['users_grp_' . $grpid . '_title']);
}
return cot_rc_link(cot_url('users', 'gm=' . $grpid), $cot_groups[$grpid][$type]);
}
}
/**
* Returns user group icon
*
* @param string $src Image file path
* @return string
*/
function cot_build_groupicon($src)
{
return ($src) ? cot_rc("icon_group", array('src' => $src)) : '';
}
/**
* Returns all user tags for XTemplate
*
* @param mixed $user_data User Info Array
* @param string $tag_prefix Prefix for tags
* @param string $emptyname Name text if user is not exist
* @param bool $allgroups Build info about all user groups
* @param bool $cacheitem Cache tags
* @return array
* @global CotDB $db
*/
function cot_generate_usertags($user_data, $tag_prefix = '', $emptyname='', $allgroups = false, $cacheitem = true)
{
global $db, $cot_extrafields, $cot_groups, $cfg, $L, $user_cache, $db_users;
static $extp_first = null, $extp_main = null;
$return_array = array();
if (is_null($extp_first))
{
$extp_first = cot_getextplugins('usertags.first');
$extp_main = cot_getextplugins('usertags.main');
}
/* === Hook === */
foreach ($extp_first as $pl)
{
include $pl;
}
/* ===== */
$user_id = is_array($user_data) ? (int)$user_data['user_id'] : (is_numeric($user_data) ? (int)$user_data : 0);
if (isset($user_cache[$user_id]))
{
$temp_array = $user_cache[$user_id];
}
else
{
if (!is_array($user_data) && $user_id > 0)
{
$sql = $db->query("SELECT * FROM $db_users WHERE user_id = $user_id LIMIT 1");
$user_data = $sql->fetch();
}
else if (!is_array($user_data))
{
$user_data = array();
}
if (is_array($user_data) && $user_data['user_id'] > 0 && !empty($user_data['user_name']))
{
$user_data['user_birthdate'] = cot_date2stamp($user_data['user_birthdate']);
$user_data['user_text'] = cot_parse($user_data['user_text'], $cfg['users']['usertextimg']);
$temp_array = array(
'ID' => $user_data['user_id'],
'NAME' => cot_build_user($user_data['user_id'], htmlspecialchars($user_data['user_name'])),
'NICKNAME' => htmlspecialchars($user_data['user_name']),
'DETAILSLINK' => cot_url('users', 'm=details&id=' . $user_data['user_id'].'&u='.htmlspecialchars($user_data['user_name'])),
'DETAILSLINKSHORT' => cot_url('users', 'm=details&id=' . $user_data['user_id']),
'FULL_NAME' => htmlspecialchars(cot_user_full_name($user_data)),
'TITLE' => $cot_groups[$user_data['user_maingrp']]['title'],
'MAINGRP' => cot_build_group($user_data['user_maingrp']),
'MAINGRPID' => $user_data['user_maingrp'],
'MAINGRPNAME' => $cot_groups[$user_data['user_maingrp']]['name'],
'MAINGRPTITLE' => cot_build_group($user_data['user_maingrp'], true),
'MAINGRPSTARS' => cot_build_stars($cot_groups[$user_data['user_maingrp']]['level']),
'MAINGRPICON' => cot_build_groupicon($cot_groups[$user_data['user_maingrp']]['icon']),
'COUNTRY' => cot_build_country($user_data['user_country']),
'COUNTRYFLAG' => cot_build_flag($user_data['user_country']),
'TEXT' => $user_data['user_text'],
'EMAIL' => cot_build_email($user_data['user_email'], $user_data['user_hideemail']),
'THEME' => $user_data['user_theme'],
'SCHEME' => $user_data['user_scheme'],
'LANG' => $user_data['user_lang'],
'GENDER' => ($user_data['user_gender'] == '' || $user_data['user_gender'] == 'U') ? '' : $L['Gender_' . $user_data['user_gender']],
'BIRTHDATE' => (is_null($user_data['user_birthdate'])) ? '' : cot_date('date_full', $user_data['user_birthdate']),
'BIRTHDATE_STAMP' => (is_null($user_data['user_birthdate'])) ? '' : $user_data['user_birthdate'],
'AGE' => (is_null($user_data['user_birthdate'])) ? '' : cot_build_age($user_data['user_birthdate']),
'TIMEZONE' => cot_build_timezone(cot_timezone_offset($user_data['user_timezone'], false, false)) . ' ' .str_replace('_', ' ', $user_data['user_timezone']),
'REGDATE' => cot_date('datetime_medium', $user_data['user_regdate']),
'REGDATE_STAMP' => $user_data['user_regdate'],
'LASTLOG' => cot_date('datetime_medium', $user_data['user_lastlog']),
'LASTLOG_STAMP' => $user_data['user_lastlog'],
'LOGCOUNT' => $user_data['user_logcount'],
'POSTCOUNT' => $user_data['user_postcount'],
'LASTIP' => $user_data['user_lastip']
);
if ($allgroups)
{
$temp_array['GROUPS'] = cot_build_groupsms($user_data['user_id'], FALSE, $user_data['user_maingrp']);
}
// Extra fields
if (!empty(cot::$extrafields[cot::$db->users])) {
foreach (cot::$extrafields[cot::$db->users] as $exfld) {
$exfld_title = cot_extrafield_title($exfld, 'user_');
$temp_array[strtoupper($exfld['field_name'])] = cot_build_extrafields_data('user', $exfld, $user_data['user_' . $exfld['field_name']]);
$temp_array[strtoupper($exfld['field_name']) . '_TITLE'] = $exfld_title;
$temp_array[strtoupper($exfld['field_name']) . '_VALUE'] = $user_data['user_' . $exfld['field_name']];
}
}
}
else
{
$temp_array = array(
'ID' => 0,
'NAME' => (!empty($emptyname)) ? $emptyname : $L['Deleted'],
'NICKNAME' => (!empty($emptyname)) ? $emptyname : $L['Deleted'],
'FULL_NAME' => (!empty($emptyname)) ? $emptyname : $L['Deleted'],
'MAINGRP' => cot_build_group(1),
'MAINGRPID' => 1,
'MAINGRPSTARS' => '',
'MAINGRPICON' => cot_build_groupicon($cot_groups[1]['icon']),
'COUNTRY' => cot_build_country(''),
'COUNTRYFLAG' => cot_build_flag(''),
'TEXT' => '',
'EMAIL' => '',
'GENDER' => '',
'BIRTHDATE' => '',
'BIRTHDATE_STAMP' => '',
'AGE' => '',
'REGDATE' => '',
'REGDATE_STAMP' => '',
'POSTCOUNT' => '',
'LASTIP' => ''
);
}
/* === Hook === */
foreach ($extp_main as $pl)
{
include $pl;
}
/* ===== */
if(is_array($user_data) && isset($user_data['user_id'])) {
$cacheitem && $user_cache[$user_data['user_id']] = $temp_array;
}
}
foreach ($temp_array as $key => $val)
{
$return_array[$tag_prefix . $key] = $val;
}
return $return_array;
}
/**
* Resize an image
*
* @param string $source Original image path.
* @param string $target Target path for saving, or 'return' to return the resized image data directly.
* @param int $target_width Maximum width of resized image.
* @param int $target_height Maximum height of resized image.
* @param string $crop Crop the image to a certain ratio. Set to 'fit' to calculate ratio from target width and height.
* @param string $fillcolor Color fill a transparent gif or png.
* @param int $quality JPEG quality
* @param bool $sharpen Sharpen JPEG image after resize.
* @return mixed Boolean or image resource, depending on $target
*/
function cot_imageresize($source, $target='return', $target_width=99999, $target_height=99999, $crop='', $fillcolor='', $quality=90, $sharpen=true)
{
if (!file_exists($source)) return;
$source_size = getimagesize($source);
if(!$source_size) return;
$mimetype = $source_size['mime'];
if (substr($mimetype, 0, 6) != 'image/') return;
$source_width = $source_size[0];
$source_height = $source_size[1];
if($target_width > $source_width) $target_width = $source_width; $noscaling_x = true;
if($target_height > $source_height) $target_height = $source_height; $noscaling_y = true;
$fillcolor = preg_replace('/[^0-9a-fA-F]/', '', (string)$fillcolor);
if (!$fillcolor && $noscaling_x && $noscaling_y)
{
$data = file_get_contents($source);
if($target == 'return') return $data;
}
$offsetX = 0;
$offsetY = 0;
if($crop)
{
$crop = ($crop == 'fit') ? array($target_width, $target_height) : explode(':', (string)$crop);
if(count($crop) == 2)
{
$source_ratio = $source_width / $source_height;
$target_ratio = (float)$crop[0] / (float)$crop[1];
if ($source_ratio < $target_ratio)
{
$temp = $source_height;
$source_height = $source_width / $target_ratio;
$offsetY = ($temp - $source_height) / 2;
}
if ($source_ratio > $target_ratio)
{
$temp = $source_width;
$source_width = $source_height * $target_ratio;
$offsetX = ($temp - $source_width) / 2;
}
}
}
$width_ratio = $target_width / $source_width;
$height_ratio = $target_height / $source_height;
if ($width_ratio * $source_height < $target_height)
{
$target_height = ceil($width_ratio * $source_height);
}
else
{
$target_width = ceil($height_ratio * $source_width);
}
// Avoid loading images there's not enough memory for
if (!cot_img_check_memory($source, (int)ceil($target_width * $target_height * 4 / 1048576)))
{
return ($return) ? null : false;
}
$canvas = imagecreatetruecolor($target_width, $target_height);
switch($mimetype)
{
case 'image/gif':
$fn_create = 'imagecreatefromgif';
$fn_output = 'imagegif';
$mimetype = 'image/gif';
//$quality = round(10 - ($quality / 10));
$sharpen = false;
break;
case 'image/x-png':
case 'image/png':
$fn_create = 'imagecreatefrompng';
$fn_output = 'imagepng';
$quality = round(10 - ($quality / 10));
$sharpen = false;
break;
default:
$fn_create = 'imagecreatefromjpeg';
$fn_output = 'imagejpeg';
$sharpen = ($target_width < 75 || $target_height < 75) ? false : $sharpen;
break;
}
$source_data = $fn_create($source);
if (in_array($mimetype, array('image/gif', 'image/png')))
{
if (!$fillcolor)
{
imagealphablending($canvas, false);
imagesavealpha($canvas, true);
}
elseif(strlen($fillcolor) == 6 || strlen($fillcolor) == 3)
{
$background = (strlen($fillcolor) == 6) ?
imagecolorallocate($canvas, hexdec($fillcolor[0].$fillcolor[1]), hexdec($fillcolor[2].$fillcolor[3]), hexdec($fillcolor[4].$fillcolor[5])):
imagecolorallocate($canvas, hexdec($fillcolor[0].$fillcolor[0]), hexdec($fillcolor[1].$fillcolor[1]), hexdec($fillcolor[2].$fillcolor[2]));
imagefill($canvas, 0, 0, $background);
}
}
imagecopyresampled($canvas, $source_data, 0, 0, $offsetX, $offsetY, $target_width, $target_height, $source_width, $source_height);
imagedestroy($source_data);
$canvas = ($sharpen) ? cot_imagesharpen($canvas, $source_width, $target_width) : $canvas;
if($target == 'return')
{
ob_start();
$fn_output($canvas, null, $quality);
$data = ob_get_contents();
ob_end_clean();
imagedestroy($canvas);
return $data;
}
else
{
$result = $fn_output($canvas, $target, $quality);
imagedestroy($canvas);
return $result;
}
}
// Fix for non-bundled GD versions
// Made by Chao Xu(Mgccl) 2/28/07
// www.webdevlogs.com
// V 1.0
if (!function_exists('imageconvolution'))
{
function imageconvolution($src, $filter, $filter_div, $offset)
{
if ($src == NULL)
{
return 0;
}
$sx = imagesx($src);
$sy = imagesy($src);
$srcback = imagecreatetruecolor($sx, $sy);
imagecopy($srcback, $src, 0, 0, 0, 0, $sx, $sy);
if ($srcback == NULL)
{
return 0;
}
// Fix here
// $pxl array was the problem so simply set it with very low values
$pxl = array(1, 1);
// this little fix worked for me as the undefined array threw out errors
for ($y = 0; $y < $sy; ++$y)
{
for ($x = 0; $x < $sx; ++$x)
{
$new_r = $new_g = $new_b = 0;
$alpha = imagecolorat($srcback, $pxl[0], $pxl[1]);
$new_a = $alpha >> 24;
for ($j = 0; $j < 3; ++$j)
{
$yv = min(max($y - 1 + $j, 0), $sy - 1);
for ($i = 0; $i < 3; ++$i)
{
$pxl = array(min(max($x - 1 + $i, 0), $sx - 1), $yv);
$rgb = imagecolorat($srcback, $pxl[0], $pxl[1]);
$new_r += ( ($rgb >> 16) & 0xFF) * $filter[$j][$i];
$new_g += ( ($rgb >> 8) & 0xFF) * $filter[$j][$i];
$new_b += ( $rgb & 0xFF) * $filter[$j][$i];
}
}
$new_r = ($new_r / $filter_div) + $offset;
$new_g = ($new_g / $filter_div) + $offset;
$new_b = ($new_b / $filter_div) + $offset;
$new_r = ($new_r > 255) ? 255 : (($new_r < 0) ? 0 : $new_r);
$new_g = ($new_g > 255) ? 255 : (($new_g < 0) ? 0 : $new_g);
$new_b = ($new_b > 255) ? 255 : (($new_b < 0) ? 0 : $new_b);
$new_pxl = imagecolorallocatealpha($src, (int) $new_r, (int) $new_g, (int) $new_b, $new_a);
if ($new_pxl == -1)
{
$new_pxl = imagecolorclosestalpha($src, (int) $new_r, (int) $new_g, (int) $new_b, $new_a);
}
if (($y >= 0) && ($y < $sy))
{
imagesetpixel($src, $x, $y, $new_pxl);
}
}
}
imagedestroy($srcback);
return 1;
}
}
/**
* Sharpen an image after resize
*
* @param image resource $imgdata Image resource from an image creation function
* @param int $source_width Width of image before resize
* @param int $target_width Width of image to sharpen (after resize)
* @return image resource
*/
function cot_imagesharpen($imgdata, $source_width, $target_width)
{
$s = $target_width * (750.0 / $source_width);
$a = 52;
$b = -0.27810650887573124;
$c = .00047337278106508946;
$sharpness = max(round($a+$b*$s+$c*$s*$s), 0);
$sharpenmatrix = array(
array(-1, -2, -1),
array(-2, $sharpness + 12, -2),
array(-1, -2, -1)
);
imageconvolution($imgdata, $sharpenmatrix, $sharpness, 0);
return $imgdata;
}
/**
* Checks if PHP can have enough memory to process an image
*
* @param string $file_path Path to an image
* @param string $extra_size Extra size to adjust to the estimate (in MB)
* @return boolean TRUE if enough memory is available, FALSE otherwise
*/
function cot_img_check_memory($file_path, $extra_size = 0)
{
// Getting memory occupied by the script
$usedMem = memory_get_usage(true);
// In megabytes
$usedMem = round($usedMem / 1048576);
$haveMem = ini_get('memory_limit');
if ($haveMem == '-1')
{
// no limit set, so we try any way
return true;
}
preg_match('/(\d+)(\w+)/', $haveMem, $mtch);
// Getting available memory in MBytes
if (!empty($mtch[2]))
{
if ($mtch[2] == 'M')
{
$haveMem = $mtch[1];
}
elseif ($mtch[2] == 'G')
{
$haveMem = $mtch[1] * 1024;
}
elseif ($mtch[2] == 'K')
{
$haveMem = $mtch[1] / 1024;
}
}
// Gettimg memory size required to process the image
$source_size = getimagesize($file_path);
if (!$source_size)
{
// Wrong image
return false;
}
$width_orig = $source_size[0];
$height_orig = $source_size[1];
$depth_orig = ($source_size['bits'] > 8) ? ($source_size['bits'] / 8) : 1;
$channels_orig = $source_size['channels'] > 0 ? $source_size['channels'] : 4;
// In MBytes too
$needMem = $width_orig * $height_orig * $depth_orig * $channels_orig / 1048576;
// Adding some offset memory for other image processing and script variables,
// otherwise the script fails
$needMem = intval($needMem + $usedMem + 15 + $extra_size);
// Trying to allocate memory required
if ($haveMem < $needMem)
{
if (!ini_set('memory_limit', $needMem.'M'))
{
// Could not allocate memory
return false;
}
}
else
{
return true;
}
// Making sure we could allocate enough memory
$haveMem = ini_get('memory_limit');
preg_match('/(\d+)(\w+)/', $haveMem, $mtch);
// Getting available memory in MBytes
if (!empty($mtch[2]))
{
if ($mtch[2] == 'M')
{
$haveMem = $mtch[1];
}
elseif ($mtch[2] == 'G')
{
$haveMem = $mtch[1] * 1024;
}
elseif ($mtch[2] == 'K')
{
$haveMem = $mtch[1] / 1024;
}
}
if ($haveMem < $needMem)
{
// No, we couldn't allocate enough memory
return false;
}
return true;
}
/**
* Returns themes info data for all available themes or a specified one
*
* @param string $theme_name Name of theme to get info.
* Returns list for all themes if no name specified.
* @return mixed Array of Theme info data or Theme info data or FALSE
*/
function cot_themes_info($theme_name = null)
{
require_once cot_incfile('extensions');
$themes_data = array();
$themelist = array();
$handle = opendir(cot::$cfg['themes_dir']);
while ($f = readdir($handle))
{
if (mb_strpos($f, '.') === FALSE && is_dir(cot::$cfg['themes_dir'] . "/$f") && $f != "admin")
{
$themelist[] = $f;
}
}
closedir($handle);
if (!is_null($theme_name))
{
if (!in_array($theme_name, $themelist))
{
return false;
}
else {
$themelist = array($theme_name);
}
}
else
{
sort($themelist);
}
foreach ($themelist as $name)
{
if ($theme_name && $theme_name != $name) continue;
$themeinfo = array();
$themeinfo_file = cot::$cfg['themes_dir'] . "/$name/$name.php";
if (file_exists($themeinfo_file) && $info = cot_infoget($themeinfo_file, 'COT_THEME'))
{
$themeinfo = $info;
if (!$themeinfo['Title']) $themeinfo['Title'] = ($info['Name'] ? $info['Name'] : $name);
$schemes_list = array();
if (!empty($info['Schemes']))
{
$schemes = preg_split('/\s*,\s*/', $info['Schemes']);
sort($schemes);
foreach ($schemes as $scheme)
{
list($sc_name, $sc_title) = explode(':', $scheme);
$schemes_list[$sc_name] = $sc_title;
}
}
$themeinfo['Schemes'] = $schemes_list;
}
if (sizeof($themeinfo) > 0) $themes_data[$name] = $themeinfo;
}
if (is_null($theme_name))
{
return $themes_data;
}
else
{
return $themes_data[$theme_name];
}
}
/**
* Returns Theme/Scheme selection dropdown
*
* @param string $selected_theme Seleced theme
* @param string $selected_scheme Seleced color scheme
* @param string $title Dropdown name
* @return string
*/
function cot_selectbox_theme($selected_theme, $selected_scheme, $input_name)
{
$themes_info = cot_themes_info();
$values = array();
$titles = array();
foreach ($themes_info as $name => $info)
{
if ($info)
{
$version = $info['Version'];
$title = $info['Title'] . ($version ? " v$version" : '');
if (sizeof($info['Schemes']))
{
foreach ($info['Schemes'] as $sc_name => $sc_title)
{
$values[] = $name . ':' . $sc_name;
$titles[] = count($info['Schemes']) > 1 ? $title . ' (' . $sc_title . ')' : $title;
}
}
else
{
$values[] = "$name:default";
$titles[] = $title;
}
}
}
return cot_selectbox("$selected_theme:$selected_scheme", $input_name, $values, $titles, false);
}
/*
* ======================== Error & Message + Logs API ========================
*/
/**
* If condition is true, triggers an error with given message and source
*
* @param bool $condition Boolean condition
* @param string $message Error message or message key
* @param string $src Error source field name
*/
function cot_check($condition, $message, $src = 'default')
{
if ($condition)
{
cot_error($message, $src);
}
}
/**
* Checks if there are messages to display
*
* @param string $src If non-emtpy, check messages in this specific source only
* @param string $class If non-empty, check messages of this specific class only
* @return bool
*/
function cot_check_messages($src = '', $class = '')
{
global $error_string, $sys;
if (empty($src) && empty($class))
{
return (is_array($_SESSION['cot_messages'][$sys['site_id']]) && count($_SESSION['cot_messages'][$sys['site_id']]) > 0)
|| !empty($error_string);
}
if (!is_array($_SESSION['cot_messages'][$sys['site_id']]))
{
return false;
}
if (empty($src))
{
foreach ($_SESSION['cot_messages'][$sys['site_id']] as $src => $grp)
{
foreach ($grp as $msg)
{
if ($msg['class'] == $class)
{
return true;
}
}
}
}
elseif (empty($class))
{
return count($_SESSION['cot_messages'][$sys['site_id']][$src]) > 0;
}
else
{
foreach ($_SESSION['cot_messages'][$sys['site_id']][$src] as $msg)
{
if ($msg['class'] == $class)
{
return true;
}
}
}
return false;
}
/**
* Clears error and other messages after they have bin displayed
* @param string $src If non-emtpy, clear messages in this specific source only
* @param string $class If non-empty, clear messages of this specific class only
* @see cot_error()
* @see cot_message()
*/
function cot_clear_messages($src = '', $class = '')
{
global $error_string, $sys;
if (empty($src) && empty($class))
{
unset($_SESSION['cot_messages'][$sys['site_id']]);
unset($error_string);
}
if (!is_array($_SESSION['cot_messages'][$sys['site_id']]) || (!empty($src) && !is_array($_SESSION['cot_messages'][$sys['site_id']][$src])))
{
return;
}
if (empty($src))
{
foreach ($_SESSION['cot_messages'][$sys['site_id']] as $src => $grp)
{
$new_grp = array();
foreach ($grp as $msg)
{
if ($msg['class'] != $class)
{
$new_grp[] = $msg;
}
}
if (count($new_grp) > 0)
{
$_SESSION['cot_messages'][$sys['site_id']][$src] = $new_grp;
}
else
{
unset($_SESSION['cot_messages'][$sys['site_id']][$src]);
}
}
}
elseif (empty($class))
{
unset($_SESSION['cot_messages'][$sys['site_id']][$src]);
}
else
{
$new_grp = array();
foreach ($_SESSION['cot_messages'][$sys['site_id']][$src] as $msg)
{
if ($msg['class'] != $class)
{
$new_grp[] = $msg;
}
}
if (count($new_grp) > 0)
{
$_SESSION['cot_messages'][$sys['site_id']][$src] = $new_grp;
}
else
{
unset($_SESSION['cot_messages'][$sys['site_id']][$src]);
}
}
}
/**
* Terminates script execution and performs redirect
*
* @param bool $cond Really die?
* @param bool $notfound Page not found?
* @return bool
*/
function cot_die($cond = true, $notfound = false)
{
if ($cond)
{
$msg = $notfound ? '404' : '950';
cot_die_message($msg, true);
}
return FALSE;
}
/**
* Terminates script execution with fatal error
*
* @param string $text Reason
* @param string $title Message title
*/
function cot_diefatal($text='Reason is unknown.', $title='Fatal error')
{
global $cfg;
if ($cfg['display_errors'])
{
$message_body = '<p><em>'.@date('Y-m-d H:i').'</em></p>';
$message_body .= '<p>'.$text.'</p>';
ob_clean();
debug_print_backtrace();
$backtrace = ob_get_contents();
ob_clean();
$message_body .= '<pre style="overflow:auto">'.$backtrace.'</pre>';
$message_body .= '<hr /><a href="'.$cfg['mainurl'].'">'.$cfg['maintitle'].'</a>';
cot_die_message(500, true, $title, $message_body);
}
else
{
$backtrace = debug_backtrace();
if (isset($backtrace[1]))
{
$text .= ' in file ' . $backtrace[1]['file'] . ' at line ' . $backtrace[1]['line'] . ' function ' . $backtrace[1]['function'] . '(' . implode(', ', $backtrace[1]['args']) . ')';
}
error_log("$title: $text");
cot_die_message(503, true);
}
}
/**
* Terminates script execution and displays message page
*
* @param integer $code Message code
* @param boolean $header Render page header
* @param string $message_title Custom page title
* @param string $message_body Custom message body
* @param string $redirect Optional URL to redirect after 3 seconds
*/
function cot_die_message($code, $header = TRUE, $message_title = '', $message_body = '', $redirect = '')
{
// Globals and requirements
global $error_string, $out, $L, $R;
$LL = is_array($L) ? $L : array();
require_once cot_langfile('message', 'core');
$L = array_merge($L, $LL);
if (cot_error_found() && $_SERVER['REQUEST_METHOD'] == 'POST')
{
// Save the POST data
cot_import_buffer_save();
if (!empty($error_string))
{
// Message should not be lost
cot_error($error_string);
}
}
// Determine response header
static $msg_status = array(
100 => '403 Forbidden',
101 => '200 OK',
102 => '200 OK',
105 => '200 OK',
106 => '200 OK',
109 => '200 OK',
117 => '403 Forbidden',
118 => '200 OK',
151 => '403 Forbidden',
152 => '403 Forbidden',
153 => '403 Forbidden',
157 => '403 Forbidden',
300 => '200 OK',
400 => '400 Bad Request',
401 => '401 Authorization Required',
403 => '403 Forbidden',
404 => '404 Not Found',
500 => '500 Internal Server Error',
503 => '503 Service Unavailable',
602 => '403 Forbidden',
603 => '403 Forbidden',
900 => '503 Service Unavailable',
904 => '403 Forbidden',
907 => '404 Not Found',
911 => '404 Not Found',
915 => '200 OK',
916 => '200 OK',
920 => '200 OK',
930 => '403 Forbidden',
940 => '403 Forbidden',
950 => '403 Forbidden',
951 => '503 Service Unavailable'
);
if (!$out['meta_contenttype'])
{
$out['meta_contenttype'] = 'text/html';
}
cot_sendheaders($out['meta_contenttype'], $msg_status[$code]);
// Determine message title and body
$title = empty($message_title) ? $L['msg' . $code . '_title'] : $message_title;
$body = empty($message_body) ? $L['msg' . $code . '_body'] : $message_body;
// Render the message page
$tpl_type = defined('COT_ADMIN') ? 'core' : 'module';
$tpl_path = '';
$stylesheet = file_exists(cot_schemefile()) ? '<link rel="stylesheet" type="text/css" href="'.cot_schemefile().'"/>' : '';