@@ -77,9 +77,81 @@ if (isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on') { | |||
// Load language file | |||
hesk_getLanguage(); | |||
// Set timezone | |||
hesk_setTimezone(); | |||
/*** FUNCTIONS ***/ | |||
function hesk_getClientIP() { | |||
global $hesk_settings; | |||
// Already set? Just return it | |||
if (isset($hesk_settings['client_IP'])) { | |||
return $hesk_settings['client_IP']; | |||
} | |||
// Empty client IP, for example when used in CLI (piping, cron jobs, ...) | |||
$hesk_settings['client_IP'] = ''; | |||
// Server (environment) variables to loop through | |||
// the first valid one found will be returned as client IP | |||
// Uncomment those used on your server | |||
$server_client_IP_variables = array( | |||
// 'HTTP_CF_CONNECTING_IP', // CloudFlare | |||
// 'HTTP_CLIENT_IP', | |||
// 'HTTP_X_FORWARDED_FOR', | |||
// 'HTTP_X_FORWARDED', | |||
// 'HTTP_FORWARDED_FOR', | |||
// 'HTTP_FORWARDED', | |||
'REMOTE_ADDR', | |||
); | |||
// The first valid environment variable is our client IP | |||
foreach ($server_client_IP_variables as $server_client_IP_variable) { | |||
// Must be set | |||
if (!isset($_SERVER[$server_client_IP_variable])) { | |||
continue; | |||
} | |||
// Must be a valid IP | |||
if (!hesk_isValidIP($_SERVER[$server_client_IP_variable])) { | |||
continue; | |||
} | |||
// Bingo! | |||
$hesk_settings['client_IP'] = $_SERVER[$server_client_IP_variable]; | |||
break; | |||
} | |||
return $hesk_settings['client_IP']; | |||
} // END hesk_getClientIP() | |||
function hesk_isValidIP($ip) { | |||
// Use filter_var for PHP 5.2.0 | |||
if (function_exists('filter_var') && filter_var($ip, FILTER_VALIDATE_IP) !== false) { | |||
return true; | |||
} | |||
// Use regex for PHP < 5.2.0 | |||
// -> IPv4 | |||
if (preg_match('/^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$/', $ip)) { | |||
return true; | |||
} | |||
// -> IPv6 | |||
if (preg_match('/^[0-9A-Fa-f\:\.]$/', $ip)) { | |||
return true; | |||
} | |||
// Not a valid IP | |||
return false; | |||
} // END hesk_isValidIP() | |||
function hesk_setcookie($name, $value, $expire=0, $path=""){ | |||
if (HESK_SSL) { | |||
setcookie($name, $value, $expire, $path, "", true, true); | |||
@@ -415,6 +487,9 @@ function hesk_getCustomerEmail($can_remember = 0, $field = '') | |||
} | |||
} | |||
// Remove unwanted side-effects | |||
$my_email = hesk_emailCleanup($my_email); | |||
$hesk_settings['e_param'] = '&e=' . rawurlencode($my_email); | |||
$hesk_settings['e_query'] = '&e=' . rawurlencode($my_email); | |||
$hesk_settings['e_email'] = $my_email; | |||
@@ -423,6 +498,10 @@ function hesk_getCustomerEmail($can_remember = 0, $field = '') | |||
} // END hesk_getCustomerEmail() | |||
function hesk_emailCleanup($my_email) { | |||
return preg_replace("/(\\\)'/", "'", $my_email); | |||
} // END hesk_emailCleanup() | |||
function hesk_formatBytes($size, $translate_unit = 1, $precision = 2) | |||
{ | |||
@@ -670,7 +749,7 @@ function hesk_cleanBfAttempts() | |||
} | |||
/* Delete expired logs from the database */ | |||
$res = hesk_dbQuery("DELETE FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "logins` WHERE `ip`='" . hesk_dbEscape($_SERVER['REMOTE_ADDR']) . "'"); | |||
hesk_dbQuery("DELETE FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."logins` WHERE `ip`='".hesk_dbEscape(hesk_getClientIP())."'"); | |||
define('HESK_BF_CLEAN', 1); | |||
@@ -683,7 +762,7 @@ function hesk_limitBfAttempts($showError = 1) | |||
global $hesk_settings, $hesklang; | |||
// Check if this IP is banned permanently | |||
if (hesk_isBannedIP($_SERVER['REMOTE_ADDR'])) { | |||
if (hesk_isBannedIP(hesk_getClientIP())) { | |||
hesk_error($hesklang['baned_ip'], 0); | |||
} | |||
@@ -695,7 +774,7 @@ function hesk_limitBfAttempts($showError = 1) | |||
/* Define this constant to avoid duplicate checks */ | |||
define('HESK_BF_LIMIT', 1); | |||
$ip = $_SERVER['REMOTE_ADDR']; | |||
$ip = hesk_getClientIP(); | |||
/* Get number of failed attempts from the database */ | |||
$res = hesk_dbQuery("SELECT `number`, (CASE WHEN `last_attempt` IS NOT NULL AND DATE_ADD(`last_attempt`, INTERVAL " . intval($hesk_settings['attempt_banmin']) . " MINUTE ) > NOW() THEN 1 ELSE 0 END) AS `banned` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "logins` WHERE `ip`='" . hesk_dbEscape($ip) . "' LIMIT 1"); | |||
@@ -1206,6 +1285,58 @@ function hesk_returnLanguage() | |||
return true; | |||
} // END hesk_returnLanguage() | |||
function hesk_setTimezone() { | |||
global $hesk_settings; | |||
// Get Hesk time difference from UTC in seconds | |||
$seconds = date('Z') + 3600*$hesk_settings['diff_hours'] + 60*$hesk_settings['diff_minutes']; | |||
// Daylight saving? | |||
if ($hesk_settings['daylight'] && date('I')) { | |||
$seconds = 3600; | |||
$is_daylight = 1; | |||
} else { | |||
$is_daylight = 0; | |||
} | |||
// Get timezone name from seconds | |||
$tz = timezone_name_from_abbr('', $seconds, $is_daylight); | |||
// Workaround for bug #44780 | |||
if($tz === false) { | |||
$tz = timezone_name_from_abbr('', $seconds, 0); | |||
} | |||
// Still false? Disregards minutes | |||
if($tz === false) { | |||
$seconds = date('Z') + 3600*$hesk_settings['diff_hours']; | |||
$tz = timezone_name_from_abbr('', $seconds, 0); | |||
} | |||
// Set timezone | |||
date_default_timezone_set($tz); | |||
return true; | |||
} // END hesk_setTimezone() | |||
function hesk_timeToHHMM($time, $time_format="seconds", $signed=true) { | |||
if ($time < 0) { | |||
$time = abs($time); | |||
$sign = "-"; | |||
} else { | |||
$sign = ""; | |||
} | |||
if ($time_format == 'minutes') { | |||
$time *= 60; | |||
} | |||
return ($signed ? $sign : '') . gmdate('H:i', $time); | |||
} // END hesk_timeToHHMM() | |||
function hesk_date($dt = '', $from_database = false, $is_str = true, $return_str = true) | |||
{ | |||
@@ -1217,25 +1348,6 @@ function hesk_date($dt = '', $from_database = false, $is_str = true, $return_str | |||
$dt = strtotime($dt); | |||
} | |||
// Adjust MySQL time if different from PHP time | |||
if ($from_database) { | |||
if (!defined('MYSQL_TIME_DIFF')) { | |||
define('MYSQL_TIME_DIFF', time() - hesk_dbTime()); | |||
} | |||
if (MYSQL_TIME_DIFF != 0) { | |||
$dt += MYSQL_TIME_DIFF; | |||
} | |||
} | |||
// Add HESK set time difference | |||
$dt += 3600 * $hesk_settings['diff_hours'] + 60 * $hesk_settings['diff_minutes']; | |||
// Daylight savings? | |||
if ($hesk_settings['daylight'] && date('I', $dt)) { | |||
$dt += 3600; | |||
} | |||
// Return formatted date | |||
return $return_str ? date($hesk_settings['timeformat'], $dt) : $dt; | |||
@@ -1728,7 +1840,7 @@ function hesk_check_maintenance($dodie = true) | |||
$hesk_settings['maintenance_mode'] == 0 && | |||
$hesk_settings['question_ans'] == 'PB6YM' && | |||
$hesk_settings['site_title'] == 'My Web site' && | |||
$hesk_settings['site_title'] == 'Website' && | |||
$hesk_settings['site_url'] == 'http://www.example.com' && | |||
$hesk_settings['webmaster_mail'] == 'support@example.com' && | |||
$hesk_settings['noreply_mail'] == 'support@example.com' && | |||
@@ -59,9 +59,6 @@ function hesk_kbTopArticles($how_many, $index = 1) | |||
// Show title in bold | |||
$font_weight = 'b'; | |||
// Print a line for spacing | |||
echo '<hr />'; | |||
} | |||
?> | |||
@@ -108,6 +105,8 @@ function hesk_kbTopArticles($how_many, $index = 1) | |||
$hesk_settings['kb_top_articles_printed'] = array(); | |||
while ($article = hesk_dbFetchAssoc($res)) { | |||
$hesk_settings['kb_spacing']--; | |||
$hesk_settings['kb_top_articles_printed'][] = $article['id']; | |||
$icon = 'fa fa-file'; | |||
@@ -217,6 +216,7 @@ function hesk_kbLatestArticles($how_many, $index = 1) | |||
/* We have some results, print them out */ | |||
$colspan = $hesk_settings['kb_date'] ? '' : 'colspan="2"'; | |||
while ($article = hesk_dbFetchAssoc($res)) { | |||
$hesk_settings['kb_spacing']--; | |||
$icon = 'fa fa-file'; | |||
$style = ''; | |||
@@ -266,7 +266,6 @@ function hesk_email2ticket($results, $pop3 = 0, $set_category = 1, $set_priority | |||
// Not a reply, but a new ticket. Add it to the database | |||
$tmpvar['category'] = $set_category; | |||
$tmpvar['priority'] = $set_priority < 0 ? hesk_getCategoryPriority($tmpvar['category']) : $set_priority; | |||
$_SERVER['REMOTE_ADDR'] = $hesklang['unknown']; | |||
// Auto assign tickets if aplicable | |||
$tmpvar['owner'] = 0; | |||
@@ -101,7 +101,7 @@ function hesk_newTicket($ticket, $isVerified = true) | |||
NOW(), | |||
NOW(), | |||
" . (isset($ticket['articles']) ? "'{$ticket['articles']}'" : 'NULL') . ", | |||
'" . hesk_dbEscape($_SERVER['REMOTE_ADDR']) . "', | |||
'" . hesk_dbEscape(hesk_getClientIP()) . "', | |||
'" . hesk_dbEscape($language) . "', | |||
'" . (isset($ticket['openedby']) ? intval($ticket['openedby']) : 0) . "', | |||
'" . intval($ticket['owner']) . "', | |||
@@ -721,7 +721,7 @@ function print_add_ticket() | |||
<!-- START KNOWLEDGEBASE SUGGEST --> | |||
<?php | |||
if ($hesk_settings['kb_enable'] && $hesk_settings['kb_recommendanswers']) { | |||
if (has_public_kb() && $hesk_settings['kb_recommendanswers']) { | |||
?> | |||
<div id="kb_suggestions" style="display:none"> | |||
<br/> <br/> | |||
@@ -1116,7 +1116,7 @@ function print_add_ticket() | |||
<b><?php echo $hesklang['we_have']; ?>:</b> | |||
<ul> | |||
<li><?php echo hesk_htmlspecialchars($_SERVER['REMOTE_ADDR']) . ' ' . $hesklang['recorded_ip']; ?></li> | |||
<li><?php echo hesk_htmlspecialchars(hesk_getClientIP()) . ' ' . $hesklang['recorded_ip']; ?></li> | |||
<li><?php echo $hesklang['recorded_time']; ?></li> | |||
</ul> | |||
</div> | |||
@@ -1206,16 +1206,26 @@ function print_start() | |||
{ | |||
global $hesk_settings, $hesklang; | |||
if ($hesk_settings['kb_enable']) | |||
{ | |||
require(HESK_PATH . 'inc/knowledgebase_functions.inc.php'); | |||
} | |||
// Connect to database | |||
hesk_load_database_functions(); | |||
hesk_dbConnect(); | |||
define('PAGE_TITLE', 'CUSTOMER_HOME'); | |||
// This will be used to determine how much space to print after KB | |||
$hesk_settings['kb_spacing'] = 4; | |||
// Include KB functionality only if we have any public articles | |||
has_public_kb(); | |||
if ($hesk_settings['kb_enable']) | |||
{ | |||
require(HESK_PATH . 'inc/knowledgebase_functions.inc.php'); | |||
} | |||
else | |||
{ | |||
$hesk_settings['kb_spacing'] += 2; | |||
} | |||
/* Print header */ | |||
require_once(HESK_PATH . 'inc/header.inc.php'); | |||
@@ -1418,7 +1428,7 @@ require(HESK_PATH . 'inc/email_functions.inc.php'); | |||
/* Get ticket(s) from database */ | |||
hesk_dbConnect(); | |||
$email = hesk_validateEmail(hesk_POST('email'), 'ERR', 0) or hesk_process_messages($hesklang['enter_valid_email'], 'ticket.php?remind=1'); | |||
$email = hesk_emailCleanup(hesk_validateEmail(hesk_POST('email'), 'ERR', 0)) or hesk_process_messages($hesklang['enter_valid_email'], 'ticket.php?remind=1'); | |||
if (isset($_POST['open_only'])) { | |||
$hesk_settings['open_only'] = $_POST['open_only'] == 1 ? 1 : 0; | |||
@@ -1437,9 +1447,9 @@ $res = hesk_dbQuery('SELECT * FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) | |||
$num = hesk_dbNumRows($res); | |||
if ($num < 1) { | |||
if ($hesk_settings['open_only']) { | |||
hesk_process_messages($hesklang['noopen'], 'ticket.php?remind=1&e=' . $email); | |||
hesk_process_messages($hesklang['noopen'],'ticket.php?remind=1&e='.rawurlencode($email)); | |||
} else { | |||
hesk_process_messages($hesklang['tid_not_found'], 'ticket.php?remind=1&e=' . $email); | |||
hesk_process_messages($hesklang['tid_not_found'],'ticket.php?remind=1&e='.rawurlencode($email)); | |||
} | |||
} | |||
@@ -1505,8 +1515,7 @@ require_once(HESK_PATH . 'inc/header.inc.php'); | |||
} // End forgot_tid() | |||
function processEmail($msg, $name, $num, $tid_list) | |||
{ | |||
function processEmail($msg, $name, $num, $tid_list) { | |||
global $hesk_settings; | |||
$msg = str_replace('%%NAME%%', $name, $msg); | |||
@@ -1517,4 +1526,48 @@ require_once(HESK_PATH . 'inc/header.inc.php'); | |||
return $msg; | |||
} | |||
?> | |||
function has_public_kb($use_cache=1) { | |||
global $hesk_settings; | |||
// Return if KB is disabled | |||
if ( ! $hesk_settings['kb_enable']) { | |||
return 0; | |||
} | |||
// Do we have a cached version available | |||
$cache_dir = $hesk_settings['cache_dir'].'/'; | |||
$cache_file = $cache_dir . 'kb.cache.php'; | |||
if ($use_cache && file_exists($cache_file)) { | |||
require($cache_file); | |||
return $hesk_settings['kb_enable']; | |||
} | |||
// Make sure we have database connection | |||
hesk_load_database_functions(); | |||
hesk_dbConnect(); | |||
// Do we have any public articles at all? | |||
$res = hesk_dbQuery("SELECT `t1`.`id` FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."kb_articles` AS `t1` | |||
LEFT JOIN `".hesk_dbEscape($hesk_settings['db_pfix'])."kb_categories` AS `t2` ON `t1`.`catid` = `t2`.`id` | |||
WHERE `t1`.`type`='0' AND `t2`.`type`='0' LIMIT 1"); | |||
// If no public articles, disable the KB functionality | |||
if (hesk_dbNumRows($res) < 1) { | |||
$hesk_settings['kb_enable'] = 0; | |||
} | |||
// Try to cache results | |||
if ($use_cache && (is_dir($cache_dir) || (@mkdir($cache_dir, 0777) && is_writable($cache_dir)))) { | |||
// Is there an index.htm file? | |||
if ( ! file_exists($cache_dir.'index.htm')) { | |||
@file_put_contents($cache_dir.'index.htm', ''); | |||
} | |||
// Write data | |||
@file_put_contents($cache_file, '<?php if (!defined(\'IN_SCRIPT\')) {die();} $hesk_settings[\'kb_enable\']=' . $hesk_settings['kb_enable'] . ';' ); | |||
} | |||
return $hesk_settings['kb_enable']; | |||
} // End has_public_kb() |
@@ -36,7 +36,7 @@ | |||
if (!defined('IN_SCRIPT')) {die('Invalid attempt');} | |||
// We will be installing this HESK version: | |||
define('HESK_NEW_VERSION','2.7.2'); | |||
define('HESK_NEW_VERSION','2.7.3'); | |||
define('MODS_FOR_HESK_NEW_VERSION','3.0.5'); | |||
define('REQUIRE_PHP_VERSION','5.3.0'); | |||
define('REQUIRE_MYSQL_VERSION','5.0.7'); | |||
@@ -20,10 +20,7 @@ require(HESK_PATH . 'inc/common.inc.php'); | |||
require(HESK_PATH . 'inc/knowledgebase_functions.inc.php'); | |||
// Load Knowledgebase-related functions | |||
hesk_load_database_functions(); | |||
/* Connect to database */ | |||
// Connect to database | |||
hesk_dbConnect(); | |||
// Are we in maintenance mode? | |||
@@ -31,11 +28,24 @@ hesk_check_maintenance(); | |||
define('PAGE_TITLE', 'CUSTOMER_KB'); | |||
/* Is Knowledgebase enabled? */ | |||
// Is Knowledgebase enabled? | |||
if (!$hesk_settings['kb_enable']) { | |||
hesk_error($hesklang['kbdis']); | |||
} | |||
// Do we have any public articles at all? | |||
$res = hesk_dbQuery("SELECT `t1`.`id` FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."kb_articles` AS `t1` | |||
LEFT JOIN `".hesk_dbEscape($hesk_settings['db_pfix'])."kb_categories` AS `t2` ON `t1`.`catid` = `t2`.`id` | |||
WHERE `t1`.`type`='0' AND `t2`.`type`='0' LIMIT 1"); | |||
// If yes, load KB functions; if not, disable and hide the KB | |||
if (hesk_dbNumRows($res) < 1) { | |||
hesk_error($hesklang['noa']); | |||
} | |||
// Load KB functions | |||
require(HESK_PATH . 'inc/knowledgebase_functions.inc.php'); | |||
/* Rating? */ | |||
if (isset($_GET['rating'])) { | |||
// Detect and block robots | |||
@@ -125,7 +125,7 @@ if (count($hesk_error_buffer) != 0) { | |||
} | |||
// Check if this IP is temporarily locked out | |||
$res = hesk_dbQuery("SELECT `number` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "logins` WHERE `ip`='" . hesk_dbEscape($_SERVER['REMOTE_ADDR']) . "' AND `last_attempt` IS NOT NULL AND DATE_ADD(`last_attempt`, INTERVAL " . intval($hesk_settings['attempt_banmin']) . " MINUTE ) > NOW() LIMIT 1"); | |||
$res = hesk_dbQuery("SELECT `number` FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."logins` WHERE `ip`='".hesk_dbEscape(hesk_getClientIP())."' AND `last_attempt` IS NOT NULL AND DATE_ADD(`last_attempt`, INTERVAL ".intval($hesk_settings['attempt_banmin'])." MINUTE ) > NOW() LIMIT 1"); | |||
if (hesk_dbNumRows($res) == 1) { | |||
if (hesk_dbResult($res) >= $hesk_settings['attempt_limit']) { | |||
unset($_SESSION); | |||
@@ -157,7 +157,7 @@ if (hesk_dbNumRows($res) > 0) { | |||
$sequential_customer_replies = $tmp['staffid'] ? 0 : $sequential_customer_replies + 1; | |||
} | |||
if ($sequential_customer_replies > 10) { | |||
hesk_dbQuery("INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . "logins` (`ip`, `number`) VALUES ('" . hesk_dbEscape($_SERVER['REMOTE_ADDR']) . "', " . intval($hesk_settings['attempt_limit'] + 1) . ")"); | |||
hesk_dbQuery("INSERT INTO `".hesk_dbEscape($hesk_settings['db_pfix'])."logins` (`ip`, `number`) VALUES ('".hesk_dbEscape(hesk_getClientIP())."', ".intval($hesk_settings['attempt_limit'] + 1).")"); | |||
hesk_error(sprintf($hesklang['yhbr'], $hesk_settings['attempt_banmin']), 0); | |||
} | |||
} | |||
@@ -87,7 +87,7 @@ if ($hesk_settings['secimg_use'] && !isset($_SESSION['img_verified'])) { | |||
require(HESK_PATH . 'inc/recaptcha/recaptchalib.php'); | |||
$resp = recaptcha_check_answer($hesk_settings['recaptcha_private_key'], | |||
$_SERVER['REMOTE_ADDR'], | |||
hesk_getClientIP(), | |||
hesk_POST('recaptcha_challenge_field', ''), | |||
hesk_POST('recaptcha_response_field', '') | |||
); | |||
@@ -268,9 +268,9 @@ foreach ($hesk_settings['custom_fields'] as $k=>$v) { | |||
$_SESSION["c_$k"] = ''; | |||
if (preg_match("/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/", $tmpvar[$k])) { | |||
$date = strtotime($tmpvar[$k] . ' t00:00:00'); | |||
$dmin = strlen($v['value']['dmin']) ? strtotime($v['value']['dmin'] . ' t00:00:00') : false; | |||
$dmax = strlen($v['value']['dmax']) ? strtotime($v['value']['dmax'] . ' t00:00:00') : false; | |||
$date = strtotime($tmpvar[$k] . ' t00:00:00 UTC'); | |||
$dmin = strlen($v['value']['dmin']) ? strtotime($v['value']['dmin'] . ' t00:00:00 UTC') : false; | |||
$dmax = strlen($v['value']['dmax']) ? strtotime($v['value']['dmax'] . ' t00:00:00 UTC') : false; | |||
$_SESSION["c_$k"] = $tmpvar[$k]; | |||
@@ -317,7 +317,7 @@ foreach ($hesk_settings['custom_fields'] as $k=>$v) { | |||
} | |||
// Check bans | |||
if ($email_available && ! isset($hesk_error_buffer['email']) && hesk_isBannedEmail($tmpvar['email']) || hesk_isBannedIP($_SERVER['REMOTE_ADDR'])) { | |||
if ($email_available && ! isset($hesk_error_buffer['email']) && hesk_isBannedEmail($tmpvar['email']) || hesk_isBannedIP(hesk_getClientIP())) { | |||
hesk_error($hesklang['baned_e']); | |||
} | |||
@@ -159,8 +159,8 @@ if ($ticket['lastreplier']) { | |||
} | |||
// If IP is unknown (tickets via email pipe/pop3 fetching) assume current visitor IP as customer IP | |||
if ($ticket['ip'] == 'Unknown' || $ticket['ip'] == $hesklang['unknown']) { | |||
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `ip` = '" . hesk_dbEscape($_SERVER['REMOTE_ADDR']) . "' WHERE `id`=" . intval($ticket['id'])); | |||
if ($ticket['ip'] == '' || $ticket['ip'] == 'Unknown' || $ticket['ip'] == $hesklang['unknown']) { | |||
hesk_dbQuery("UPDATE `".hesk_dbEscape($hesk_settings['db_pfix'])."tickets` SET `ip` = '".hesk_dbEscape(hesk_getClientIP())."' WHERE `id`=".intval($ticket['id'])); | |||
} | |||
/* Get category name and ID */ | |||