";
$suberr = Config::checkWriteAccessToDirs();
if ($suberr > $error) {
$error = $suberr;
}
$suberr = self::checkSELinux();
if ($suberr > $error) {
$error = $suberr;
}
return $error;
}
/**
* Check SELinux configuration
*
* @since version 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;
}
$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 "$msg\n";
} else {
echo "
$msg
";
// All modes should be ok
echo "
";
}
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
if (!file_exists('/usr/sbin/getenforce')) {
// should always be there
return 0;
}
$bools = array('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) {
$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 "$msg\n";
} else {
echo "$msg ($msg2)\n";
}
} else {
if (substr($state, -2) == 'on') {
echo "
$msg
";
echo "
".
"
";
} else {
echo "
$msg ($msg2)
";
echo "
".
"
";
$err = 1;
}
echo "
";
}
}
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 = array(__('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
*
* @since version 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);
//resize image
imagecopyresampled($source_dest, $source_res, 0, 0, $img_x, $img_y,
$new_width, $new_height, $img_width, $img_height);
//output img
return imagejpeg($source_dest, $dest_path, 90);
}
/**
* Check if new version is available
*
* @param $auto boolean: check done autically ? (if not display result)
* (true by default)
* @param $messageafterredirect boolean: use message after redirect instead of display
* (false by default)
*
* @return string explaining the result
**/
static function checkNewVersionAvailable($auto=true, $messageafterredirect=false) {
global $CFG_GLPI;
if (!$auto
&& !Session::haveRight('backup', Backup::CHECKUPDATE)) {
return false;
}
if (!$auto && !$messageafterredirect) {
echo " ";
}
//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 = array();
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) {
if (!$auto) {
if ($messageafterredirect) {
Session::addMessageAfterRedirect($error, true, ERROR);
} else {
echo "
$error
";
}
} else {
return $error;
}
} else {
if (version_compare($CFG_GLPI["version"], $latest_version, '<')) {
$config_object = new Config();
$input["id"] = 1;
$input["founded_new_version"] = $latest_version;
$config_object->update($input);
if (!$auto) {
if ($messageafterredirect) {
Session::addMessageAfterRedirect(sprintf(__('A new version is available: %s.'),
$latest_version));
Session::addMessageAfterRedirect(__('You will find it on the GLPI-PROJECT.org site.'));
} else {
echo "
".sprintf(__('A new version is available: %s.'),
$latest_version)."
";
echo "
".__('You will find it on the GLPI-PROJECT.org site.').
"
";
}
} else {
if ($messageafterredirect) {
Session::addMessageAfterRedirect(sprintf(__('A new version is available: %s.'),
$latest_version));
} else {
return sprintf(__('A new version is available: %s.'), $latest_version);
}
}
} else {
if (!$auto) {
if ($messageafterredirect) {
Session::addMessageAfterRedirect(__('You have the latest available version'));
} else {
echo "
".__('You have the latest available version')."
";
}
} else {
if ($messageafterredirect) {
Session::addMessageAfterRedirect(__('You have the latest available 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');
}
/**
* 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 = strtolower($plug['class']);
} else { // Standard case
$item = strtolower($itemtype);
}
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 = strtolower($plug['class']);
} else { // Standard case
if ($itemtype == 'Cartridge') {
$itemtype = 'CartridgeItem';
}
if ($itemtype == 'Consumable') {
$itemtype = 'ConsumableItem';
}
$item = strtolower($itemtype);
}
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 $length integer: length of the random string
*
* @return random string
**/
static function getRandomString($length) {
$alphabet = "1234567890abcdefghijklmnopqrstuvwxyz";
$rndstring = "";
for ($a=0 ; $a<$length ; $a++) {
if (function_exists('random_int')) { // PHP 7+
$b = random_int(0, strlen($alphabet) - 1);
} else {
$b = mt_rand(0, strlen($alphabet) - 1);
}
$rndstring .= $alphabet[$b];
}
return $rndstring;
}
/**
* 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) {
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
];
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,
CURLOPT_HTTPPROXYTUNNEL => 1
];
if (!empty($CFG_GLPI["proxy_user"])) {
$opts += [
CURLOPT_PROXYAUTH => CURLAUTH_BASIC,
CURLOPT_PROXYUSERPWD => $CFG_GLPI["proxy_user"] . ":" . self::decrypt($CFG_GLPI["proxy_passwd"], GLPIKEY)
];
}
}
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');
}
return $content;
}
/**
* @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, $PLUGIN_HOOKS;
if (!empty($where)) {
if (isset($_SESSION["glpiactiveprofile"]["interface"])
&& !empty($_SESSION["glpiactiveprofile"]["interface"])) {
$decoded_where = rawurldecode($where);
// redirect to URL : URL must be rawurlencoded
if ($link = preg_match('/(https?:\/\/[^\/]+)\/.+/',$decoded_where, $matches)) {
if($matches[1] !== $CFG_GLPI['url_base']) {
Session::addMessageAfterRedirect('Redirection failed');
if($_SESSION["glpiactiveprofile"]["interface"] === "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["glpiactiveprofile"]["interface"]) {
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);
}
}
}
if ($_SESSION['glpiticket_timeline'] == 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);
}
Html::redirect($CFG_GLPI["root_doc"]."/front/ticket.form.php?id=".
$data[1]."&$forcetab");
// redirect to list
} else if (!empty($data[0])) {
if ($item = getItemForItemtype($data[0])) {
Html::redirect($item->getSearchURL()."?$forcetab");
}
}
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($CFG_GLPI["root_doc"]."/front/reservation.form.php?id=".
$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);
}
}
}
if ($_SESSION['glpiticket_timeline'] == 1 && $item->getType() == 'Ticket') {
// force redirect to timeline when timeline is enabled
$forcetab = str_replace( 'TicketFollowup$1', 'Ticket$1', $forcetab);
$forcetab = str_replace( 'TicketTask$1', 'Ticket$1', $forcetab);
}
Html::redirect($item->getFormURL()."?id=".$data[1]."&$forcetab");
}
// redirect to list
} else if (!empty($data[0])) {
if ($item = getItemForItemtype($data[0])) {
Html::redirect($item->getSearchURL()."?$forcetab");
}
}
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 version 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 = array();
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 "