/system/functions.php
PHP | 5754 lines | 4227 code | 438 blank | 1089 comment | 709 complexity | 010ee4a0819b072e95cb57b8fa37606b MD5 | raw file
Possible License(s): LGPL-2.1, MPL-2.0-no-copyleft-exception
Large files files are truncated, but you can click here to view the full file
- <?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;
- // Todo fill some variables with defoult values
- 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
- // On the first step of installer it is not initialized yet
- if ( !(empty($db) && isset($env['location']) && $env['location'] == 'install' )) {
- $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');
- }
- // Fill some variables with default values
- // May be isset() is not needed
- if(!isset(self::$out['head'])) self::$out['head'] = '';
- if(!isset(self::$out['subtitle'])) self::$out['subtitle'] = '';
- if(!isset(self::$env['ext'])) self::$env['ext'] = null;
- }
- }
- /*
- * =========================== 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
- *
- * @todo PSR-4 autoloader
- * @param string $class Class name
- */
- function cot_autoload($class)
- {
- global $cfg, $env;
- $type = isset(cot::$env['type']) ? cot::$env['type'] : null;
- if ($type == 'module') {
- $paths[] = "{$cfg['modules_dir']}/{$env['ext']}/classes/$class.php";
- } elseif ($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 (!empty($cot_import_filters[$filter]) && 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('<', '<', $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 = "'.$filter.'" ?');
- 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;
- }
- }
- return null;
- }
- /**
- * 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.
- *
- * @see cot_import_list() for parameters
- *
- * @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')
- {
- if (function_exists('cot_import_date_custom'))
- {
- return cot_import_date_custom($name, $usertimezone, $returnarray, $source);
- }
- $result = NULL;
- /* === Hook === */
- foreach (cot_getextplugins('import.date') as $pl)
- {
- include $pl;
- }
- /* ===== */
- if($result !== NULL) return $result;
- //$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 -= cot::$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);
- }
- $ret = true;
- 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;
- $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;
- }
- /**
- * Allocate memory
- *
- * @param int $needMemory Memory to allocate in bytes
- * @return bool TRUE if enough memory is available, FALSE otherwise
- */
- function cot_memory_allocate($needMemory)
- {
- $needMemory = (int)$needMemory;
- if(empty($needMemory)) return false;
- // Getting memory occupied by the script (in bytes)
- $usedMem = memory_get_usage(true);
- $haveMem = ini_get('memory_limit');
- // no limit set, so we try any way
- if ($haveMem == '-1') return true;
- preg_match('/(\d+)(\w+)/', $haveMem, $mtch);
- if (!empty($mtch[2])) {
- $mtch[2] = mb_strtoupper($mtch[2]);
- if ($mtch[2] == 'G') {
- $haveMem = $mtch[1] * 1073741824;
- } elseif ($mtch[2] == 'M') {
- $haveMem = $mtch[1] * 1048576;
- } elseif ($mtch[2] == 'K') {
- $haveMem = $mtch[1] * 1024;
- }
- }
- $needMem = intval($needMemory + $usedMem);
- if ($haveMem < $needMem) {
- // Could not allocate memory
- if (!ini_set('memory_limit', $needMem)) return false;
- } else {
- return true;
- }
- // Making sure we could allocate enough memory
- $haveMem = ini_get('memory_limit');
- preg_match('/(\d+)(\w+)/', $haveMem, $mtch);
- if (!empty($mtch[2])) {
- $mtch[2] = mb_strtoupper($mtch[2]);
- if ($mtch[2] == 'G') {
- $haveMem = $mtch[1] * 1073741824;
- } elseif ($mtch[2] == 'M') {
- $haveMem = $mtch[1] * 1048576;
- } elseif ($mtch[2] == 'K') {
- $haveMem = $mtch[1] * 1024;
- }
- }
- // No, we couldn't allocate enough memory
- if ($haveMem < $needMem) return false;
- 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]);
- }
- /**
- * 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(cot::$cfg[$mask])) ? cot::$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];
- if(isset($args[$var])) {
- $val = $escape ? htmlspecialchars($args[$var], ENT_COMPAT, 'UTF-8', false) : $args[$var];
- } else {
- $val = '';
- }
- $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;
- $string = '';
- 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])) {
- cot::$sys['auth_log'][] = $area.'.'.$option.'.'.$ml.'=0';
- $res[] = FALSE;
- } elseif ($option == 'any') {
- $cnt = 0;
- if(is_array(cot::$usr['auth'])) {
- if (isset(cot::$usr['auth'][$area]) && is_array(cot::$usr['auth'][$area])) {
- foreach (cot::$usr['auth'][$area] as $k => $g) {
- $cnt += (($g & $mn[$ml]) == $mn[$ml]);
- }
- }
- $cnt = ($cnt == 0 && cot::$usr['auth']['admin']['a'] && $ml == 'A') ? 1 : $cnt;
- }
- cot::$sys['auth_log'][] = ($cnt > 0) ? $area.'.'.$option.'.'.$ml.'=1' : $area.'.'.$option.'.'.$ml.'=0';
- $res[] = ($cnt > 0) ? TRUE : FALSE;
- } else {
- $tmpOption = 0;
- if (isset(cot::$usr['auth'][$area][$option])) $tmpOption = cot::$usr['auth'][$area][$option];
- cot::$sys['auth_log'][] = (($tmpOption & $mn[$ml]) == $mn[$ml]) ? $area.'.'.$option.'.'.$ml.'=1' : $area.'.'.$option.'.'.$ml.'=0';
- $res[] = (($tmpOption & $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']] = 0;
- $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;
- }
- /**
- * Authorize user
- *
- * @param int $id User ID
- * @param bool|null $remember remember user authorization
- * @return bool
- *
- * @todo May be we should optionally fill user data like in system/common.php on line 336
- * It can be useful if we will not redirect user after login, may be we should redirect anyway
- */
- function cot_user_authorize($id, $remember = null)
- {
- if(is_null($remember) && cot::$cfg['forcerememberme'])
- {
- $remember = true;
- }
- if(is_array($id) && isset($id['user_id']) && isset($id['user_password']))
- {
- $user = $id;
- $id = $user['user_id'];
- }
- else
- {
- $id = (int)$id;
- if($id <= 0) return false;
- $res = cot::$db->query("SELECT user_id, user_password, user_maingrp, user_banexpire, user_sid, ".
- "user_sidtime, user_passsalt, user_passfunc FROM ".cot::$db->users." WHERE user_id = ? LIMIT 1", $id);
- $user = $res->fetch();
- if($user <= 0) return false;
- }
- if ($user['user_maingrp'] == COT_GROUP_BANNED)
- {
- if (cot::$sys['now'] > $user['user_banexpire'] && $user['user_banexpire'] > 0)
- {
- cot::$db->update(cot::$db->users, array('user_maingrp' => COT_GROUP_MEMBERS), "user_id={$user['user_id']}");
- $row['user_maingrp'] = COT_GROUP_MEMBERS;
- }
- else
- {
- return false;
- }
- }
- $token = cot_unique(16);
- $sid = hash_hmac('sha256', $user['user_password'] . $user['user_sidtime'], cot::$cfg['secret_key']);
- $update_sid = '';
- if (empty($user['user_sid']) || $user['user_sid'] != $sid
- || $user['user_sidtime'] + cot::$cfg['cookielifetime'] < cot::$sys['now'])
- {
- // Generate new session identifier
- $sid = hash_hmac('sha256', $user['user_password'] . cot::$sys['now'], cot::$cfg['secret_key']);
- $update_sid = ", user_sid = " . cot::$db->quote($sid) . ", user_sidtime = " . cot::$sys['now'];
- }
- cot::$db->query("UPDATE ".cot::$db->users." SET user_lastip='".cot::$usr['ip']."', user_lastlog = ".cot::$sys['now'].
- ", user_logcount = user_logcount + 1, user_token = ".cot::$db->quote($token).
- " $update_sid WHERE user_id={$user['user_id']}");
- // Hash the sid once more so it can't be faked even if you know user_sid
- $sid = hash_hmac('sha1', $sid, cot::$cfg['secret_key']);
- $u = base64_encode($user['user_id'].':'.$sid);
- /* === Hook === */
- foreach (cot_getextplugins('users.authorize') as $pl)
- {
- include $pl;
- }
- /* ===== */
- if($remember)
- {
- cot_setcookie(cot::$sys['site_id'], $u, time()+ cot::$cfg['cookielifetime'], cot::$cfg['cookiepath'],
- cot::$cfg['cookiedomain'], cot::$sys['secure'], true);
- unset($_SESSION[cot::$sys['site_id']]);
- }
- else
- {
- $_SESSION[cot::$sys['site_id']] = $u;
- }
- /* === Hook === */
- foreach (cot_getextplugins('users.authorize.done') as $pl)
- {
- include $pl;
- }
- /* ===== */
- return true;
- }
- /*
- * =========================== 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 = true, $plain = false, $inrc = '', $separator = '')
- {
- global $cfg, $L;
- $tmp = array();
- if ($home)
- {
- $maintitle = (empty($L['breadcrumbmaintitle'])) ? $cfg['maintitle'] : $L['breadcrumbmaintitle'];
- array_unshift($crumbs, array(cot_url('index'), $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();
- if (isset(cot::$structure[$area][$cat]['path'])) {
- $pathcodes = explode('.', cot::$structure[$area][$cat]['path']);
- foreach ($pathcodes as $x) {
- if ($x != 'system') {
- $tmp[] = array(cot_url($area, 'c=' . $x), cot::$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;
- $country = isset($cot_countries[$flag]) ? $cot_countries[$flag] : cot::$R['code_option_empty'];
- return cot_rc_link(cot_url('users', 'f=country_'.$flag), $country, array(
- 'title' => $country
- ));
- }
- /**
- * 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;
- $sc_sign = ' '; // leading space for keys index cast as string
- $units = $binary ? array(
- $sc_sign . 1099511627776 => $Ls['Tebibytes'],
- $sc_sign . 1073741824 => $Ls['Gibibytes'],
- $sc_sign . 1048576 => $Ls['Mebibytes'],
- $sc_sign . 1024 => $Ls['Kibibytes'],
- $sc_sign . 1 => $Ls['Bytes'],
- ) : array(
- $sc_sign . 1000000000000 => $Ls['Terabytes'],
- $sc_sign . 1000000000 => $Ls['Gigabytes'],
- $sc_sign . 1000000 => $Ls['Megabytes'],
- $sc_sign . 1000 => $Ls['Kilobytes'],
- $sc_sign . 1 => $Ls['Bytes']
- );
- if ($smallestunit) $smallestunit = $sc_sign . $smallestunit;
- $sizes = array_keys($units);
- if ($bytes < $sizes[sizeof($units)-2]) $decimals = 0; // as byte can not be fractional
- 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;
- $country = isset($cot_countries[$flag]) ? $cot_countries[$flag] : cot::$R['code_option_empty'];
- return cot_rc_link(cot_url('users', 'f=country_'.$flag),
- cot_rc('icon_flag', array('code' => $flag, 'alt' => $flag)),
- array('title' => $country)
- );
- }
- /**
- * 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 …
Large files files are truncated, but you can click here to view the full file