Skip to content
Permalink
039c184cba
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
3001 lines (2584 sloc) 90.7 KB
<?php
/**
* ---------------------------------------------------------------------
* GLPI - Gestionnaire Libre de Parc Informatique
* Copyright (C) 2015-2018 Teclib' and contributors.
*
* http://glpi-project.org
*
* based on GLPI - Gestionnaire Libre de Parc Informatique
* Copyright (C) 2003-2014 by the INDEPNET Development Team.
*
* ---------------------------------------------------------------------
*
* LICENSE
*
* This file is part of GLPI.
*
* GLPI is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GLPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GLPI. If not, see <http://www.gnu.org/licenses/>.
* ---------------------------------------------------------------------
*/
use Glpi\Event;
use Monolog\Logger;
if (!defined('GLPI_ROOT')) {
die("Sorry. You can't access this file directly");
}
/**
* Toolbox Class
**/
class Toolbox {
/**
* Wrapper for max_input_vars
*
* @since 0.84
*
* @return integer
**/
static function get_max_input_vars() {
$max = ini_get('max_input_vars'); // Security limit since PHP 5.3.9
if (!$max) {
$max = ini_get('suhosin.post.max_vars'); // Security limit from Suhosin
}
return $max;
}
/**
* Convert first caracter in upper
*
* @since 0.83
* @since 9.3 Rework
*
* @param $str string to change
*
* @return string changed
**/
static function ucfirst($str) {
$first_letter = mb_strtoupper(mb_substr ($str, 0, 1));
$str_end = mb_substr($str, 1, mb_strlen ($str));
return $first_letter . $str_end;
}
/**
* to underline shortcut letter
*
* @since 0.83
*
* @param $str string from dico
* @param $shortcut letter of shortcut
*
* @return string
**/
static function shortcut($str, $shortcut) {
$pos = self::strpos(self::strtolower($str), self::strtolower($shortcut));
if ($pos !== false) {
return self::substr($str, 0, $pos).
"<u>". self::substr($str, $pos, 1)."</u>".
self::substr($str, $pos+1);
}
return $str;
}
/**
* substr function for utf8 string
*
* @param $str string string
* @param $tofound string string to found
* @param $offset integer The search offset. If it is not specified, 0 is used.
* (default 0)
*
* @return substring
**/
static function strpos($str, $tofound, $offset = 0) {
return mb_strpos($str, $tofound, $offset, "UTF-8");
}
/**
* Replace str_pad()
* who bug with utf8
*
* @param $input string input string
* @param $pad_length integer padding length
* @param $pad_string string padding string (default '')
* @param $pad_type integer padding type (default STR_PAD_RIGHT)
*
* @return string
**/
static function str_pad($input, $pad_length, $pad_string = " ", $pad_type = STR_PAD_RIGHT) {
$diff = (strlen($input) - self::strlen($input));
return str_pad($input, $pad_length+$diff, $pad_string, $pad_type);
}
/**
* strlen function for utf8 string
*
* @param $str string
*
* @return length of the string
**/
static function strlen($str) {
return mb_strlen($str, "UTF-8");
}
/**
* substr function for utf8 string
*
* @param $str string
* @param $start integer start of the result substring
* @param $length integer The maximum length of the returned string if > 0 (default -1)
*
* @return substring
**/
static function substr($str, $start, $length = -1) {
if ($length == -1) {
$length = self::strlen($str)-$start;
}
return mb_substr($str, $start, $length, "UTF-8");
}
/**
* strtolower function for utf8 string
*
* @param $str string
*
* @return lower case string
**/
static function strtolower($str) {
return mb_strtolower($str, "UTF-8");
}
/**
* strtoupper function for utf8 string
*
* @param $str string
*
* @return upper case string
**/
static function strtoupper($str) {
return mb_strtoupper($str, "UTF-8");
}
/**
* Is a string seems to be UTF-8 one ?
*
* @param $str string string to analyze
*
* @return boolean
**/
static function seems_utf8($str) {
return mb_check_encoding($str, "UTF-8");
}
/**
* Encode string to UTF-8
*
* @param $string string string to convert
* @param $from_charset string original charset (if 'auto' try to autodetect)
* (default "ISO-8859-1")
*
* @return utf8 string
**/
static function encodeInUtf8($string, $from_charset = "ISO-8859-1") {
if (strcmp($from_charset, "auto") == 0) {
$from_charset = mb_detect_encoding($string);
}
return mb_convert_encoding($string, "UTF-8", $from_charset);
}
/**
* Decode string from UTF-8 to specified charset
*
* @param $string string string to convert
* @param $to_charset string destination charset (default "ISO-8859-1")
*
* @return converted string
**/
static function decodeFromUtf8($string, $to_charset = "ISO-8859-1") {
return mb_convert_encoding($string, $to_charset, "UTF-8");
}
/**
* Encrypt a string
*
* @param $string string to encrypt
* @param $key string key used to encrypt
*
* @return encrypted string
**/
static function encrypt($string, $key = null) {
if ($key === null) {
$key = self::getGlpiSecKey();
}
if ($key === GLPIKEY && !defined('TU_USER')) {
self::deprecated('Using GLPIKEY is not secure!');
}
$result = '';
for ($i=0; $i<strlen($string); $i++) {
$char = substr($string, $i, 1);
$keychar = substr($key, ($i % strlen($key))-1, 1);
$char = chr(ord($char)+ord($keychar));
$result .= $char;
}
return base64_encode($result);
}
/**
* Decrypt a string
*
* @param $string string to decrypt
* @param $key string key used to decrypt
*
* @return decrypted string
**/
static function decrypt($string, $key = null) {
if ($key === null) {
$key = self::getGlpiSecKey();
}
$result = '';
$string = base64_decode($string);
for ($i=0; $i<strlen($string); $i++) {
$char = substr($string, $i, 1);
$keychar = substr($key, ($i % strlen($key))-1, 1);
$char = chr(ord($char)-ord($keychar));
$result .= $char;
}
return Toolbox::unclean_cross_side_scripting_deep($result);
}
/**
* Get GLPI security key used for decryptable passwords
*
* Will read key from config/glpi.key if present.
* For 9.4 branch, this will defaults to GLPIKEY.
*
* @return string
*/
public static function getGlpiSecKey() {
$glpikey = new GLPIKey();
return $glpikey->get();
}
/**
* Prevent from XSS
* Clean code
*
* @param $value array or string: item to prevent (array or string)
*
* @return clean item
*
* @see unclean_cross_side_scripting_deep*
**/
static function clean_cross_side_scripting_deep($value) {
if ((array) $value === $value) {
return array_map([__CLASS__, 'clean_cross_side_scripting_deep'], $value);
}
if (!is_string($value)) {
return $value;
}
$in = ['<', '>'];
$out = ['&lt;', '&gt;'];
return str_replace($in, $out, $value);
}
/**
* Invert fonction from clean_cross_side_scripting_deep
*
* @param $value array or string item to unclean from clean_cross_side_scripting_deep
*
* @return unclean item
*
* @see clean_cross_side_scripting_deep
**/
static function unclean_cross_side_scripting_deep($value) {
if ((array) $value === $value) {
return array_map([__CLASS__, 'unclean_cross_side_scripting_deep'], $value);
}
if (!is_string($value)) {
return $value;
}
$in = ['<', '>'];
$out = ['&lt;', '&gt;'];
return str_replace($out, $in, $value);
}
/**
* Invert fonction from clean_cross_side_scripting_deep to display HTML striping XSS code
*
* @since 0.83.3
*
* @param $value array or string: item to unclean from clean_cross_side_scripting_deep
*
* @return unclean item
*
* @see clean_cross_side_scripting_deep
**/
static function unclean_html_cross_side_scripting_deep($value) {
include_once(GLPI_HTMLAWED);
if ((array) $value === $value) {
$value = array_map([__CLASS__, 'unclean_html_cross_side_scripting_deep'], $value);
} else {
$value = self::unclean_cross_side_scripting_deep($value);
}
// revert unclean inside <pre>
if (is_string($value)) {
$count = preg_match_all('/(<pre[^>]*>)(.*?)(<\/pre>)/is', $value, $matches);
for ($i = 0; $i < $count; ++$i) {
$complete = $matches[0][$i];
$cleaned = self::clean_cross_side_scripting_deep($matches[2][$i]);
$cleancomplete = $matches[1][$i].$cleaned.$matches[3][$i];
$value = str_replace($complete, $cleancomplete, $value);
}
$config = ['safe'=>1];
$config["elements"] = "*+iframe+audio+video";
$config["direct_list_nest"] = 1;
$value = htmLawed($value, $config);
// Special case : remove the 'denied:' for base64 img in case the base64 have characters
// combinaison introduce false positive
foreach (['png', 'gif', 'jpg', 'jpeg'] as $imgtype) {
$value = str_replace('src="denied:data:image/'.$imgtype.';base64,',
'src="data:image/'.$imgtype.';base64,', $value);
}
}
return $value;
}
/**
* Log in 'php-errors' all args
*
* @param Logger $logger Logger instance, if any
* @param integer $level Log level (defaults to warning)
* @param array $args Arguments (message to log, ...)
*
* @return void
**/
private static function log($logger = null, $level = Logger::WARNING, $args = null) {
static $tps = 0;
$extra = [];
if (method_exists('Session', 'getLoginUserID')) {
$extra['user'] = Session::getLoginUserID().'@'.php_uname('n');
}
if ($tps && function_exists('memory_get_usage')) {
$extra['mem_usage'] = number_format(microtime(true)-$tps, 3).'", '.
number_format(memory_get_usage()/1024/1024, 2).'Mio)';
}
$msg = "";
if (function_exists('debug_backtrace')) {
$bt = debug_backtrace();
if (count($bt) > 2) {
if (isset($bt[2]['class'])) {
$msg .= $bt[2]['class'].'::';
}
$msg .= $bt[2]['function'].'() in ';
}
$msg .= $bt[1]['file'] . ' line ' . $bt[1]['line'] . "\n";
}
if ($args == null) {
$args = func_get_args();
} else if (!is_array($args)) {
$args = [$args];
}
foreach ($args as $arg) {
if (is_array($arg) || is_object($arg)) {
$msg .= str_replace("\n", "\n ", print_r($arg, true));
} else if (is_null($arg)) {
$msg .= 'NULL ';
} else if (is_bool($arg)) {
$msg .= ($arg ? 'true' : 'false').' ';
} else {
$msg .= $arg . ' ';
}
}
$tps = microtime(true);
if ($logger === null) {
global $PHPLOGGER;
$logger = $PHPLOGGER;
}
$logger->addRecord($level, $msg, $extra);
if (defined('TU_USER') && $level >= Logger::NOTICE) {
throw new \RuntimeException($msg);
} else if (isCommandLine() && $level >= Logger::WARNING) {
echo $msg;
}
}
/**
* PHP debug log
*/
static function logDebug() {
self::log(null, Logger::DEBUG, func_get_args());
}
/**
* PHP info log
*/
static function loginfo() {
self::log(null, Logger::INFO, func_get_args());
}
/**
* PHP warning log
*/
static function logWarning() {
self::log(null, Logger::WARNING, func_get_args());
}
/**
* PHP error log
*/
static function logError() {
self::log(null, Logger::ERROR, func_get_args());
}
/**
* SQL error log
*/
static function logSqlDebug() {
global $SQLLOGGER;
$args = func_get_args();
self::log($SQLLOGGER, Logger::DEBUG, $args);
}
/**
* SQL error log
*/
static function logSqlError() {
global $SQLLOGGER;
$args = func_get_args();
$msg = $args[0];
try {
self::log($SQLLOGGER, Logger::ERROR, $args);
} catch (\RuntimeException $e) {
$msg = $e->getMessage();
} finally {
if (class_exists('GlpitestSQLError')) { // For unit test
throw new \GlpitestSQLError($msg);
}
}
}
/**
* Generate a Backtrace
*
* @param $log String log file name (default php-errors)
* if false, return the strung
* @param $hide String call to hide (but display script/line) (default '')
* @param $skip Array of call to not display at all
*
* @since 0.85
*
* @return string if $log is false
**/
static function backtrace($log = 'php-errors', $hide = '', Array $skip = []) {
if (function_exists("debug_backtrace")) {
$message = " Backtrace :\n";
$traces = debug_backtrace();
foreach ($traces as $trace) {
$script = (isset($trace["file"]) ? $trace["file"] : "") . ":" .
(isset($trace["line"]) ? $trace["line"] : "");
if (strpos($script, GLPI_ROOT)===0) {
$script = substr($script, strlen(GLPI_ROOT)+1);
}
if (strlen($script)>50) {
$script = "...".substr($script, -47);
} else {
$script = str_pad($script, 50);
}
$call = (isset($trace["class"]) ? $trace["class"] : "") .
(isset($trace["type"]) ? $trace["type"] : "") .
(isset($trace["function"]) ? $trace["function"]."()" : "");
if ($call == $hide) {
$call = '';
}
if (!in_array($call, $skip)) {
$message .= " $script $call\n";
}
}
} else {
$message = " Script : " . $_SERVER["SCRIPT_FILENAME"]. "\n";
}
if ($log) {
self::logInFile($log, $message, true);
} else {
return $message;
}
}
/**
* Send a deprecated message in log (with backtrace)
* @param string $message the message to send
* @return void
*/
static function deprecated($message = "Called method is deprecated") {
try {
self::log(null, Logger::NOTICE, [$message]);
} finally {
if (defined('TU_USER')) {
if (isCommandLine()) {
echo self::backtrace(null);
} else {
self::backtrace();
}
}
}
}
/**
* Log a message in log file
*
* @param $name string name of the log file
* @param $text string text to log
* @param $force boolean force log in file not seeing use_log_in_files config (false by default)
**/
static function logInFile($name, $text, $force = false) {
global $CFG_GLPI;
$user = '';
if (method_exists('Session', 'getLoginUserID')) {
$user = " [".Session::getLoginUserID().'@'.php_uname('n')."]";
}
$ok = true;
if ((isset($CFG_GLPI["use_log_in_files"]) && $CFG_GLPI["use_log_in_files"])
|| $force) {
$ok = error_log(date("Y-m-d H:i:s")."$user\n".$text, 3, GLPI_LOG_DIR."/".$name.".log");
}
if (isset($_SESSION['glpi_use_mode'])
&& ($_SESSION['glpi_use_mode'] == Session::DEBUG_MODE)
&& isCommandLine()) {
$stderr = fopen('php://stderr', 'w');
fwrite($stderr, $text);
fclose($stderr);
}
return $ok;
}
/**
* Specific error handler in Normal mode
*
* @param $errno integer level of the error raised.
* @param $errmsg string error message.
* @param $filename string filename that the error was raised in.
* @param $linenum integer line number the error was raised at.
**/
static function userErrorHandlerNormal($errno, $errmsg, $filename, $linenum) {
// Date et heure de l'erreur
$errortype = [E_ERROR => 'Error',
E_WARNING => 'Warning',
E_PARSE => 'Parsing Error',
E_NOTICE => 'Notice',
E_CORE_ERROR => 'Core Error',
E_CORE_WARNING => 'Core Warning',
E_COMPILE_ERROR => 'Compile Error',
E_COMPILE_WARNING => 'Compile Warning',
E_USER_ERROR => 'User Error',
E_USER_WARNING => 'User Warning',
E_USER_NOTICE => 'User Notice',
E_STRICT => 'Runtime Notice',
E_RECOVERABLE_ERROR => 'Catchable Fatal Error',
E_DEPRECATED => 'Deprecated function',
E_USER_DEPRECATED => 'User deprecated function'];
// Les niveaux qui seront enregistr??s
$user_errors = [E_USER_ERROR, E_USER_NOTICE, E_USER_WARNING];
$err = ' *** PHP '.$errortype[$errno] . "($errno): $errmsg\n";
$skip = ['Toolbox::backtrace()'];
if (isset($_SESSION['glpi_use_mode']) && $_SESSION['glpi_use_mode'] == Session::DEBUG_MODE) {
$hide = "Toolbox::userErrorHandlerDebug()";
$skip[] = "Toolbox::userErrorHandlerNormal()";
} else {
$hide = "Toolbox::userErrorHandlerNormal()";
}
$err .= self::backtrace(false, $hide, $skip);
// For unit test
if (class_exists('GlpitestPHPerror')) {
if (in_array($errno, [E_ERROR, E_USER_ERROR])) {
throw new GlpitestPHPerror($err);
}
/* for tuture usage
if (in_array($errno, [E_STRICT, E_WARNING, E_CORE_WARNING, E_USER_WARNING, E_DEPRECATED, E_USER_DEPRECATED])) {
throw new GlpitestPHPwarning($err);
}
if (in_array($errno, [E_NOTICE, E_USER_NOTICE])) {
throw new GlpitestPHPnotice($err);
}
*/
}
// Save error
static::logError($err);
return $errortype[$errno];
}
/**
* Specific error handler in Debug mode
*
* @param $errno integer level of the error raised.
* @param $errmsg string error message.
* @param $filename string filename that the error was raised in.
* @param $linenum integer line number the error was raised at.
**/
static function userErrorHandlerDebug($errno, $errmsg, $filename, $linenum) {
// For file record
$type = self::userErrorHandlerNormal($errno, $errmsg, $filename, $linenum);
// Display
if (!isCommandLine()) {
echo '<div style="position:float-left; background-color:red; z-index:10000">'.
'<span class="b">PHP '.$type.': </span>';
echo $errmsg.' in '.$filename.' at line '.$linenum.'</div>';
} else {
echo 'PHP '.$type.': '.$errmsg.' in '.$filename.' at line '.$linenum."\n";
}
}
/**
* Switch error mode for GLPI
*
* @param $mode Integer from Session::*_MODE (default NULL)
* @param $debug_sql Boolean (default NULL)
* @param $debug_vars Boolean (default NULL)
* @param $log_in_files Boolean (default NULL)
*
* @since 0.84
**/
static function setDebugMode($mode = null, $debug_sql = null, $debug_vars = null, $log_in_files = null) {
global $CFG_GLPI;
if (isset($mode)) {
$_SESSION['glpi_use_mode'] = $mode;
}
if (isset($debug_sql)) {
$CFG_GLPI['debug_sql'] = $debug_sql;
}
if (isset($debug_vars)) {
$CFG_GLPI['debug_vars'] = $debug_vars;
}
if (isset($log_in_files)) {
$CFG_GLPI['use_log_in_files'] = $log_in_files;
}
// If debug mode activated : display some information
if ($_SESSION['glpi_use_mode'] == Session::DEBUG_MODE) {
// Recommended development settings
ini_set('display_errors', 'On');
error_reporting(E_ALL);
set_error_handler(['Toolbox','userErrorHandlerDebug']);
} else if (!defined('TU_USER')) {
// Recommended production settings
ini_set('display_errors', 'Off');
error_reporting(E_ALL & ~E_DEPRECATED & ~E_STRICT);
set_error_handler(['Toolbox', 'userErrorHandlerNormal']);
}
}
/**
* Send a file (not a document) to the navigator
* See Document->send();
*
* @param $file string: storage filename
* @param $filename string: file title
* @param $mime string: file mime type
*
* @return nothing
**/
static function sendFile($file, $filename, $mime = null) {
// Test securite : document in DOC_DIR
$tmpfile = str_replace(GLPI_DOC_DIR, "", $file);
if (strstr($tmpfile, "../") || strstr($tmpfile, "..\\")) {
Event::log($file, "sendFile", 1, "security",
$_SESSION["glpiname"]." try to get a non standard file.");
echo "Security attack!!!";
die(1);
}
if (!file_exists($file)) {
echo "Error file $file does not exist";
die(1);
}
// if $mime is defined, ignore mime type by extension
if ($mime === null && preg_match('/\.(...)$/', $file, $regs)) {
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $file);
finfo_close($finfo);
}
// don't download picture files, see them inline
$attachment = "";
// if not begin 'image/'
if (strncmp($mime, 'image/', 6) !== 0
&& $mime != 'application/pdf'
// svg vector of attack, force attachment
// see https://github.com/glpi-project/glpi/issues/3873
|| $mime == 'image/svg+xml') {
$attachment = ' attachment;';
}
$etag = md5_file($file);
$lastModified = filemtime($file);
// Now send the file with header() magic
header("Last-Modified: ".gmdate("D, d M Y H:i:s", $lastModified)." GMT");
header("Etag: $etag");
header('Pragma: private'); /// IE BUG + SSL
header('Cache-control: private, must-revalidate'); /// IE BUG + SSL
header(
"Content-disposition:$attachment filename=\"" .
addslashes(utf8_decode($filename)) .
"\"; filename*=utf-8''" .
rawurlencode($filename)
);
header("Content-type: ".$mime);
// HTTP_IF_NONE_MATCH takes precedence over HTTP_IF_MODIFIED_SINCE
// http://tools.ietf.org/html/rfc7232#section-3.3
if (isset($_SERVER['HTTP_IF_NONE_MATCH']) && trim($_SERVER['HTTP_IF_NONE_MATCH']) === $etag) {
http_response_code(304); //304 - Not Modified
exit;
}
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && @strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= $lastModified) {
http_response_code(304); //304 - Not Modified
exit;
}
readfile($file) or die ("Error opening file $file");
}
/**
* Add slash for variable & array
*
* @param $value array or string: value to add slashes (array or string)
*
* @return addslashes value
**/
static function addslashes_deep($value) {
global $DB;
$value = ((array) $value === $value)
? array_map([__CLASS__, 'addslashes_deep'], $value)
: (is_null($value)
? null : (is_resource($value)
? $value : $DB->escape(
str_replace(
['&#039;', '&#39;', '&#x27;', '&apos;', '&quot;'],
["'", "'", "'", "'", "\""],
$value
)
))
);
return $value;
}
/**
* Strip slash for variable & array
*
* @param $value array or string: item to stripslashes (array or string)
*
* @return stripslashes item
**/
static function stripslashes_deep($value) {
$value = ((array) $value === $value)
? array_map([__CLASS__, 'stripslashes_deep'], $value)
: (is_null($value)
? null : (is_resource($value)
? $value :stripslashes($value)));
return $value;
}
/** Converts an array of parameters into a query string to be appended to a URL.
*
* @param $array array parameters to append to the query string.
* @param $separator separator may be defined as &amp; to display purpose
* (default '&')
* @param $parent This should be left blank (it is used internally by the function).
* (default '')
*
* @return string : Query string to append to a URL.
**/
static function append_params($array, $separator = '&', $parent = '') {
$params = [];
foreach ($array as $k => $v) {
if (is_array($v)) {
$params[] = self::append_params($v, $separator,
(empty($parent) ? rawurlencode($k)
: $parent . '%5B' . rawurlencode($k) . '%5D'));
} else {
$params[] = (!empty($parent) ? $parent . '%5B' . rawurlencode($k) . '%5D' : rawurlencode($k)) . '=' . rawurlencode($v);
}
}
return implode($separator, $params);
}
/**
* Compute PHP memory_limit
*
* @param $ininame String name of the ini ooption to retrieve (since 9.1)
*
* @return memory limit
**/
static function getMemoryLimit($ininame = 'memory_limit') {
$mem = ini_get($ininame);
preg_match("/([-0-9]+)([KMG]*)/", $mem, $matches);
$mem = "";
// no K M or G
if (isset($matches[1])) {
$mem = $matches[1];
if (isset($matches[2])) {
switch ($matches[2]) {
case "G" :
$mem *= 1024;
// nobreak;
case "M" :
$mem *= 1024;
// nobreak;
case "K" :
$mem *= 1024;
// nobreak;
}
}
}
return $mem;
}
/**
* Check is current memory_limit is enough for GLPI
*
* @since 0.83
*
* @return 0 if PHP not compiled with memory_limit support
* 1 no memory limit (memory_limit = -1)
* 2 insufficient memory for GLPI
* 3 enough memory for GLPI
**/
static function checkMemoryLimit() {
$mem = self::getMemoryLimit();
if ($mem == "") {
return 0;
}
if ($mem == "-1") {
return 1;
}
if ($mem < (64*1024*1024)) {
return 2;
}
return 3;
}
/**
* Common Checks needed to use GLPI
* @param boolean $isInstall Is the check run on a install process (don't check DB as not configured yet)
*
* @return integer 2 = creation error / 1 = delete error / 0 = OK
*/
static function commonCheckForUseGLPI($isInstall = false) {
global $CFG_GLPI;
$error = 0;
// Title
echo "<tr><th>".__('Test done')."</th><th >".__('Results')."</th></tr>";
// Parser test
echo "<tr class='tab_bg_1'><td class='b left'>".__('Testing PHP Parser')."</td>";
// PHP Version - exclude PHP3, PHP 4 and zend.ze1 compatibility
if (version_compare(PHP_VERSION, GLPI_MIN_PHP) >= 0) {
// PHP version ok, now check PHP zend.ze1_compatibility_mode
if (ini_get("zend.ze1_compatibility_mode") == 1) {
$error = 2;
echo "<td class='red'>
<img src='".$CFG_GLPI['root_doc']."/pics/ko_min.png'>".
__('GLPI is not compatible with the option zend.ze1_compatibility_mode = On.').
"</td>";
} else {
echo "<td><img src='".$CFG_GLPI['root_doc']."/pics/ok_min.png' alt=\"".
sprintf(__s('PHP version is at least %s - Perfect!'), GLPI_MIN_PHP)."\"
title=\"".sprintf(__s('PHP version is at least %s - Perfect!'), GLPI_MIN_PHP)."\"></td>";
}
} else { // PHP <5
$error = 2;
echo "<td class='red'>
<img src='".$CFG_GLPI['root_doc']."/pics/ko_min.png'>".
sprintf(__('You must install at least PHP %s.'), GLPI_MIN_PHP)."</td>";
}
echo "</tr>";
// session test
echo "<tr class='tab_bg_1'><td class='b left'>".__('Sessions test')."</td>";
// check whether session are enabled at all!!
if (!extension_loaded('session')) {
$error = 2;
echo "<td class='red b'>".__('Your parser PHP is not installed with sessions support!').
"</td>";
} else if ((isset($_SESSION["Test_session_GLPI"]) && ($_SESSION["Test_session_GLPI"] == 1)) // From install
|| isset($_SESSION["glpi_currenttime"])) { // From Update
echo "<td><img src='".$CFG_GLPI['root_doc']."/pics/ok_min.png' alt=\"".
__s('Sessions support is available - Perfect!').
"\" title=\"".__s('Sessions support is available - Perfect!')."\"></td>";
} else if ($error != 2) {
echo "<td class='red'>";
echo "<img src='".$CFG_GLPI['root_doc']."/pics/warning_min.png'>".
__('Make sure that sessions support has been activated in your php.ini')."</td>";
$error = 1;
}
echo "</tr>";
// Test for session auto_start
if (ini_get('session.auto_start')==1) {
echo "<tr class='tab_bg_1'><td class='b'>".__('Test session auto start')."</td>";
echo "<td class='red'>";
echo "<img src='".$CFG_GLPI['root_doc']."/pics/ko_min.png'>".
__('session.auto_start is activated. See .htaccess file in the GLPI root for more information.').
"</td></tr>";
$error = 2;
}
// Test for option session use trans_id loaded or not.
echo "<tr class='tab_bg_1'>";
echo "<td class='left b'>".__('Test if Session_use_trans_sid is used')."</td>";
if (isset($_POST[session_name()]) || isset($_GET[session_name()])) {
echo "<td class='red'>";
echo "<img src='".$CFG_GLPI['root_doc']."/pics/ko_min.png'>".
__('You must desactivate the Session_use_trans_id option in your php.ini')."</td>";
$error = 2;
} else {
echo "<td><img src='".$CFG_GLPI['root_doc']."/pics/ok_min.png' alt=\"".
__s('Ok - the sessions works (no problem with trans_id) - Perfect!').
"\" title=\"". __s('Ok - the sessions works (no problem with trans_id) - Perfect!').
"\"></td>";
}
echo "</tr>";
$suberr = Config::displayCheckExtensions();
if ($suberr > $error) {
$error = $suberr;
}
// No DB version check on system check on the install (DB conf not defined when test are running)
if (!$isInstall) {
//database version check
echo "<tr class='tab_bg_1'><td class='b left'>" . __('Testing DB engine version') . "</td>";
$suberr = Config::displayCheckDbEngine();
if ($suberr > $error) {
$error = $suberr;
}
echo "</tr>";
}
// memory test
echo "<tr class='tab_bg_1'><td class='left b'>".__('Allocated memory test')."</td>";
//Get memory limit
$mem = self::getMemoryLimit();
switch (self::checkMemoryLimit()) {
case 0 : // memory_limit not compiled -> no memory limit
case 1 : // memory_limit compiled and unlimited
echo "<td><img src='".$CFG_GLPI['root_doc']."/pics/ok_min.png' alt=\"".
__s('Unlimited memory - Perfect!')."\" title=\"".
__s('Unlimited memory - Perfect!')."\"></td>";
break;
case 2: //Insufficient memory
$showmem = $mem/1048576;
echo "<td class='red'><img src='".$CFG_GLPI['root_doc']."/pics/ko_min.png'>".
"<span class='b'>".sprintf(__('%1$s: %2$s'), __('Allocated memory'),
sprintf(__('%1$s %2$s'), $showmem, __('Mio'))).
"</span>".
"<br>".__('A minimum of 64Mio is commonly required for GLPI.').
"<br>".__('Try increasing the memory_limit parameter in the php.ini file.').
"</td>";
$error = 2;
break;
case 3: //Got enough memory, going to the next step
echo "<td><img src='".$CFG_GLPI['root_doc']."/pics/ok_min.png' alt=\"".
__s('Allocated memory > 64Mio - Perfect!')."\" title=\"".
__s('Allocated memory > 64Mio - Perfect!')."\"></td>";
break;
}
echo "</tr>";
if (!isset($_REQUEST['skipCheckWriteAccessToDirs'])) {
$suberr = Config::checkWriteAccessToDirs();
if ($suberr > $error) {
$error = $suberr;
}
}
$suberr = self::checkSELinux();
if ($suberr > $error) {
$error = $suberr;
}
return $error;
}
/**
* Check SELinux configuration
*
* @since 0.84
* @param $fordebug Boolean true is displayed in system information
*
* @return integer 0: OK, 1:Warning, 2:Error
**/
static function checkSELinux($fordebug = false) {
global $CFG_GLPI;
if ((DIRECTORY_SEPARATOR != '/')
|| !file_exists('/usr/sbin/getenforce')) {
// This is not a SELinux system
return 0;
}
if (function_exists('selinux_getenforce')) { // Use https://pecl.php.net/package/selinux
$mode = selinux_getenforce();
// Make it human readable, with same output as the command
if ($mode > 0) {
$mode = 'Enforcing';
} else if ($mode < 0) {
$mode = 'Disabled';
} else {
$mode = 'Permissive';
}
} else {
$mode = exec("/usr/sbin/getenforce");
if (empty($mode)) {
$mode = "Unknown";
}
}
//TRANS: %s is mode name (Permissive, Enforcing of Disabled)
$msg = sprintf(__('SELinux mode is %s'), $mode);
if ($fordebug) {
echo "<img src='".$CFG_GLPI['root_doc']."/pics/ok_min.png' alt=\"" . __s('OK') . "\">$msg\n";
} else {
echo "<tr class='tab_bg_1'><td class='left b'>$msg</td>";
// All modes should be ok
echo "<td><img src='".$CFG_GLPI['root_doc']."/pics/ok_min.png' alt='$mode' title='$msg'></td></tr>";
}
if (!strcasecmp($mode, 'Disabled')) {
// Other test are not useful
return 0;
}
$err = 0;
// No need to check file context as checkWriteAccessToDirs will show issues
// Enforcing mode will block some feature (notif, ...)
// Permissive mode will write lot of stuff in audit.log
$bools = ['httpd_can_network_connect', 'httpd_can_network_connect_db',
'httpd_can_sendmail'];
$msg2 = __s('Some features may require this to be on');
foreach ($bools as $bool) {
if (function_exists('selinux_get_boolean_active')) {
$state = selinux_get_boolean_active($bool);
// Make it human readable, with same output as the command
$state = "$bool --> " . ($state ? 'on' : 'off');
} else {
$state = exec('/usr/sbin/getsebool '.$bool);
if (empty($state)) {
$state = "$bool --> unkwown";
}
}
//TRANS: %s is an option name
$msg = sprintf(__('SELinux boolean configuration for %s'), $state);
if ($fordebug) {
if (substr($state, -2) == 'on') {
echo "<img src='".$CFG_GLPI['root_doc']."/pics/ok_min.png' alt=\"". __s('OK') .
"\" title=\"" . __s('OK') . "\">$msg\n";
} else {
echo "<img src='".$CFG_GLPI['root_doc']."/pics/warning_min.png' alt=\"". $msg2 .
"\" title=\"$msg2\">$msg ($msg2)\n";
}
} else {
if (substr($state, -2) == 'on') {
echo "<tr class='tab_bg_1'><td class='left b'>$msg</td>";
echo "<td><img src='".$CFG_GLPI['root_doc']."/pics/ok_min.png' alt='$state' title='$state'>".
"</td>";
} else {
echo "<tr class='tab_bg_1'><td class='left b'>$msg ($msg2)</td>";
echo "<td><img src='".$CFG_GLPI['root_doc']."/pics/warning_min.png' alt='$msg2' title='$msg2'>".
"</td>";
$err = 1;
}
echo "</tr>";
}
}
return $err;
}
/**
* Get the filesize of a complete directory (from php.net)
*
* @param $path string: directory or file to get size
*
* @return size of the $path
**/
static function filesizeDirectory($path) {
if (!is_dir($path)) {
return filesize($path);
}
if ($handle = opendir($path)) {
$size = 0;
while (false !== ($file = readdir($handle))) {
if (($file != '.') && ($file != '..')) {
$size += filesize($path.'/'.$file);
$size += self::filesizeDirectory($path.'/'.$file);
}
}
closedir($handle);
return $size;
}
}
/** Format a size passing a size in octet
*
* @param $size integer: Size in octet
*
* @return formatted size
**/
static function getSize($size) {
//TRANS: list of unit (o for octet)
$bytes = [__('o'), __('Kio'), __('Mio'), __('Gio'), __('Tio')];
foreach ($bytes as $val) {
if ($size > 1024) {
$size = $size / 1024;
} else {
break;
}
}
//TRANS: %1$s is a number maybe float or string and %2$s the unit
return sprintf(__('%1$s %2$s'), round($size, 2), $val);
}
/**
* Delete a directory and file contains in it
*
* @param $dir string: directory to delete
**/
static function deleteDir($dir) {
if (file_exists($dir)) {
chmod($dir, 0777);
if (is_dir($dir)) {
$id_dir = opendir($dir);
while (($element = readdir($id_dir)) !== false) {
if (($element != ".") && ($element != "..")) {
if (is_dir($dir."/".$element)) {
self::deleteDir($dir."/".$element);
} else {
unlink($dir."/".$element);
}
}
}
closedir($id_dir);
rmdir($dir);
} else { // Delete file
unlink($dir);
}
}
}
/**
* Resize a picture to the new size
* Always produce a JPG file!
*
* @since 0.85
*
* @param $source_path string path of the picture to be resized
* @param $dest_path string path of the new resized picture
* @param $new_width string new width after resized (default 71)
* @param $new_height string new height after resized (default 71)
* @param $img_y string y axis of picture (default 0)
* @param $img_x string x axis of picture (default 0)
* @param $img_width string width of picture (default 0)
* @param $img_height string height of picture (default 0)
* @param $max_size integer max size of the picture (default 500, is set to 0 no resize)
*
* @return bool : true or false
**/
static function resizePicture($source_path, $dest_path, $new_width = 71, $new_height = 71,
$img_y = 0, $img_x = 0, $img_width = 0, $img_height = 0, $max_size = 500) {
//get img informations (dimensions and extension)
$img_infos = getimagesize($source_path);
if (empty($img_width)) {
$img_width = $img_infos[0];
}
if (empty($img_height)) {
$img_height = $img_infos[1];
}
if (empty($new_width)) {
$new_width = $img_infos[0];
}
if (empty($new_height)) {
$new_height = $img_infos[1];
}
// Image max size is 500 pixels : is set to 0 no resize
if ($max_size>0) {
if (($img_width > $max_size)
|| ($img_height > $max_size)) {
$source_aspect_ratio = $img_width / $img_height;
if ($source_aspect_ratio < 1) {
$new_width = $max_size * $source_aspect_ratio;
$new_height = $max_size;
} else {
$new_width = $max_size;
$new_height = $max_size / $source_aspect_ratio;
}
}
}
$img_type = $img_infos[2];
switch ($img_type) {
case IMAGETYPE_BMP :
$source_res = imagecreatefromwbmp($source_path);
break;
case IMAGETYPE_GIF :
$source_res = imagecreatefromgif($source_path);
break;
case IMAGETYPE_JPEG :
$source_res = imagecreatefromjpeg($source_path);
break;
case IMAGETYPE_PNG :
$source_res = imagecreatefrompng($source_path);
break;
default :
return false;
}
//create new img resource for store thumbnail
$source_dest = imagecreatetruecolor($new_width, $new_height);
// set transparent background for PNG/GIF
if ($img_type === IMAGETYPE_GIF || $img_type === IMAGETYPE_PNG) {
imagecolortransparent($source_dest, imagecolorallocatealpha($source_dest, 0, 0, 0, 127));
imagealphablending($source_dest, false);
imagesavealpha($source_dest, true);
}
//resize image
imagecopyresampled($source_dest, $source_res, 0, 0, $img_x, $img_y,
$new_width, $new_height, $img_width, $img_height);
//output img
$result = null;
switch ($img_type) {
case IMAGETYPE_GIF :
case IMAGETYPE_PNG :
$result = imagepng($source_dest, $dest_path);
break;
case IMAGETYPE_JPEG :
default :
$result = imagejpeg($source_dest, $dest_path, 90);
break;
}
return $result;
}
/**
* Check if new version is available
*
* @return string
**/
static function checkNewVersionAvailable() {
global $CFG_GLPI;
//parse github releases (get last version number)
$error = "";
$json_gh_releases = self::getURLContent("https://api.github.com/repos/glpi-project/glpi/releases", $error);
$all_gh_releases = json_decode($json_gh_releases, true);
$released_tags = [];
foreach ($all_gh_releases as $release) {
if ($release['prerelease'] == false) {
$released_tags[] = $release['tag_name'];
}
}
usort($released_tags, 'version_compare');
$latest_version = array_pop($released_tags);
if (strlen(trim($latest_version)) == 0) {
return $error;
} else {
if (version_compare($CFG_GLPI["version"], $latest_version, '<')) {
Config::setConfigurationValues('core', ['founded_new_version' => $latest_version]);
return sprintf(__('A new version is available: %s.'), $latest_version);
} else {
return __('You have the latest available version');
}
}
return 1;
}
/**
* Determine if Imap/Pop is usable checking extension existence
*
* @return boolean
**/
static function canUseImapPop() {
return extension_loaded('imap');
}
/**
* Determine if Ldap is usable checking ldap extension existence
*
* @return boolean
**/
static function canUseLdap() {
return extension_loaded('ldap');
}
/**
* Determine if CAS auth is usable checking lib existence
*
* @since 9.3
*
* @return boolean
**/
static function canUseCas() {
return class_exists('phpCAS');
}
/**
* Check Write Access to a directory
*
* @param $dir string: directory to check
*
* @return 2 : creation error 1 : delete error 0: OK
**/
static function testWriteAccessToDirectory($dir) {
$rand = rand();
// Check directory creation which can be denied by SElinux
$sdir = sprintf("%s/test_glpi_%08x", $dir, $rand);
if (!mkdir($sdir)) {
return 4;
}
if (!rmdir($sdir)) {
return 3;
}
// Check file creation
$path = sprintf("%s/test_glpi_%08x.txt", $dir, $rand);
$fp = fopen($path, 'w');
if (empty($fp)) {
return 2;
}
$fw = fwrite($fp, "This file was created for testing reasons. ");
fclose($fp);
$delete = unlink($path);
if (!$delete) {
return 1;
}
return 0;
}
/**
* Get form URL for itemtype
*
* @param $itemtype string item type
* @param $full path or relative one (true by default)
*
* return string itemtype Form URL
**/
static function getItemTypeFormURL($itemtype, $full = true) {
global $CFG_GLPI;
$dir = ($full ? $CFG_GLPI['root_doc'] : '');
if ($plug = isPluginItemType($itemtype)) {
/* PluginFooBar => /plugins/foo/front/bar */
$dir .= "/plugins/".strtolower($plug['plugin']);
$item = str_replace('\\', '/', strtolower($plug['class']));
} else { // Standard case
$item = strtolower($itemtype);
if (substr($itemtype, 0, \strlen(NS_GLPI)) === NS_GLPI) {
$item = str_replace('\\', '/', substr($item, \strlen(NS_GLPI)));
}
}
return "$dir/front/$item.form.php";
}
/**
* Get search URL for itemtype
*
* @param $itemtype string item type
* @param $full path or relative one (true by default)
*
* return string itemtype search URL
**/
static function getItemTypeSearchURL($itemtype, $full = true) {
global $CFG_GLPI;
$dir = ($full ? $CFG_GLPI['root_doc'] : '');
if ($plug = isPluginItemType($itemtype)) {
$dir .= "/plugins/".strtolower($plug['plugin']);
$item = str_replace('\\', '/', strtolower($plug['class']));
} else { // Standard case
if ($itemtype == 'Cartridge') {
$itemtype = 'CartridgeItem';
}
if ($itemtype == 'Consumable') {
$itemtype = 'ConsumableItem';
}
$item = strtolower($itemtype);
if (substr($itemtype, 0, \strlen(NS_GLPI)) === NS_GLPI) {
$item = str_replace('\\', '/', substr($item, \strlen(NS_GLPI)));
}
}
return "$dir/front/$item.php";
}
/**
* Get ajax tabs url for itemtype
*
* @param $itemtype string item type
* @param $full path or relative one (true by default)
*
* return string itemtype tabs URL
**/
static function getItemTypeTabsURL($itemtype, $full = true) {
global $CFG_GLPI;
$filename = "/ajax/common.tabs.php";
return ($full ? $CFG_GLPI['root_doc'] : '').$filename;
}
/**
* Get a random string
*
* @param integer $length of the random string
*
* @return random string
*
* @see https://stackoverflow.com/questions/4356289/php-random-string-generator/31107425#31107425
**/
static function getRandomString($length) {
$keyspace = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$str = '';
$max = mb_strlen($keyspace, '8bit') - 1;
for ($i = 0; $i < $length; ++$i) {
$str .= $keyspace[random_int(0, $max)];
}
return $str;
}
/**
* Split timestamp in time units
*
* @param $time integer: timestamp
*
* @return string
**/
static function getTimestampTimeUnits($time) {
$time = round(abs($time));
$out['second'] = 0;
$out['minute'] = 0;
$out['hour'] = 0;
$out['day'] = 0;
$out['second'] = $time%MINUTE_TIMESTAMP;
$time -= $out['second'];
if ($time > 0) {
$out['minute'] = ($time%HOUR_TIMESTAMP)/MINUTE_TIMESTAMP;
$time -= $out['minute']*MINUTE_TIMESTAMP;
if ($time > 0) {
$out['hour'] = ($time%DAY_TIMESTAMP)/HOUR_TIMESTAMP;
$time -= $out['hour']*HOUR_TIMESTAMP;
if ($time > 0) {
$out['day'] = $time/DAY_TIMESTAMP;
}
}
}
return $out;
}
/**
* Get a web page. Use proxy if configured
*
* @param string $url URL to retrieve
* @param string $msgerr set if problem encountered (default NULL)
* @param integer $rec internal use only Must be 0 (default 0)
*
* @return content of the page (or empty)
**/
static function getURLContent ($url, &$msgerr = null, $rec = 0) {
$content = self::callCurl($url);
return $content;
}
/**
* Executes a curl call
*
* @param string $url URL to retrieve
* @param array $eopts Extra curl opts
* @param string $msgerr set if problem encountered (default NULL)
*
* @return string
*/
public static function callCurl($url, array $eopts = [], &$msgerr = null) {
global $CFG_GLPI;
$content = "";
$taburl = parse_url($url);
$hostscheme = '';
$defaultport = 80;
// Manage standard HTTPS port : scheme detection or port 443
if ((isset($taburl["scheme"]) && $taburl["scheme"]=='https')
|| (isset($taburl["port"]) && $taburl["port"]=='443')) {
$hostscheme = 'ssl://';
$defaultport = 443;
}
$ch = curl_init($url);
$opts = [
CURLOPT_URL => $url,
CURLOPT_USERAGENT => "GLPI/".trim($CFG_GLPI["version"]),
CURLOPT_RETURNTRANSFER => 1
] + $eopts;
if (!empty($CFG_GLPI["proxy_name"])) {
// Connection using proxy
$opts += [
CURLOPT_PROXY => $CFG_GLPI['proxy_name'],
CURLOPT_PROXYPORT => $CFG_GLPI['proxy_port'],
CURLOPT_PROXYTYPE => CURLPROXY_HTTP
];
if (!empty($CFG_GLPI["proxy_user"])) {
$opts += [
CURLOPT_PROXYAUTH => CURLAUTH_BASIC,
CURLOPT_PROXYUSERPWD => $CFG_GLPI["proxy_user"] . ":" . self::decrypt($CFG_GLPI["proxy_passwd"]),
];
}
if ($defaultport == 443) {
$opts += [
CURLOPT_HTTPPROXYTUNNEL => 1
];
}
}
curl_setopt_array($ch, $opts);
$content = curl_exec($ch);
$errstr = curl_error($ch);
curl_close($ch);
if ($errstr) {
if (empty($CFG_GLPI["proxy_name"])) {
//TRANS: %s is the error string
$msgerr = sprintf(
__('Connection failed. If you use a proxy, please configure it. (%s)'),
$errstr
);
} else {
//TRANS: %s is the error string
$msgerr = sprintf(
__('Failed to connect to the proxy server (%s)'),
$errstr
);
}
return '';
}
if (empty($content)) {
$msgerr = __('No data available on the web site');
}
if (!empty($msgerr)) {
Toolbox::logError($msgerr);
}
return $content;
}
/**
* Returns whether this is an AJAX (XMLHttpRequest) request.
*
* @return boolean whether this is an AJAX (XMLHttpRequest) request.
*/
static function isAjax() {
return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest';
}
/**
* @param $need
* @param $tab
**/
static function key_exists_deep($need, $tab) {
foreach ($tab as $key => $value) {
if ($need == $key) {
return true;
}
if (is_array($value)
&& self::key_exists_deep($need, $value)) {
return true;
}
}
return false;
}
/**
* Manage planning posted datas (must have begin + duration or end)
* Compute end if duration is set
*
* @param $data array data to process
*
* @return processed datas
**/
static function manageBeginAndEndPlanDates(&$data) {
if (!isset($data['end'])) {
if (isset($data['begin'])
&& isset($data['_duration'])) {
$begin_timestamp = strtotime($data['begin']);
$data['end'] = date("Y-m-d H:i:s", $begin_timestamp+$data['_duration']);
unset($data['_duration']);
}
}
}
/**
* Manage login redirection
*
* @param $where string: where to redirect ?
**/
static function manageRedirect($where) {
global $CFG_GLPI;
if (!empty($where)) {
if (Session::getCurrentInterface()) {
$decoded_where = rawurldecode($where);
// redirect to URL : URL must be rawurlencoded
if (preg_match('@(([^:/].+:)?//[^/]+)(/.+)?@', $decoded_where, $matches)) {
if ($matches[1] !== $CFG_GLPI['url_base']) {
Session::addMessageAfterRedirect('Redirection failed');
if (Session::getCurrentInterface() === "helpdesk") {
Html::redirect($CFG_GLPI["root_doc"]."/front/helpdesk.public.php");
} else {
Html::redirect($CFG_GLPI["root_doc"]."/front/central.php");
}
} else {
Html::redirect($decoded_where);
}
}
// Redirect based on GLPI_ROOT : URL must be rawurlencoded
if ($decoded_where[0] == '/') {
// echo $decoded_where;exit();
Html::redirect($CFG_GLPI["root_doc"].$decoded_where);
}
$data = explode("_", $where);
$forcetab = '';
// forcetab for simple items
if (isset($data[2])) {
$forcetab = 'forcetab='.$data[2];
}
switch (Session::getCurrentInterface()) {
case "helpdesk" :
switch (strtolower($data[0])) {
// Use for compatibility with old name
case "tracking" :
case "ticket" :
$data[0] = 'Ticket';
// redirect to item
if (isset($data[1])
&& is_numeric($data[1])
&& ($data[1] > 0)) {
// Check entity
if (($item = getItemForItemtype($data[0]))
&& $item->isEntityAssign()) {
if ($item->getFromDB($data[1])) {
if (!Session::haveAccessToEntity($item->getEntityID())) {
Session::changeActiveEntities($item->getEntityID(), 1);
}
}
}
// force redirect to timeline when timeline is enabled and viewing
// Tasks or Followups
$forcetab = str_replace( 'TicketFollowup$1', 'Ticket$1', $forcetab);
$forcetab = str_replace( 'TicketTask$1', 'Ticket$1', $forcetab);
$forcetab = str_replace( 'ITILFollowup$1', 'Ticket$1', $forcetab);
Html::redirect(Ticket::getFormURLWithID($data[1])."&$forcetab");
} else if (!empty($data[0])) { // redirect to list
if ($item = getItemForItemtype($data[0])) {
$searchUrl = $item->getSearchURL();
$searchUrl .= strpos($searchUrl, '?') === false ? '?' : '&';
$searchUrl .= $forcetab;
Html::redirect($searchUrl);
}
}
Html::redirect($CFG_GLPI["root_doc"]."/front/helpdesk.public.php");
break;
case "preference" :
Html::redirect($CFG_GLPI["root_doc"]."/front/preference.php?$forcetab");
break;
case "reservation" :
Html::redirect(Reservation::getFormURLWithID($data[1])."&$forcetab");
break;
default :
Html::redirect($CFG_GLPI["root_doc"]."/front/helpdesk.public.php");
break;
}
break;
case "central" :
switch (strtolower($data[0])) {
case "preference" :
Html::redirect($CFG_GLPI["root_doc"]."/front/preference.php?$forcetab");
break;
// Use for compatibility with old name
// no break
case "tracking" :
$data[0] = "Ticket";
default :
// redirect to item
if (!empty($data[0] )
&& isset($data[1])
&& is_numeric($data[1])
&& ($data[1] > 0)) {
// Check entity
if ($item = getItemForItemtype($data[0])) {
if ($item->isEntityAssign()) {
if ($item->getFromDB($data[1])) {
if (!Session::haveAccessToEntity($item->getEntityID())) {
Session::changeActiveEntities($item->getEntityID(), 1);
}
}
}
// force redirect to timeline when timeline is enabled
$forcetab = str_replace( 'TicketFollowup$1', 'Ticket$1', $forcetab);
$forcetab = str_replace( 'TicketTask$1', 'Ticket$1', $forcetab);
$forcetab = str_replace( 'ITILFollowup$1', 'Ticket$1', $forcetab);
Html::redirect($item->getFormURLWithID($data[1])."&$forcetab");
}
} else if (!empty($data[0])) { // redirect to list
if ($item = getItemForItemtype($data[0])) {
$searchUrl = $item->getSearchURL();
$searchUrl .= strpos($searchUrl, '?') === false ? '?' : '&';
$searchUrl .= $forcetab;
Html::redirect($searchUrl);
}
}
Html::redirect($CFG_GLPI["root_doc"]."/front/central.php");
break;
}
break;
}
}
}
}
/**
* Convert a value in byte, kbyte, megabyte etc...
*
* @param $val string: config value (like 10k, 5M)
*
* @return $val
**/
static function return_bytes_from_ini_vars($val) {
$val = trim($val);
$last = self::strtolower($val[strlen($val)-1]);
$val = (int)$val;
switch ($last) {
// Le modifieur 'G' est disponible depuis PHP 5.1.0
case 'g' :
$val *= 1024;
// no break;
case 'm' :
$val *= 1024;
// no break;
case 'k' :
$val *= 1024;
// no break;
}
return $val;
}
/**
* Parse imap open connect string
*
* @since 0.84
*
* @param $value string: connect string
* @param $forceport boolean: force compute port if not set (false by default)
*
* @return array of parsed arguments (address, port, mailbox, type, ssl, tls, validate-cert
* norsh, secure and debug) : options are empty if not set
* and options have boolean values if set
**/
static function parseMailServerConnectString($value, $forceport = false) {
$tab = [];
if (strstr($value, ":")) {
$tab['address'] = str_replace("{", "", preg_replace("/:.*/", "", $value));
$tab['port'] = preg_replace("/.*:/", "", preg_replace("/\/.*/", "", $value));
} else {
if (strstr($value, "/")) {
$tab['address'] = str_replace("{", "", preg_replace("/\/.*/", "", $value));
} else {
$tab['address'] = str_replace("{", "", preg_replace("/}.*/", "", $value));
}
$tab['port'] = "";
}
$tab['mailbox'] = preg_replace("/.*}/", "", $value);
$tab['type'] = '';
if (strstr($value, "/imap")) {
$tab['type'] = 'imap';
} else if (strstr($value, "/pop")) {
$tab['type'] = 'pop';
}
$tab['ssl'] = false;
if (strstr($value, "/ssl")) {
$tab['ssl'] = true;
}
if ($forceport && empty($tab['port'])) {
if ($tab['type'] == 'pop') {
if ($tab['ssl']) {
$tab['port'] = 110;
} else {
$tab['port'] = 995;
}
}
if ($tab['type'] = 'imap') {
if ($tab['ssl']) {
$tab['port'] = 993;
} else {
$tab['port'] = 143;
}
}
}
$tab['tls'] = '';
if (strstr($value, "/tls")) {
$tab['tls'] = true;
}
if (strstr($value, "/notls")) {
$tab['tls'] = false;
}
$tab['validate-cert'] = '';
if (strstr($value, "/validate-cert")) {
$tab['validate-cert'] = true;
}
if (strstr($value, "/novalidate-cert")) {
$tab['validate-cert'] = false;
}
$tab['norsh'] = '';
if (strstr($value, "/norsh")) {
$tab['norsh'] = true;
}
$tab['secure'] = '';
if (strstr($value, "/secure")) {
$tab['secure'] = true;
}
$tab['debug'] = '';
if (strstr($value, "/debug")) {
$tab['debug'] = true;
}
return $tab;
}
/**
* Display a mail server configuration form
*
* @param $value String host connect string ex
* {localhost:993/imap/ssl}INBOX
*
* @return String type of the server (imap/pop)
**/
static function showMailServerConfig($value) {
if (!Config::canUpdate()) {
return false;
}
$tab = Toolbox::parseMailServerConnectString($value);
echo "<tr class='tab_bg_1'><td>" . __('Server') . "</td>";
echo "<td><input size='30' type='text' name='mail_server' value=\"" .$tab['address']. "\">";
echo "</td></tr>\n";
echo "<tr class='tab_bg_1'><td>" . __('Connection options') . "</td><td>";
$values = [//TRANS: imap_open option see http://www.php.net/manual/en/function.imap-open.php
'/imap' => __('IMAP'),
//TRANS: imap_open option see http://www.php.net/manual/en/function.imap-open.php
'/pop' => __('POP'),];
$svalue = (!empty($tab['type'])?'/'.$tab['type']:'');
Dropdown::showFromArray('server_type', $values,
['value' => $svalue,
'display_emptychoice' => true]);
$values = [//TRANS: imap_open option see http://www.php.net/manual/en/function.imap-open.php
'/ssl' => __('SSL')];
$svalue = ($tab['ssl']?'/ssl':'');
Dropdown::showFromArray('server_ssl', $values,
['value' => $svalue,
'display_emptychoice' => true]);
$values = [//TRANS: imap_open option see http://www.php.net/manual/en/function.imap-open.php
'/tls' => __('TLS'),
//TRANS: imap_open option see http://www.php.net/manual/en/function.imap-open.php
'/notls' => __('NO-TLS'),];
$svalue = '';
if (($tab['tls'] === true)) {
$svalue = '/tls';
}
if (($tab['tls'] === false)) {
$svalue = '/notls';
}
Dropdown::showFromArray('server_tls', $values,
['value' => $svalue,
'width' => '14%',
'display_emptychoice' => true]);
$values = [//TRANS: imap_open option see http://www.php.net/manual/en/function.imap-open.php
'/novalidate-cert' => __('NO-VALIDATE-CERT'),
//TRANS: imap_open option see http://www.php.net/manual/en/function.imap-open.php
'/validate-cert' => __('VALIDATE-CERT'),];
$svalue = '';
if (($tab['validate-cert'] === false)) {
$svalue = '/novalidate-cert';
}
if (($tab['validate-cert'] === true)) {
$svalue = '/validate-cert';
}
Dropdown::showFromArray('server_cert', $values,
['value' => $svalue,
'display_emptychoice' => true]);
$values = [//TRANS: imap_open option see http://www.php.net/manual/en/function.imap-open.php
'/norsh' => __('NORSH')];
$svalue = ($tab['norsh'] === true?'/norsh':'');
Dropdown::showFromArray('server_rsh', $values,
['value' => $svalue,
'display_emptychoice' => true]);
$values = [//TRANS: imap_open option see http://www.php.net/manual/en/function.imap-open.php
'/secure' => __('SECURE')];
$svalue = ($tab['secure'] === true?'/secure':'');
Dropdown::showFromArray('server_secure', $values,
['value' => $svalue,
'display_emptychoice' => true]);
$values = [//TRANS: imap_open option see http://www.php.net/manual/en/function.imap-open.php
'/debug' => __('DEBUG')];
$svalue = ($tab['debug'] === true?'/debug':'');
Dropdown::showFromArray('server_debug', $values,
['value' => $svalue,
'width' => '12%',
'display_emptychoice' => true]);
echo "<input type=hidden name=imap_string value='".$value."'>";
echo "</td></tr>\n";
echo "<tr class='tab_bg_1'><td>". __('Incoming mail folder (optional, often INBOX)')."</td>";
echo "<td>";
echo "<input size='30' type='text' id='server_mailbox' name='server_mailbox' value=\"" . $tab['mailbox'] . "\" >";
echo "<i class='fa fa-list pointer get-imap-folder'></i>";
echo "</td></tr>\n";
//TRANS: for mail connection system
echo "<tr class='tab_bg_1'><td>" . __('Port (optional)') . "</td>";
echo "<td><input size='10' type='text' name='server_port' value='".$tab['port']."'></td></tr>\n";
if (empty($value)) {
$value = "&nbsp;";
}
//TRANS: for mail connection system
echo "<tr class='tab_bg_1'><td>" . __('Connection string') . "</td>";
echo "<td class='b'>$value</td></tr>\n";
return $tab['type'];
}
/**
* @param $input
**/
static function constructMailServerConfig($input) {
$out = "";
if (isset($input['mail_server']) && !empty($input['mail_server'])) {
$out .= "{" . $input['mail_server'];
} else {
return $out;
}
if (isset($input['server_port']) && !empty($input['server_port'])) {
$out .= ":" . $input['server_port'];
}
if (isset($input['server_type']) && !empty($input['server_type'])) {
$out .= $input['server_type'];
}
if (isset($input['server_ssl']) && !empty($input['server_ssl'])) {
$out .= $input['server_ssl'];
}
if (isset($input['server_cert']) && !empty($input['server_cert'])
&& (!empty($input['server_ssl']) || !empty($input['server_tls']))) {
$out .= $input['server_cert'];
}
if (isset($input['server_tls']) && !empty($input['server_tls'])) {
$out .= $input['server_tls'];
}
if (isset($input['server_rsh']) && !empty($input['server_rsh'])) {
$out .= $input['server_rsh'];
}
if (isset($input['server_secure']) && !empty($input['server_secure'])) {
$out .= $input['server_secure'];
}
if (isset($input['server_debug']) && !empty($input['server_debug'])) {
$out .= $input['server_debug'];
}
$out .= "}";
if (isset($input['server_mailbox']) && !empty($input['server_mailbox'])) {
$out .= $input['server_mailbox'];
}
return $out;
}
static function getDaysOfWeekArray() {
$tab[0] = __("Sunday");
$tab[1] = __("Monday");
$tab[2] = __("Tuesday");
$tab[3] = __("Wednesday");
$tab[4] = __("Thursday");
$tab[5] = __("Friday");
$tab[6] = __("Saturday");
return $tab;
}
static function getMonthsOfYearArray() {
$tab[1] = __("January");
$tab[2] = __("February");
$tab[3] = __("March");
$tab[4] = __("April");
$tab[5] = __("May");
$tab[6] = __("June");
$tab[7] = __("July");
$tab[8] = __("August");
$tab[9] = __("September");
$tab[10] = __("October");
$tab[11] = __("November");
$tab[12] = __("December");
return $tab;
}
/**
* Do a in_array search comparing string using strcasecmp
*
* @since 0.84
*
* @param $string string to search
* @param $datas array to search to search
*
* @return boolean : string founded ?
**/
static function inArrayCaseCompare($string, $datas = []) {
if (count($datas)) {
foreach ($datas as $tocheck) {
if (strcasecmp($string, $tocheck) == 0) {
return true;
}
}
}
return false;
}
/**
* Clean integer value (strip all chars not - and spaces )
*
* @since versin 0.83.5
*
* @param $integer string integer string
*
* @return clean integer
**/
static function cleanInteger($integer) {
return preg_replace("/[^0-9-]/", "", $integer);
}
/**
* Clean decimal value (strip all chars not - and spaces )
*
* @since versin 0.83.5
*
* @param $decimal string float string
*
* @return clean integer
**/
static function cleanDecimal($decimal) {
return preg_replace("/[^0-9\.-]/", "", $decimal);
}
/**
* Clean new lines of a string
*
* @since versin 0.85
*
* @param $string string string to clean
*
* @return clean string
**/
static function cleanNewLines($string) {
$string = preg_replace("/\r\n/", " ", $string);
$string = preg_replace("/\n/", " ", $string);
$string = preg_replace("/\r/", " ", $string);
return $string;
}
/**
* Create the GLPI default schema
*
* @since 9.1
*
* @param string $lang Language to install
*
* @return void
**/
static function createSchema($lang = 'en_GB') {
global $CFG_GLPI, $DB;
include_once (GLPI_CONFIG_DIR . "/config_db.php");
$DB = new DB();
if (!$DB->runFile(GLPI_ROOT ."/install/mysql/glpi-empty.sql")) {
echo "Errors occurred inserting default database";
} else {
// update default language
Config::setConfigurationValues(
'core',
[
'language' => $lang,
'version' => GLPI_VERSION,
'dbversion' => GLPI_SCHEMA_VERSION
]
);
if (defined('GLPI_SYSTEM_CRON')) {
// Downstream packages may provide a good system cron
$DB->updateOrDie(
'glpi_crontasks', [
'mode' => 2
], [
'name' => ['!=', 'watcher'],
'allowmode' => ['&', 2]
],
'4203'
);
}
}
}
/**
* Save a configuration file
*
* @since 0.84
*
* @param $name string config file name
* @param $content string config file content
*
* @return boolean
**/
static function writeConfig($name, $content) {
$name = GLPI_CONFIG_DIR . '/'.$name;
$fp = fopen($name, 'wt');
if ($fp) {
$fw = fwrite($fp, $content);
fclose($fp);
if (function_exists('opcache_invalidate')) {
/* Invalidate Zend OPcache to ensure saved version used */
opcache_invalidate($name, true);
}
return ($fw>0);
}
return false;
}
/**
* Prepare array passed on an input form
*
* @param $value array passed array
*
* @since 0.83.91
*
* @return string encoded array
**/
static function prepareArrayForInput(array $value) {
return base64_encode(json_encode($value));
}
/**
* Decode array passed on an input form
*
* @param $value string encoded value
*
* @since 0.83.91
*
* @return string decoded array
**/
static function decodeArrayFromInput($value) {
if ($dec = base64_decode($value)) {
if ($ret = json_decode($dec, true)) {
return $ret;
}
}
return [];
}
/**
* Check valid referer accessing GLPI
*
* @since 0.84.2
*
* @return nothing : display error if not permit
**/
static function checkValidReferer() {
global $CFG_GLPI;
$isvalidReferer = true;
if (!isset($_SERVER['HTTP_REFERER'])) {
if ($_SESSION['glpi_use_mode'] == Session::DEBUG_MODE) {
Html::displayErrorAndDie(__("No HTTP_REFERER found in request. Reload previous page before doing action again."),
true);
$isvalidReferer = false;
}
} else if (!is_array($url = parse_url($_SERVER['HTTP_REFERER']))) {
if ($_SESSION['glpi_use_mode'] == Session::DEBUG_MODE) {
Html::displayErrorAndDie(__("Error when parsing HTTP_REFERER. Reload previous page before doing action again."),
true);
$isvalidReferer = false;
}
}
if (!isset($url['host'])
|| (($url['host'] != $_SERVER['SERVER_NAME'])
&& (!isset($_SERVER['HTTP_X_FORWARDED_SERVER'])
|| ($url['host'] != $_SERVER['HTTP_X_FORWARDED_SERVER'])))) {
if ($_SESSION['glpi_use_mode'] == Session::DEBUG_MODE) {
Html::displayErrorAndDie(__("None or Invalid host in HTTP_REFERER. Reload previous page before doing action again."),
true);
$isvalidReferer = false;
}
}
if (!isset($url['path'])
|| (!empty($CFG_GLPI['root_doc'])
&& (strpos($url['path'], $CFG_GLPI['root_doc']) !== 0))) {
if ($_SESSION['glpi_use_mode'] == Session::DEBUG_MODE) {
Html::displayErrorAndDie(__("None or Invalid path in HTTP_REFERER. Reload previous page before doing action again."),
true);
$isvalidReferer = false;
}
}
if (!$isvalidReferer && $_SESSION['glpi_use_mode'] != Session::DEBUG_MODE) {
Html::displayErrorAndDie(__("The action you have requested is not allowed. Reload previous page before doing action again."),
true);
}
}
/**
* Retrieve the mime type of a file
*
* @since 0.85.5
*
* @param $file string path of the file
* @param $type string check if $file is the correct type (false by default)
*
* @return string (if $type not given) else boolean
*
**/
static function getMime($file, $type = false) {
static $finfo = null;
if (is_null($finfo)) {
$finfo = new finfo(FILEINFO_MIME_TYPE);
}
$mime = $finfo->file($file);
if ($type) {
$parts = explode('/', $mime, 2);
return ($parts[0] == $type);
}
return ($mime);
}
/**
* Summary of in_array_recursive
*
* @since 9.1
*
* @param mixed $needle
* @param array $haystack
* @param bool $strict: If strict is set to TRUE then it will also
* check the types of the needle in the haystack.
* @return bool
*/
static function in_array_recursive($needle, $haystack, $strict = false) {
$it = new RecursiveIteratorIterator(new RecursiveArrayIterator($haystack));
foreach ($it AS $element) {
if ($strict) {
if ($element === $needle) {
return true;
}
} else {
if ($element == $needle) {
return true;
}
}
}
return false;
}
/**
* Sanitize received values
*
* @param array $array
*
* @return array
*/
static public function sanitize($array) {
$array = array_map('Toolbox::addslashes_deep', $array);
$array = array_map('Toolbox::clean_cross_side_scripting_deep', $array);
return $array;
}
/**
* Remove accentued characters and return lower case string
*
* @param string $string String to handle
*
* @return string
*/
public static function removeHtmlSpecialChars($string) {
$string = htmlentities($string, ENT_NOQUOTES, 'utf-8');
$string = preg_replace(
'#&([A-za-z])(?:acute|cedil|caron|circ|grave|orn|ring|slash|th|tilde|uml);#',
'\1',
$string
);
$string = preg_replace('#&([A-za-z]{2})(?:lig);#', '\1', $string);
$string = preg_replace('#&[^;]+;#', '', $string);
return self::strtolower($string, 'UTF-8');
}
/**
* Slugify
*
* @param string $string String to slugify
*
* @return string
*/
public static function slugify($string) {
$string = str_replace(' ', '-', self::strtolower($string, 'UTF-8'));
$string = self::removeHtmlSpecialChars($string);
$string = preg_replace('~[^0-9a-z]+~i', '-', $string);
$string = trim($string, '-');
if ($string == '') {
//prevent empty slugs; see https://github.com/glpi-project/glpi/issues/2946
//harcoded prefix string because html @id must begin with a letter
$string = 'nok_' . Toolbox::getRandomString(10);
} else if (ctype_digit(substr($string, 0, 1))) {
//starts with a number; not ok to be used as an html id attribute
$string = 'slug_' . $string;
}
return $string;
}
/**
* Convert tag to image
*
* @since 9.2
*
* @param string $content_text text content of input
* @param CommonDBTM $item Glpi item where to convert image tag to image document
* @param array $doc_data list of filenames and tags
*
* @return string the $content_text param after parsing
**/
static function convertTagToImage($content_text, CommonDBTM $item, $doc_data = []) {
global $CFG_GLPI;
$document = new Document();
$matches = [];
// If no doc data available we match all tags in content
if (!count($doc_data)) {
preg_match_all('/'.Document::getImageTag('(([a-z0-9]+|[\.\-]?)+)').'/', $content_text,
$matches, PREG_PATTERN_ORDER);
if (isset($matches[1]) && count($matches[1])) {
$doc_data = $document->find(['tag' => array_unique($matches[1])]);
}
}
if (count($doc_data)) {
$base_path = $CFG_GLPI['root_doc'];
if (isCommandLine()) {
$base_path = parse_url($CFG_GLPI['url_base'], PHP_URL_PATH);
}
foreach ($doc_data as $id => $image) {
if (isset($image['tag'])) {
// Add only image files : try to detect mime type
if ($document->getFromDB($id)
&& strpos($document->fields['mime'], 'image/') !== false) {
// append itil object reference in image link
$itil_object = null;
if ($item instanceof CommonITILObject) {
$itil_object = $item;
} else if (isset($item->input['_job'])
&& $item->input['_job'] instanceof CommonITILObject) {
$itil_object = $item->input['_job'];
}
$itil_url_param = null !== $itil_object
? "&{$itil_object->getForeignKeyField()}={$itil_object->fields['id']}"
: "";
$img = "<img alt='".$image['tag']."' src='".$base_path.
"/front/document.send.php?docid=".$id.$itil_url_param."'/>";
// 1 - Replace direct tag (with prefix and suffix) by the image
$content_text = preg_replace('/'.Document::getImageTag($image['tag']).'/',
Html::entities_deep($img), $content_text);
// 2 - Replace img with tag in id attribute by the image
$regex = '/<img[^>]+' . preg_quote($image['tag'], '/') . '[^<]+>/im';
preg_match_all($regex, Html::entity_decode_deep($content_text), $matches);
foreach ($matches[0] as $match_img) {
//retrieve dimensions
$width = $height = null;
preg_match_all('/(width|height)=\\\"([^"]*)\\\"/i', $match_img, $attributes);
if (isset($attributes[1][0])) {
${$attributes[1][0]} = $attributes[2][0];
}
if (isset($attributes[1][1])) {
${$attributes[1][1]} = $attributes[2][1];
}
if ($width == null || $height == null) {
$path = GLPI_DOC_DIR."/".$image['filepath'];
$img_infos = getimagesize($path);
$width = $img_infos[0];
$height = $img_infos[1];
}
// replace image
$new_image = Html::getImageHtmlTagForDocument(
$id,
$width,
$height,
true,
$itil_url_param
);
if (empty($new_image)) {
$new_image = '#'.$image['tag'].'#';
}
$content_text = str_replace(
$match_img,
$new_image,
Html::entity_decode_deep($content_text)
);
$content_text = Html::entities_deep($content_text);
}
// Replace <br> TinyMce bug
$content_text = str_replace(['&gt;rn&lt;','&gt;\r\n&lt;','&gt;\r&lt;','&gt;\n&lt;'],
'&gt;&lt;', $content_text);
// If the tag is from another ticket : link document to ticket
if ($item instanceof Ticket
&& $item->getID()
&& isset($image['tickets_id'])
&& $image['tickets_id'] != $item->getID()) {
$docitem = new Document_Item();
$docitem->add(['documents_id' => $image['id'],
'_do_notif' => false,
'_disablenotif' => true,
'itemtype' => $item->getType(),
'items_id' => $item->fields['id']]);
}
} else {
// Remove tag
$content_text = preg_replace('/'.Document::getImageTag($image['tag']).'/',
'', $content_text);
}
}
}
}
return $content_text;
}
/**
* Convert image to tag
*
* @since 9.2
*
* @param $content_html html content of input
* @param $force_update force update of content in item (false by default)
*
* @return html content
**/
static function convertImageToTag($content_html, $force_update = false) {
if (!empty($content_html)) {
preg_match_all("/alt\s*=\s*['|\"](.+?)['|\"]/", $content_html, $matches, PREG_PATTERN_ORDER);
if (isset($matches[1]) && count($matches[1])) {
// Get all image src
foreach ($matches[1] as $src) {
// Set tag if image matches
$content_html = preg_replace(["/<img.*alt=['|\"]".$src."['|\"][^>]*\>/", "/<object.*alt=['|\"]".$src."['|\"][^>]*\>/"], Document::getImageTag($src), $content_html);
}
}
return $content_html;
}
}
/**
* Delete tag or image from ticket content
*
* @since 9.2
*
* @param string $content html content of input
* @param array $tags list of tags to clen
*
* @return html content
**/
static function cleanTagOrImage($content, array $tags) {
// RICH TEXT : delete img tag
$content = Html::entity_decode_deep($content);
foreach ($tags as $tag) {
$content = preg_replace("/<img.*alt=['|\"]".$tag."['|\"][^>]*\>/", "<p></p>", $content);
}
return $content;
}
/**
* Decode JSON in GLPI
* Because json can have been modified from addslashes_deep
*
* @param string $encoded Encoded JSON
* @param boolean $assoc assoc parameter of json_encode native function
*
* @return mixed
*/
static public function jsonDecode($encoded, $assoc = false) {
if (!is_string($encoded)) {
self::log(null, Logger::NOTICE, ['Only strings can be json to decode!']);
return $encoded;
}
$json = json_decode($encoded, $assoc);
if (json_last_error() != JSON_ERROR_NONE) {
//something went wrong... Try to stripslashes before decoding.
$json = json_decode(self::stripslashes_deep($encoded), $assoc);
if (json_last_error() != JSON_ERROR_NONE) {
self::log(null, Logger::NOTICE, ['Unable to decode JSON string! Is this really JSON?']);
return $encoded;
}
}
return $json;
}
/**
* Checks if a string starts with another one
*
* @since 9.1.5
*
* @param string $haystack String to check
* @param string $needle String to find
*
* @return boolean
*/
static public function startsWith($haystack, $needle) {
$length = strlen($needle);
return (substr($haystack, 0, $length) === $needle);
}
/**
* Checks if a string starts with another one
*
* @since 9.2
*
* @param string $haystack String to check
* @param string $needle String to find
*
* @return boolean
*/
static public function endsWith($haystack, $needle) {
$length = strlen($needle);
return $length === 0 || (substr($haystack, -$length) === $needle);
}
/**
* gets the IP address of the client
*
* @since 9.2
*
* @return string the IP address
*/
public static function getRemoteIpAddress() {
return (isset($_SERVER["HTTP_X_FORWARDED_FOR"]) ?
self::clean_cross_side_scripting_deep($_SERVER["HTTP_X_FORWARDED_FOR"]):
$_SERVER["REMOTE_ADDR"]);
}
/**
* Get available date formats
*
* @since 9.2
*
* @param string $type Type for (either 'php' or 'js')
*
* @return array
*/
public static function getDateFormats($type) {
$formats = [];
switch ($type) {
case 'js':
$formats = [
0 => 'YYYY MMM DD',
1 => 'DD MMM YYYY',
2 => 'MMM DD YYYY'
];
break;
case 'php':
$formats = [
0 => __('YYYY-MM-DD'),
1 => __('DD-MM-YYYY'),
2 => __('MM-DD-YYYY')
];
break;
default: