2010-12-16 09:29:49 +00:00
|
|
|
|
<?php
|
|
|
|
|
// MyDMS. Document Management System
|
|
|
|
|
// Copyright (C) 2002-2005 Markus Westphal
|
2010-10-29 13:19:51 +00:00
|
|
|
|
// Copyright (C) 2006-2008 Malcolm Cowe
|
2010-12-16 09:29:49 +00:00
|
|
|
|
// Copyright (C) 2010 Matteo Lucarelli
|
|
|
|
|
//
|
|
|
|
|
// This program 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.
|
|
|
|
|
//
|
|
|
|
|
// This program 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 this program; if not, write to the Free Software
|
|
|
|
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
2010-10-29 13:19:51 +00:00
|
|
|
|
|
2020-12-17 10:42:20 +00:00
|
|
|
|
/* Date picker needs a different syntax for date formats using
|
|
|
|
|
* yyyy for %Y
|
|
|
|
|
* yy for %y
|
|
|
|
|
* mm for %m
|
|
|
|
|
* dd for %d
|
|
|
|
|
* This functions returns the converted format
|
|
|
|
|
*/
|
2023-09-29 12:29:44 +00:00
|
|
|
|
function getConvertDateFormat($dateformat) { /* {{{ */
|
2020-12-01 17:25:22 +00:00
|
|
|
|
global $settings;
|
2023-09-29 12:29:44 +00:00
|
|
|
|
if(!$dateformat)
|
|
|
|
|
$dateformat = $settings->_dateformat;
|
|
|
|
|
if($dateformat) {
|
2020-12-17 10:42:20 +00:00
|
|
|
|
return str_replace(['y', 'Y', 'm', 'M', 'F', 'd', 'l', 'D'], ['yy', 'yyyy', 'mm', 'M', 'MM', 'dd', 'DD', 'D'], $settings->_dateformat);
|
|
|
|
|
} else
|
|
|
|
|
return 'yyyy-mm-dd';
|
2021-02-24 12:22:03 +00:00
|
|
|
|
} /* }}} */
|
2020-12-17 10:42:20 +00:00
|
|
|
|
|
2022-04-29 16:29:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* Return a human readable date string
|
|
|
|
|
*
|
|
|
|
|
* This function formats a timestamp according to the date format
|
|
|
|
|
* settings. If no timestamp is passed the current date is used.
|
|
|
|
|
* If null or an empty string is passed, then an empty string
|
|
|
|
|
* is returned. If $timestamp is numeric it will be taken as a unix
|
|
|
|
|
* timestamp. If $timestamp is a string it will be parѕed with strtotime().
|
|
|
|
|
*/
|
2020-12-17 12:40:04 +00:00
|
|
|
|
function getReadableDate($timestamp=0) { /* {{{ */
|
2020-12-01 17:25:22 +00:00
|
|
|
|
global $settings;
|
2022-04-29 16:29:17 +00:00
|
|
|
|
if($timestamp === 0)
|
2020-12-17 12:40:04 +00:00
|
|
|
|
$timestamp = time();
|
2022-04-30 12:10:51 +00:00
|
|
|
|
elseif($timestamp && is_numeric($timestamp))
|
|
|
|
|
;
|
2022-04-29 16:29:17 +00:00
|
|
|
|
elseif($timestamp && is_string($timestamp))
|
2020-12-01 17:33:30 +00:00
|
|
|
|
$timestamp = strtotime($timestamp);
|
2022-04-29 16:29:17 +00:00
|
|
|
|
elseif(!is_numeric($timestamp))
|
|
|
|
|
return '';
|
2020-12-01 17:25:22 +00:00
|
|
|
|
if($settings->_dateformat)
|
|
|
|
|
return date($settings->_dateformat, $timestamp);
|
|
|
|
|
else
|
|
|
|
|
return date("Y-m-d", $timestamp);
|
2016-02-26 07:17:30 +00:00
|
|
|
|
} /* }}} */
|
2010-10-29 13:19:51 +00:00
|
|
|
|
|
2022-05-02 09:45:32 +00:00
|
|
|
|
/**
|
|
|
|
|
* Return a human readable date and time string
|
|
|
|
|
*
|
|
|
|
|
* See note for getReadableDate()
|
|
|
|
|
*/
|
|
|
|
|
function getLongReadableDate($timestamp=0) { /* {{{ */
|
2020-12-01 17:25:22 +00:00
|
|
|
|
global $settings;
|
2022-05-02 09:45:32 +00:00
|
|
|
|
if($timestamp === 0)
|
|
|
|
|
$timestamp = time();
|
|
|
|
|
elseif($timestamp && is_numeric($timestamp))
|
|
|
|
|
;
|
|
|
|
|
elseif($timestamp && is_string($timestamp))
|
2020-12-01 17:33:30 +00:00
|
|
|
|
$timestamp = strtotime($timestamp);
|
2022-05-02 09:45:32 +00:00
|
|
|
|
elseif(!is_numeric($timestamp))
|
|
|
|
|
return '';
|
2022-05-31 18:05:38 +00:00
|
|
|
|
if($settings->_datetimeformat)
|
2020-12-01 17:25:22 +00:00
|
|
|
|
return date($settings->_datetimeformat, $timestamp);
|
|
|
|
|
else
|
|
|
|
|
return date("Y-m-d H:i:s", $timestamp);
|
2016-02-26 07:17:30 +00:00
|
|
|
|
} /* }}} */
|
2010-10-29 13:19:51 +00:00
|
|
|
|
|
2020-12-07 09:24:30 +00:00
|
|
|
|
function getPeriodOfTime($timestamp) { /* {{{ */
|
|
|
|
|
if(!is_numeric($timestamp))
|
|
|
|
|
$timestamp = strtotime($timestamp);
|
|
|
|
|
|
|
|
|
|
$time = time() - $timestamp; // to get the time since that moment
|
|
|
|
|
$time = ($time<1)? 1 : $time;
|
|
|
|
|
$tokens = array (
|
2020-12-07 19:43:27 +00:00
|
|
|
|
31536000 => 'abbr_year',
|
|
|
|
|
2592000 => 'abbr_month',
|
|
|
|
|
604800 => 'abbr_week',
|
|
|
|
|
86400 => 'abbr_day',
|
|
|
|
|
3600 => 'abbr_hour',
|
|
|
|
|
60 => 'abbr_minute',
|
|
|
|
|
1 => 'abbr_second'
|
2020-12-07 09:24:30 +00:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
foreach ($tokens as $unit => $text) {
|
|
|
|
|
if ($time < $unit) continue;
|
|
|
|
|
$numberOfUnits = floor($time / $unit);
|
2020-12-07 19:43:27 +00:00
|
|
|
|
return $numberOfUnits.' '.(($numberOfUnits>1) ? getMLText($text):getMLText($text));
|
2020-12-07 09:24:30 +00:00
|
|
|
|
}
|
|
|
|
|
} /* }}} */
|
|
|
|
|
|
2020-12-17 12:40:04 +00:00
|
|
|
|
/*
|
|
|
|
|
* Converts a date string into a timestamp
|
|
|
|
|
*
|
|
|
|
|
* @param $date string date in format understood by strftime
|
|
|
|
|
* @return integer/boolean unix timestamp or false in case of an error
|
|
|
|
|
*/
|
|
|
|
|
function makeTsFromDate($date) { /* {{{ */
|
|
|
|
|
return strtotime($date);
|
|
|
|
|
} /* }}} */
|
|
|
|
|
|
2014-11-14 19:22:30 +00:00
|
|
|
|
/*
|
|
|
|
|
* Converts a date/time string into a timestamp
|
|
|
|
|
*
|
|
|
|
|
* @param $date string date in form Y-m-d H:i:s
|
|
|
|
|
* @return integer/boolean unix timestamp or false in case of an error
|
|
|
|
|
*/
|
2015-07-28 05:28:34 +00:00
|
|
|
|
function makeTsFromLongDate($date) { /* {{{ */
|
2020-12-17 12:40:04 +00:00
|
|
|
|
return strtotime($date);
|
2014-11-14 19:22:30 +00:00
|
|
|
|
$tmp = explode(' ', $date);
|
|
|
|
|
if(count($tmp) != 2)
|
|
|
|
|
return false;
|
|
|
|
|
$tarr = explode(':', $tmp[1]);
|
|
|
|
|
$darr = explode('-', $tmp[0]);
|
|
|
|
|
if(count($tarr) != 3 || count($darr) != 3)
|
|
|
|
|
return false;
|
|
|
|
|
$ts = mktime($tarr[0], $tarr[1], $tarr[2], $darr[1], $darr[2], $darr[0]);
|
|
|
|
|
return $ts;
|
|
|
|
|
} /* }}} */
|
|
|
|
|
|
2016-02-26 07:17:30 +00:00
|
|
|
|
function getReadableDuration($secs) { /* {{{ */
|
2013-01-24 08:34:59 +00:00
|
|
|
|
$s = "";
|
|
|
|
|
foreach ( getReadableDurationArray($secs) as $k => $v ) {
|
|
|
|
|
if ( $v ) $s .= $v." ".($v==1? substr($k,0,-1) : $k).", ";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return substr($s, 0, -2);
|
2016-02-26 07:17:30 +00:00
|
|
|
|
} /* }}} */
|
2013-01-24 08:34:59 +00:00
|
|
|
|
|
2016-02-26 07:17:30 +00:00
|
|
|
|
function getReadableDurationArray($secs) { /* {{{ */
|
2013-01-24 08:34:59 +00:00
|
|
|
|
$units = array(
|
2014-11-14 19:22:30 +00:00
|
|
|
|
getMLText("weeks") => 7*24*3600,
|
|
|
|
|
getMLText("days") => 24*3600,
|
|
|
|
|
getMLText("hours") => 3600,
|
|
|
|
|
getMLText("minutes") => 60,
|
|
|
|
|
getMLText("seconds") => 1,
|
2013-01-24 08:34:59 +00:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
foreach ( $units as &$unit ) {
|
|
|
|
|
$quot = intval($secs / $unit);
|
|
|
|
|
$secs -= $quot * $unit;
|
|
|
|
|
$unit = $quot;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $units;
|
2016-02-26 07:17:30 +00:00
|
|
|
|
} /* }}} */
|
2013-01-24 08:34:59 +00:00
|
|
|
|
|
2023-09-29 12:29:30 +00:00
|
|
|
|
/**
|
|
|
|
|
* Return the timestamp after a period of time
|
|
|
|
|
*
|
|
|
|
|
* The period is relative to $start. $r sets if the returned
|
|
|
|
|
* time stamp is the start, end or current seconds of day.
|
|
|
|
|
* getTsByPeriod('today', 's') returns 00:00:00 of today
|
|
|
|
|
* getTsByPeriod('tomorrow', 'e') returns 23:59:59 of tommorrow
|
|
|
|
|
* The parameter $start can be any timestamp from where the
|
|
|
|
|
* period starts
|
|
|
|
|
* getTsByPeriod('today', 's', time()+7*86400) is equivalent to
|
|
|
|
|
* getTsByPeriod('1w', 's')
|
|
|
|
|
*/
|
|
|
|
|
function getTsByPeriod($period, $r='', $start=0) { /* {{{ */
|
|
|
|
|
if(!$start)
|
|
|
|
|
$start = time();
|
|
|
|
|
$sofd = time() - strtotime('today'); // seconds elapsed today
|
|
|
|
|
switch($r) {
|
|
|
|
|
case 's': // start of day
|
|
|
|
|
$o = $sofd;
|
|
|
|
|
break;
|
|
|
|
|
case 'e': // end of day
|
|
|
|
|
$o = $sofd-86400+1;
|
|
|
|
|
break;
|
|
|
|
|
default: // same sec as current time
|
|
|
|
|
$o = 0;
|
|
|
|
|
}
|
|
|
|
|
switch($period) {
|
|
|
|
|
case "never":
|
|
|
|
|
$expiration = 0;
|
|
|
|
|
break;
|
|
|
|
|
case "1h":
|
|
|
|
|
$expiration = $start+3600;
|
|
|
|
|
break;
|
|
|
|
|
case "2h":
|
|
|
|
|
$expiration = $start+7200;
|
|
|
|
|
break;
|
|
|
|
|
case "24h":
|
|
|
|
|
$expiration = $start+86400;
|
|
|
|
|
break;
|
|
|
|
|
case "today":
|
|
|
|
|
$expiration = $start - $o;
|
|
|
|
|
break;
|
|
|
|
|
case "1d":
|
|
|
|
|
$expiration = $start-$o+86400;
|
|
|
|
|
break;
|
|
|
|
|
case "tomorrow":
|
|
|
|
|
$expiration = $start - $o + 86400;
|
|
|
|
|
break;
|
|
|
|
|
case "1w":
|
|
|
|
|
$expiration = $start-$o+7*86400;
|
|
|
|
|
break;
|
|
|
|
|
case "1m":
|
|
|
|
|
$tmp = explode('-', date('Y-m-d', $start));
|
|
|
|
|
$expiration = mktime(0,0,0, $tmp[1]+1, $tmp[2], $tmp[0])+$sofd-$o;
|
|
|
|
|
break;
|
|
|
|
|
case "1y":
|
|
|
|
|
$tmp = explode('-', date('Y-m-d', $start));
|
|
|
|
|
$expiration = mktime(0,0,0, $tmp[1], $tmp[2], $tmp[0]+1)+$sofd-$o;
|
|
|
|
|
break;
|
|
|
|
|
case "2y":
|
|
|
|
|
$tmp = explode('-', date('Y-m-d', $start));
|
|
|
|
|
$expiration = mktime(0,0,0, $tmp[1], $tmp[2], $tmp[0]+2)+$sofd-$o;
|
|
|
|
|
break;
|
|
|
|
|
case "3y":
|
|
|
|
|
$tmp = explode('-', date('Y-m-d', $start));
|
|
|
|
|
$expiration = mktime(0,0,0, $tmp[1], $tmp[2], $tmp[0]+3)+$sofd-$o;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
$expiration = false;
|
|
|
|
|
}
|
|
|
|
|
return $expiration;
|
|
|
|
|
} /* }}} */
|
|
|
|
|
|
2013-02-20 08:46:08 +00:00
|
|
|
|
/* Deprecated, do not use anymore, but keep it for upgrading
|
|
|
|
|
* older versions
|
|
|
|
|
*/
|
2010-12-16 09:29:49 +00:00
|
|
|
|
function mydmsDecodeString($string) { /* {{{ */
|
|
|
|
|
|
|
|
|
|
$string = (string)$string;
|
|
|
|
|
|
|
|
|
|
$string = str_replace("&", "&", $string);
|
|
|
|
|
$string = str_replace("%", "%", $string); // percent
|
|
|
|
|
$string = str_replace(""", "\"", $string); // double quote
|
|
|
|
|
$string = str_replace("/*", "/*", $string); // start of comment
|
|
|
|
|
$string = str_replace("*/", "*/", $string); // end of comment
|
|
|
|
|
$string = str_replace("<", "<", $string);
|
|
|
|
|
$string = str_replace(">", ">", $string);
|
|
|
|
|
$string = str_replace("=", "=", $string);
|
|
|
|
|
$string = str_replace(")", ")", $string);
|
|
|
|
|
$string = str_replace("(", "(", $string);
|
|
|
|
|
$string = str_replace("'", "'", $string);
|
|
|
|
|
$string = str_replace("+", "+", $string);
|
|
|
|
|
|
|
|
|
|
return $string;
|
|
|
|
|
} /* }}} */
|
|
|
|
|
|
|
|
|
|
function createVersionigFile($document) { /* {{{ */
|
|
|
|
|
global $settings, $dms;
|
2017-07-19 17:14:28 +00:00
|
|
|
|
|
2010-10-29 13:19:51 +00:00
|
|
|
|
// if directory has been removed recreate it
|
2011-01-28 07:41:26 +00:00
|
|
|
|
if (!file_exists($dms->contentDir . $document->getDir()))
|
2013-02-14 11:10:53 +00:00
|
|
|
|
if (!SeedDMS_Core_File::makeDir($dms->contentDir . $document->getDir())) return false;
|
2017-07-19 17:14:28 +00:00
|
|
|
|
|
2011-01-28 07:41:26 +00:00
|
|
|
|
$handle = fopen($dms->contentDir . $document->getDir() .$settings-> _versioningFileName , "wb");
|
2017-07-19 17:14:28 +00:00
|
|
|
|
|
2010-10-29 13:19:51 +00:00
|
|
|
|
if (is_bool($handle)&&!$handle) return false;
|
2017-07-19 17:14:28 +00:00
|
|
|
|
|
2014-02-21 10:05:49 +00:00
|
|
|
|
$tmp = $document->getName()." (ID ".$document->getID().")\n\n";
|
2010-10-29 13:19:51 +00:00
|
|
|
|
fwrite($handle, $tmp);
|
|
|
|
|
|
|
|
|
|
$owner = $document->getOwner();
|
|
|
|
|
$tmp = getMLText("owner")." = ".$owner->getFullName()." <".$owner->getEmail().">\n";
|
|
|
|
|
fwrite($handle, $tmp);
|
2017-07-19 17:14:28 +00:00
|
|
|
|
|
2010-12-16 09:29:49 +00:00
|
|
|
|
$tmp = getMLText("creation_date")." = ".getLongReadableDate($document->getDate())."\n";
|
2010-10-29 13:19:51 +00:00
|
|
|
|
fwrite($handle, $tmp);
|
2017-07-19 17:14:28 +00:00
|
|
|
|
|
2010-10-29 13:19:51 +00:00
|
|
|
|
$latestContent = $document->getLatestContent();
|
|
|
|
|
$tmp = "\n### ".getMLText("current_version")." ###\n\n";
|
|
|
|
|
fwrite($handle, $tmp);
|
2017-07-19 17:14:28 +00:00
|
|
|
|
|
2010-10-29 13:19:51 +00:00
|
|
|
|
$tmp = getMLText("version")." = ".$latestContent->getVersion()."\n";
|
2017-07-19 17:14:28 +00:00
|
|
|
|
fwrite($handle, $tmp);
|
|
|
|
|
|
2010-10-29 13:19:51 +00:00
|
|
|
|
$tmp = getMLText("file")." = ".$latestContent->getOriginalFileName()." (".$latestContent->getMimeType().")\n";
|
|
|
|
|
fwrite($handle, $tmp);
|
2017-07-19 17:14:28 +00:00
|
|
|
|
|
2011-12-05 14:52:05 +00:00
|
|
|
|
$tmp = getMLText("comment")." = ". $latestContent->getComment()."\n";
|
2010-10-29 13:19:51 +00:00
|
|
|
|
fwrite($handle, $tmp);
|
2017-07-19 17:14:28 +00:00
|
|
|
|
|
2010-12-16 09:29:49 +00:00
|
|
|
|
$status = $latestContent->getStatus();
|
2010-10-29 13:19:51 +00:00
|
|
|
|
$tmp = getMLText("status")." = ".getOverallStatusText($status["status"])."\n";
|
|
|
|
|
fwrite($handle, $tmp);
|
2017-07-19 17:14:28 +00:00
|
|
|
|
|
2010-10-29 13:19:51 +00:00
|
|
|
|
$reviewStatus = $latestContent->getReviewStatus();
|
|
|
|
|
$tmp = "\n### ".getMLText("reviewers")." ###\n";
|
|
|
|
|
fwrite($handle, $tmp);
|
2017-07-19 17:14:28 +00:00
|
|
|
|
|
2010-10-29 13:19:51 +00:00
|
|
|
|
foreach ($reviewStatus as $r) {
|
2017-07-19 17:14:28 +00:00
|
|
|
|
|
2010-12-16 09:29:49 +00:00
|
|
|
|
switch ($r["type"]) {
|
|
|
|
|
case 0: // Reviewer is an individual.
|
|
|
|
|
$required = $dms->getUser($r["required"]);
|
|
|
|
|
if (!is_object($required)) $reqName = getMLText("unknown_user")." = ".$r["required"];
|
|
|
|
|
else $reqName = getMLText("user")." = ".$required->getFullName();
|
|
|
|
|
break;
|
|
|
|
|
case 1: // Reviewer is a group.
|
|
|
|
|
$required = $dms->getGroup($r["required"]);
|
|
|
|
|
if (!is_object($required)) $reqName = getMLText("unknown_group")." = ".$r["required"];
|
|
|
|
|
else $reqName = getMLText("group")." = ".$required->getName();
|
2010-10-29 13:19:51 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$tmp = "\n".$reqName."\n";
|
|
|
|
|
fwrite($handle, $tmp);
|
2017-07-19 17:14:28 +00:00
|
|
|
|
|
2010-10-29 13:19:51 +00:00
|
|
|
|
$tmp = getMLText("status")." = ".getReviewStatusText($r["status"])."\n";
|
|
|
|
|
fwrite($handle, $tmp);
|
2017-07-19 17:14:28 +00:00
|
|
|
|
|
2011-12-05 14:52:05 +00:00
|
|
|
|
$tmp = getMLText("comment")." = ". $r["comment"]."\n";
|
2010-10-29 13:19:51 +00:00
|
|
|
|
fwrite($handle, $tmp);
|
2017-07-19 17:14:28 +00:00
|
|
|
|
|
2010-10-29 13:19:51 +00:00
|
|
|
|
$tmp = getMLText("last_update")." = ".$r["date"]."\n";
|
|
|
|
|
fwrite($handle, $tmp);
|
|
|
|
|
|
|
|
|
|
}
|
2017-07-19 17:14:28 +00:00
|
|
|
|
|
|
|
|
|
|
2010-10-29 13:19:51 +00:00
|
|
|
|
$approvalStatus = $latestContent->getApprovalStatus();
|
|
|
|
|
$tmp = "\n### ".getMLText("approvers")." ###\n";
|
|
|
|
|
fwrite($handle, $tmp);
|
|
|
|
|
|
|
|
|
|
foreach ($approvalStatus as $r) {
|
2017-07-19 17:14:28 +00:00
|
|
|
|
|
2010-12-16 09:29:49 +00:00
|
|
|
|
switch ($r["type"]) {
|
|
|
|
|
case 0: // Reviewer is an individual.
|
|
|
|
|
$required = $dms->getUser($r["required"]);
|
|
|
|
|
if (!is_object($required)) $reqName = getMLText("unknown_user")." = ".$r["required"];
|
|
|
|
|
else $reqName = getMLText("user")." = ".$required->getFullName();
|
|
|
|
|
break;
|
|
|
|
|
case 1: // Reviewer is a group.
|
|
|
|
|
$required = $dms->getGroup($r["required"]);
|
|
|
|
|
if (!is_object($required)) $reqName = getMLText("unknown_group")." = ".$r["required"];
|
|
|
|
|
else $reqName = getMLText("group")." = ".$required->getName();
|
2010-10-29 13:19:51 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$tmp = "\n".$reqName."\n";
|
|
|
|
|
fwrite($handle, $tmp);
|
2017-07-19 17:14:28 +00:00
|
|
|
|
|
2010-10-29 13:19:51 +00:00
|
|
|
|
$tmp = getMLText("status")." = ".getApprovalStatusText($r["status"])."\n";
|
|
|
|
|
fwrite($handle, $tmp);
|
2017-07-19 17:14:28 +00:00
|
|
|
|
|
2011-12-05 14:52:05 +00:00
|
|
|
|
$tmp = getMLText("comment")." = ". $r["comment"]."\n";
|
2010-10-29 13:19:51 +00:00
|
|
|
|
fwrite($handle, $tmp);
|
2017-07-19 17:14:28 +00:00
|
|
|
|
|
2010-10-29 13:19:51 +00:00
|
|
|
|
$tmp = getMLText("last_update")." = ".$r["date"]."\n";
|
|
|
|
|
fwrite($handle, $tmp);
|
2017-07-19 17:14:28 +00:00
|
|
|
|
|
2010-10-29 13:19:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-07-19 17:14:28 +00:00
|
|
|
|
$versions = $document->getContent();
|
2010-10-29 13:19:51 +00:00
|
|
|
|
$tmp = "\n### ".getMLText("previous_versions")." ###\n";
|
|
|
|
|
fwrite($handle, $tmp);
|
2010-12-16 09:29:49 +00:00
|
|
|
|
|
2010-10-29 13:19:51 +00:00
|
|
|
|
for ($i = count($versions)-2; $i >= 0; $i--){
|
2017-07-19 17:14:28 +00:00
|
|
|
|
|
2010-12-16 09:29:49 +00:00
|
|
|
|
$version = $versions[$i];
|
2017-07-19 17:14:28 +00:00
|
|
|
|
$status = $version->getStatus();
|
|
|
|
|
|
2010-10-29 13:19:51 +00:00
|
|
|
|
$tmp = "\n".getMLText("version")." = ".$version->getVersion()."\n";
|
2017-07-19 17:14:28 +00:00
|
|
|
|
fwrite($handle, $tmp);
|
|
|
|
|
|
2010-10-29 13:19:51 +00:00
|
|
|
|
$tmp = getMLText("file")." = ".$version->getOriginalFileName()." (".$version->getMimeType().")\n";
|
|
|
|
|
fwrite($handle, $tmp);
|
2017-07-19 17:14:28 +00:00
|
|
|
|
|
2011-12-05 14:52:05 +00:00
|
|
|
|
$tmp = getMLText("comment")." = ". $version->getComment()."\n";
|
2010-10-29 13:19:51 +00:00
|
|
|
|
fwrite($handle, $tmp);
|
2017-07-19 17:14:28 +00:00
|
|
|
|
|
2010-12-16 09:29:49 +00:00
|
|
|
|
$status = $latestContent->getStatus();
|
2010-10-29 13:19:51 +00:00
|
|
|
|
$tmp = getMLText("status")." = ".getOverallStatusText($status["status"])."\n";
|
|
|
|
|
fwrite($handle, $tmp);
|
2017-07-19 17:14:28 +00:00
|
|
|
|
|
2010-10-29 13:19:51 +00:00
|
|
|
|
}
|
2017-07-19 17:14:28 +00:00
|
|
|
|
|
2010-10-29 13:19:51 +00:00
|
|
|
|
fclose($handle);
|
|
|
|
|
return true;
|
2010-12-16 09:29:49 +00:00
|
|
|
|
} /* }}} */
|
2010-10-29 13:19:51 +00:00
|
|
|
|
|
2014-05-16 10:48:37 +00:00
|
|
|
|
/**
|
|
|
|
|
* Calculate disk space of file or directory
|
|
|
|
|
*
|
|
|
|
|
* original funcion by shalless at rubix dot net dot au (php.net)
|
|
|
|
|
* stat() replace by filesize() to make it work on all platforms.
|
|
|
|
|
*
|
|
|
|
|
* @param string $dir directory or filename
|
|
|
|
|
* @return integer number of bytes
|
|
|
|
|
*/
|
2012-12-13 21:32:05 +00:00
|
|
|
|
function dskspace($dir) { /* {{{ */
|
2014-05-16 10:48:37 +00:00
|
|
|
|
$space = 0;
|
|
|
|
|
if(is_file($dir)) {
|
|
|
|
|
$space = filesize($dir);
|
|
|
|
|
} elseif (is_dir($dir)) {
|
2015-07-28 05:50:37 +00:00
|
|
|
|
if($dh = opendir($dir)) {
|
|
|
|
|
while (($file = readdir($dh)) !== false)
|
|
|
|
|
if ($file != "." and $file != "..")
|
|
|
|
|
$space += dskspace($dir."/".$file);
|
|
|
|
|
closedir($dh);
|
|
|
|
|
}
|
2014-05-16 10:48:37 +00:00
|
|
|
|
}
|
|
|
|
|
return $space;
|
2012-12-13 21:32:05 +00:00
|
|
|
|
} /* }}} */
|
|
|
|
|
|
2017-03-03 07:53:26 +00:00
|
|
|
|
/**
|
|
|
|
|
* Replacement of PHP's basename function
|
|
|
|
|
*
|
|
|
|
|
* Because basename is locale dependent and strips off non ascii chars
|
|
|
|
|
* from the beginning of filename, it cannot be used in a environment
|
|
|
|
|
* where locale is set to e.g. 'C'
|
|
|
|
|
*/
|
|
|
|
|
function utf8_basename($path, $suffix='') { /* {{{ */
|
|
|
|
|
$rpos = strrpos($path, DIRECTORY_SEPARATOR);
|
|
|
|
|
if($rpos === false)
|
|
|
|
|
return $path;
|
|
|
|
|
$file = substr($path, $rpos+1);
|
|
|
|
|
|
|
|
|
|
$suflen = strlen($suffix);
|
|
|
|
|
if($suflen && (substr($file, -$suflen) == $suffix)){
|
|
|
|
|
$file = substr($file, 0, -$suflen);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $file;
|
|
|
|
|
} /* }}} */
|
|
|
|
|
|
2022-09-07 06:56:08 +00:00
|
|
|
|
/**
|
|
|
|
|
* Return a valid file name
|
|
|
|
|
*
|
|
|
|
|
* This function returns a valid file name for the given document content
|
|
|
|
|
* or an arbitrary string. If a document content is given the name of
|
|
|
|
|
* the document will be used. The extension of the file name will be
|
|
|
|
|
* either taken from the document name or the original file. If the two
|
|
|
|
|
* differ the extension from the original file name will be used.
|
|
|
|
|
*
|
|
|
|
|
* @param object|string $content document content or an arbitrary string
|
|
|
|
|
* @return string valid file name
|
|
|
|
|
*/
|
|
|
|
|
function getFilenameByDocname($content) { /* {{{ */
|
2023-02-28 09:44:25 +00:00
|
|
|
|
if(is_string($content)) {
|
2022-09-07 06:56:08 +00:00
|
|
|
|
$filename = $content;
|
|
|
|
|
} else {
|
|
|
|
|
$document = $content->getDocument();
|
|
|
|
|
$ext = pathinfo($document->getName(), PATHINFO_EXTENSION);
|
|
|
|
|
$oext = pathinfo($content->getOriginalFileName(), PATHINFO_EXTENSION);
|
|
|
|
|
if($ext == $oext)
|
|
|
|
|
$filename = $document->getName();
|
|
|
|
|
else {
|
|
|
|
|
$filename = $document->getName().'.'.$oext;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return mb_ereg_replace("([^\w\s\d\-_~,;\[\]\(\).])", '', $filename);
|
|
|
|
|
} /* }}} */
|
|
|
|
|
|
2022-11-08 19:07:08 +00:00
|
|
|
|
function getLogger($prefix='', $mask=PEAR_LOG_INFO) { /* {{{ */
|
2022-04-07 12:38:32 +00:00
|
|
|
|
global $settings;
|
|
|
|
|
|
|
|
|
|
if($settings->_logFileEnable) {
|
|
|
|
|
if ($settings->_logFileRotation=="h") $logname=date("YmdH", time());
|
|
|
|
|
else if ($settings->_logFileRotation=="d") $logname=date("Ymd", time());
|
|
|
|
|
else $logname=date("Ym", time());
|
|
|
|
|
$logname = $settings->_contentDir."log/".$prefix.$logname.".log";
|
|
|
|
|
if(!file_exists($settings->_contentDir.'log'))
|
|
|
|
|
@mkdir($settings->_contentDir.'log');
|
|
|
|
|
if(file_exists($settings->_contentDir.'log') && is_dir($settings->_contentDir.'log')) {
|
|
|
|
|
$logger = Log::factory('file', $logname);
|
2022-11-08 19:07:08 +00:00
|
|
|
|
$logger->setMask(Log::MAX($mask));
|
2022-04-07 12:38:32 +00:00
|
|
|
|
} else
|
|
|
|
|
$logger = null;
|
|
|
|
|
} else {
|
|
|
|
|
$logger = null;
|
|
|
|
|
}
|
|
|
|
|
return $logger;
|
|
|
|
|
} /* }}} */
|
|
|
|
|
|
2013-10-06 10:27:54 +00:00
|
|
|
|
/**
|
|
|
|
|
* Log a message
|
|
|
|
|
*
|
|
|
|
|
* This function is still here for convienice and because it is
|
|
|
|
|
* used at so many places.
|
|
|
|
|
*
|
|
|
|
|
* @param string $msg
|
|
|
|
|
* @param int $priority can be one of PEAR_LOG_EMERG, PEAR_LOG_ALERT,
|
|
|
|
|
* PEAR_LOG_CRIT, PEAR_LOG_ERR, PEAR_LOG_WARNING,
|
|
|
|
|
* PEAR_LOG_NOTICE, PEAR_LOG_INFO, and PEAR_LOG_DEBUG.
|
|
|
|
|
*/
|
|
|
|
|
function add_log_line($msg="", $priority=null) { /* {{{ */
|
2011-05-16 15:44:59 +00:00
|
|
|
|
global $logger, $user;
|
|
|
|
|
|
|
|
|
|
if(!$logger) return;
|
2013-02-07 16:59:41 +00:00
|
|
|
|
|
2019-02-14 11:45:39 +00:00
|
|
|
|
$ip = "-";
|
2016-08-03 06:53:14 +00:00
|
|
|
|
if(!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
|
|
|
|
|
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
|
2019-02-14 11:45:39 +00:00
|
|
|
|
elseif(!empty($_SERVER['REMOTE_ADDR']))
|
2016-08-03 06:53:14 +00:00
|
|
|
|
$ip = $_SERVER['REMOTE_ADDR'];
|
2019-02-14 11:45:39 +00:00
|
|
|
|
if(!empty($_SERVER["REQUEST_URI"]))
|
2021-10-15 11:50:46 +00:00
|
|
|
|
$scriptname = basename($_SERVER["REQUEST_URI"]).' ';
|
2019-02-14 11:45:39 +00:00
|
|
|
|
else
|
2021-06-28 09:15:56 +00:00
|
|
|
|
$scriptname = basename($_SERVER["SCRIPT_NAME"]).' ';
|
2013-02-07 16:59:41 +00:00
|
|
|
|
if($user)
|
2020-08-05 16:45:09 +00:00
|
|
|
|
$logger->log($user->getLogin()." (".$ip.") ".$scriptname.($msg ? $msg : ''), $priority);
|
2013-02-07 16:59:41 +00:00
|
|
|
|
else
|
2020-08-05 16:45:09 +00:00
|
|
|
|
$logger->log("-- (".$ip.") ".$scriptname.($msg ? $msg : ''), $priority);
|
2011-05-16 15:44:59 +00:00
|
|
|
|
} /* }}} */
|
|
|
|
|
|
|
|
|
|
function _add_log_line($msg="") { /* {{{ */
|
2010-10-29 13:19:51 +00:00
|
|
|
|
global $settings,$user;
|
2017-07-19 17:14:28 +00:00
|
|
|
|
|
2010-10-29 13:19:51 +00:00
|
|
|
|
if ($settings->_logFileEnable!=TRUE) return;
|
|
|
|
|
|
|
|
|
|
if ($settings->_logFileRotation=="h") $logname=date("YmdH", time());
|
|
|
|
|
else if ($settings->_logFileRotation=="d") $logname=date("Ymd", time());
|
|
|
|
|
else $logname=date("Ym", time());
|
2017-07-19 17:14:28 +00:00
|
|
|
|
|
2010-10-29 13:19:51 +00:00
|
|
|
|
if($h = fopen($settings->_contentDir.$logname.".log", "a")) {
|
2021-06-28 07:25:58 +00:00
|
|
|
|
fwrite($h,date("Y/m/d H:i", time())." ".$user->getLogin()." (".$_SERVER['REMOTE_ADDR'].") ".basename($_SERVER["REQUEST_URI"]).$msg."\n");
|
2010-10-29 13:19:51 +00:00
|
|
|
|
fclose($h);
|
|
|
|
|
}
|
2010-12-16 09:29:49 +00:00
|
|
|
|
} /* }}} */
|
2010-10-29 13:19:51 +00:00
|
|
|
|
|
2021-02-24 12:22:03 +00:00
|
|
|
|
function getFolderPathHTML($folder, $tagAll=false, $document=null) { /* {{{ */
|
|
|
|
|
$path = $folder->getPath();
|
|
|
|
|
$txtpath = "";
|
|
|
|
|
for ($i = 0; $i < count($path); $i++) {
|
|
|
|
|
if ($i +1 < count($path)) {
|
|
|
|
|
$txtpath .= "<a href=\"../out/out.ViewFolder.php?folderid=".$path[$i]->getID()."&showtree=".showtree()."\">".
|
|
|
|
|
htmlspecialchars($path[$i]->getName())."</a> / ";
|
2010-12-22 08:50:57 +00:00
|
|
|
|
}
|
2021-02-24 12:22:03 +00:00
|
|
|
|
else {
|
|
|
|
|
$txtpath .= ($tagAll ? "<a href=\"../out/out.ViewFolder.php?folderid=".$path[$i]->getID()."&showtree=".showtree()."\">".
|
|
|
|
|
htmlspecialchars($path[$i]->getName())."</a>" : htmlspecialchars($path[$i]->getName()));
|
2010-12-22 08:50:57 +00:00
|
|
|
|
}
|
2021-02-24 12:22:03 +00:00
|
|
|
|
}
|
|
|
|
|
if($document)
|
|
|
|
|
$txtpath .= " / <a href=\"../out/out.ViewDocument.php?documentid=".$document->getId()."\">".htmlspecialchars($document->getName())."</a>";
|
2012-12-13 21:32:05 +00:00
|
|
|
|
|
2021-02-24 12:22:03 +00:00
|
|
|
|
return $txtpath;
|
|
|
|
|
} /* }}} */
|
2017-07-19 17:14:28 +00:00
|
|
|
|
|
2010-12-16 09:29:49 +00:00
|
|
|
|
function showtree() { /* {{{ */
|
2010-10-29 13:19:51 +00:00
|
|
|
|
global $settings;
|
2017-07-19 17:14:28 +00:00
|
|
|
|
|
2012-08-28 06:39:15 +00:00
|
|
|
|
if (isset($_GET["showtree"])) return intval($_GET["showtree"]);
|
2017-07-19 17:14:28 +00:00
|
|
|
|
else if ($settings->_expandFolderTree==0) return 0;
|
|
|
|
|
|
2010-10-29 13:19:51 +00:00
|
|
|
|
return 1;
|
2010-12-16 09:29:49 +00:00
|
|
|
|
} /* }}} */
|
|
|
|
|
|
2012-08-29 20:49:42 +00:00
|
|
|
|
/**
|
|
|
|
|
* Create a unique key which is used for form validation to prevent
|
|
|
|
|
* CSRF attacks. The key is added to a any form that has to be secured
|
|
|
|
|
* as a hidden field. Once the form is submitted the key is compared
|
|
|
|
|
* to the current key in the session and the request is only executed
|
|
|
|
|
* if both are equal. The key is derived from the session id, a configurable
|
|
|
|
|
* encryption key and form identifierer.
|
|
|
|
|
*
|
|
|
|
|
* @param string $formid individual form identifier
|
|
|
|
|
* @return string session key
|
|
|
|
|
*/
|
|
|
|
|
function createFormKey($formid='') { /* {{{ */
|
|
|
|
|
global $settings, $session;
|
|
|
|
|
|
2021-04-18 05:02:53 +00:00
|
|
|
|
if($session && $id = $session->getId()) {
|
2012-08-29 20:49:42 +00:00
|
|
|
|
return md5($id.$settings->_encryptionKey.$formid);
|
|
|
|
|
} else {
|
2021-04-18 05:02:53 +00:00
|
|
|
|
return md5($settings->_encryptionKey.$formid);
|
2012-08-29 20:49:42 +00:00
|
|
|
|
}
|
|
|
|
|
} /* }}} */
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create a hidden field with the name 'formtoken' and set its value
|
|
|
|
|
* to the key returned by createFormKey()
|
|
|
|
|
*
|
|
|
|
|
* @param string $formid individual form identifier
|
|
|
|
|
* @return string input field for html formular
|
|
|
|
|
*/
|
|
|
|
|
function createHiddenFieldWithKey($formid='') { /* {{{ */
|
2017-07-19 17:14:28 +00:00
|
|
|
|
return '<input type="hidden" name="formtoken" value="'.createFormKey($formid).'" />';
|
2012-08-29 20:49:42 +00:00
|
|
|
|
} /* }}} */
|
|
|
|
|
|
|
|
|
|
/**
|
2012-08-31 07:43:43 +00:00
|
|
|
|
* Check if the form key in the POST or GET request variable 'formtoken'
|
|
|
|
|
* has the value of key returned by createFormKey(). Request to modify
|
|
|
|
|
* data in the DMS should always use POST because it is harder to run
|
|
|
|
|
* CSRF attacks using POST than GET.
|
2012-08-29 20:49:42 +00:00
|
|
|
|
*
|
|
|
|
|
* @param string $formid individual form identifier
|
2012-08-31 07:43:43 +00:00
|
|
|
|
* @param string $method defines if the form data is pass via GET or
|
|
|
|
|
* POST (default)
|
2012-08-29 20:49:42 +00:00
|
|
|
|
* @return boolean true if key matches otherwise false
|
|
|
|
|
*/
|
2012-08-31 07:43:43 +00:00
|
|
|
|
function checkFormKey($formid='', $method='POST') { /* {{{ */
|
|
|
|
|
switch($method) {
|
|
|
|
|
case 'GET':
|
|
|
|
|
if(isset($_GET['formtoken']) && $_GET['formtoken'] == createFormKey($formid))
|
|
|
|
|
return true;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
if(isset($_POST['formtoken']) && $_POST['formtoken'] == createFormKey($formid))
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2017-07-19 17:14:28 +00:00
|
|
|
|
|
2012-08-29 20:49:42 +00:00
|
|
|
|
return false;
|
|
|
|
|
} /* }}} */
|
2012-12-19 10:08:06 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check disk usage of currently logged in user
|
|
|
|
|
*
|
|
|
|
|
* @return boolean/integer true if no quota is set, number of bytes until
|
|
|
|
|
* quota is reached. Negative values indicate a disk usage above quota.
|
|
|
|
|
*/
|
2014-05-20 04:31:12 +00:00
|
|
|
|
function checkQuota($user) { /* {{{ */
|
|
|
|
|
global $settings, $dms;
|
|
|
|
|
|
|
|
|
|
/* check if quota is turn off system wide */
|
|
|
|
|
if($settings->_quota == 0)
|
|
|
|
|
return true;
|
2012-12-19 10:08:06 +00:00
|
|
|
|
|
|
|
|
|
$quota = 0;
|
|
|
|
|
$uquota = $user->getQuota();
|
|
|
|
|
if($uquota > 0)
|
|
|
|
|
$quota = $uquota;
|
2014-05-20 04:31:12 +00:00
|
|
|
|
elseif($settings->_quota > 0) {
|
2012-12-19 10:08:06 +00:00
|
|
|
|
$quota = $settings->_quota;
|
2014-05-20 04:31:12 +00:00
|
|
|
|
}
|
2012-12-19 10:08:06 +00:00
|
|
|
|
|
|
|
|
|
if($quota == 0)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return ($quota - $user->getUsedDiskSpace());
|
|
|
|
|
} /* }}} */
|
2013-09-03 06:23:23 +00:00
|
|
|
|
|
2019-07-12 14:40:38 +00:00
|
|
|
|
/**
|
|
|
|
|
* Encrypt any data with a key
|
|
|
|
|
*
|
|
|
|
|
* @param string $key
|
|
|
|
|
* @param string $value plain text data
|
|
|
|
|
* @return string encrypted data
|
|
|
|
|
*/
|
|
|
|
|
function encryptData($key, $value) { /* {{{ */
|
2023-04-18 18:09:03 +00:00
|
|
|
|
if(function_exists('openssl_cipher_iv_length')) {
|
|
|
|
|
$nonceSize = openssl_cipher_iv_length('aes-256-ctr');
|
|
|
|
|
$nonce = openssl_random_pseudo_bytes($nonceSize);
|
|
|
|
|
|
|
|
|
|
$ciphertext = openssl_encrypt(
|
|
|
|
|
$value,
|
|
|
|
|
'aes-256-ctr',
|
|
|
|
|
$key,
|
|
|
|
|
OPENSSL_RAW_DATA,
|
|
|
|
|
$nonce
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Now let's pack the IV and the ciphertext together
|
|
|
|
|
// Naively, we can just concatenate
|
|
|
|
|
return $nonce.$ciphertext;
|
|
|
|
|
} else {
|
|
|
|
|
$text = $value;
|
|
|
|
|
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
|
|
|
|
|
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
|
|
|
|
|
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_ECB, $iv);
|
|
|
|
|
return $crypttext;
|
|
|
|
|
}
|
2019-07-12 14:40:38 +00:00
|
|
|
|
} /* }}} */
|
2013-09-03 06:23:23 +00:00
|
|
|
|
|
2019-07-12 14:40:38 +00:00
|
|
|
|
/**
|
|
|
|
|
* Decrypt data previously encrypted by encrypt
|
|
|
|
|
*
|
|
|
|
|
* @param string $key
|
|
|
|
|
* @param string $value encrypted data
|
|
|
|
|
* @return string plain text data
|
|
|
|
|
*/
|
|
|
|
|
function decryptData($key, $value) { /* {{{ */
|
2023-04-18 18:09:03 +00:00
|
|
|
|
if(function_exists('openssl_cipher_iv_length')) {
|
|
|
|
|
$nonceSize = openssl_cipher_iv_length('aes-256-ctr');
|
|
|
|
|
$nonce = mb_substr($value, 0, $nonceSize, '8bit');
|
|
|
|
|
$ciphertext = mb_substr($value, $nonceSize, null, '8bit');
|
|
|
|
|
|
|
|
|
|
$plaintext = openssl_decrypt(
|
|
|
|
|
$ciphertext,
|
|
|
|
|
'aes-256-ctr',
|
|
|
|
|
$key,
|
|
|
|
|
OPENSSL_RAW_DATA,
|
|
|
|
|
$nonce
|
|
|
|
|
);
|
|
|
|
|
return $plaintext;
|
|
|
|
|
} else {
|
|
|
|
|
$crypttext = $value;
|
|
|
|
|
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
|
|
|
|
|
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
|
|
|
|
|
$decrypttext = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $crypttext, MCRYPT_MODE_ECB, $iv);
|
|
|
|
|
return trim($decrypttext);
|
|
|
|
|
}
|
2019-07-12 14:40:38 +00:00
|
|
|
|
} /* }}} */
|
2013-09-03 06:23:23 +00:00
|
|
|
|
|
2015-06-12 06:59:05 +00:00
|
|
|
|
/**
|
|
|
|
|
* Return file extension for a give mimetype
|
|
|
|
|
*
|
|
|
|
|
* @param string $mimetype Mime-Type
|
|
|
|
|
* @return string file extension including leading dot
|
|
|
|
|
*/
|
|
|
|
|
function get_extension($mimetype) { /* {{{ */
|
|
|
|
|
if(empty($mimetype)) return false;
|
|
|
|
|
switch($mimetype) {
|
|
|
|
|
case 'image/bmp': return '.bmp';
|
2022-04-12 06:14:53 +00:00
|
|
|
|
case 'image/x-ms-bmp': return '.bmp';
|
2015-06-12 06:59:05 +00:00
|
|
|
|
case 'image/cis-cod': return '.cod';
|
|
|
|
|
case 'image/gif': return '.gif';
|
|
|
|
|
case 'image/ief': return '.ief';
|
|
|
|
|
case 'image/jpeg': return '.jpg';
|
2024-06-29 11:23:29 +00:00
|
|
|
|
case 'image/jpg': return '.jpg';
|
2015-06-12 06:59:05 +00:00
|
|
|
|
case 'image/pipeg': return '.jfif';
|
|
|
|
|
case 'image/tiff': return '.tif';
|
|
|
|
|
case 'image/x-cmu-raster': return '.ras';
|
|
|
|
|
case 'image/x-cmx': return '.cmx';
|
|
|
|
|
case 'image/x-icon': return '.ico';
|
|
|
|
|
case 'image/x-portable-anymap': return '.pnm';
|
|
|
|
|
case 'image/x-portable-bitmap': return '.pbm';
|
|
|
|
|
case 'image/x-portable-graymap': return '.pgm';
|
|
|
|
|
case 'image/x-portable-pixmap': return '.ppm';
|
|
|
|
|
case 'image/x-rgb': return '.rgb';
|
|
|
|
|
case 'image/x-xbitmap': return '.xbm';
|
|
|
|
|
case 'image/x-xpixmap': return '.xpm';
|
|
|
|
|
case 'image/x-xwindowdump': return '.xwd';
|
|
|
|
|
case 'image/png': return '.png';
|
|
|
|
|
case 'image/x-jps': return '.jps';
|
|
|
|
|
case 'image/x-freehand': return '.fh';
|
|
|
|
|
case 'image/svg+xml': return '.svg';
|
2022-04-12 06:14:53 +00:00
|
|
|
|
case 'audio/mp3': return '.mp3';
|
|
|
|
|
case 'audio/mpeg': return '.mpeg';
|
|
|
|
|
case 'audio/ogg': return '.ogg';
|
|
|
|
|
case 'video/mp4': return '.mp4';
|
|
|
|
|
case 'video/webm': return '.webm';
|
2015-06-12 06:59:05 +00:00
|
|
|
|
case 'application/zip': return '.zip';
|
2022-04-12 06:14:53 +00:00
|
|
|
|
case 'application/x-gzip': return '.gz';
|
2015-06-12 06:59:05 +00:00
|
|
|
|
case 'application/x-rar': return '.rar';
|
2022-04-12 06:14:53 +00:00
|
|
|
|
case 'application/x-compressed-tar': return '.tgz';
|
2024-07-11 17:48:13 +00:00
|
|
|
|
case 'application/x-xopp': return '.xopp';
|
2015-06-12 06:59:05 +00:00
|
|
|
|
case 'application/pdf': return '.pdf';
|
2022-04-12 06:14:53 +00:00
|
|
|
|
case 'application/dxf': return '.dxf';
|
|
|
|
|
case 'application/msword': return '.doc';
|
2015-06-12 06:59:05 +00:00
|
|
|
|
case 'application/postscript': return '.ps';
|
|
|
|
|
case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': return '.docx';
|
2015-11-30 18:48:40 +00:00
|
|
|
|
case 'application/vnd.openxmlformats-officedocument.presentationml.presentation': return '.pptx';
|
2023-03-24 15:33:17 +00:00
|
|
|
|
case 'application/vnd.oasis.opendocument.text': return '.odt';
|
|
|
|
|
case 'application/vnd.oasis.opendocument.spreadsheet': return '.ods';
|
|
|
|
|
case 'application/vnd.oasis.opendocument.presentation': return '.odp';
|
2015-06-12 06:59:05 +00:00
|
|
|
|
case 'text/plain': return '.txt';
|
|
|
|
|
case 'text/csv': return '.csv';
|
2022-04-12 06:14:53 +00:00
|
|
|
|
case 'text/rtf': return '.rtf';
|
|
|
|
|
case 'text/xml': return '.xml';
|
|
|
|
|
case 'text/x-php': return '.php';
|
|
|
|
|
case 'text/x-tex': return '.tex';
|
|
|
|
|
case 'message/rfc822': return '.eml';
|
2015-06-12 06:59:05 +00:00
|
|
|
|
default: return false;
|
|
|
|
|
}
|
|
|
|
|
} /* }}} */
|
2015-07-28 05:28:34 +00:00
|
|
|
|
|
|
|
|
|
/**
|
2023-02-17 15:10:59 +00:00
|
|
|
|
* Adds a missing directory separator (or any other char) to a string
|
2015-07-28 05:28:34 +00:00
|
|
|
|
*
|
|
|
|
|
* This function is used for making sure a directory name has a
|
2023-02-17 15:10:59 +00:00
|
|
|
|
* trailing directory separator. It can also be used to add
|
|
|
|
|
* any other char at the end of a string, e.g. an URL which must
|
|
|
|
|
* end in '/' (DIRECTORY_SEPARATOR wouldn't be right in that case,
|
|
|
|
|
* because it is '\' on Windows)
|
2015-07-28 05:28:34 +00:00
|
|
|
|
*/
|
2023-02-17 15:10:59 +00:00
|
|
|
|
function addDirSep($str, $chr=DIRECTORY_SEPARATOR) { /* {{{ */
|
2015-07-28 05:32:29 +00:00
|
|
|
|
if(trim($str) == '')
|
|
|
|
|
return '';
|
2023-02-17 15:10:59 +00:00
|
|
|
|
if(substr(trim($str), -1, 1) != $chr)
|
|
|
|
|
return trim($str).$chr;
|
2015-07-28 05:28:34 +00:00
|
|
|
|
else
|
2015-07-28 05:32:29 +00:00
|
|
|
|
return trim($str);
|
2015-07-28 05:28:34 +00:00
|
|
|
|
} /* }}} */
|
2017-07-18 11:35:35 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Formats comments for aknowledge of reception.
|
|
|
|
|
*
|
|
|
|
|
* Only use in documentListRow()
|
|
|
|
|
*/
|
|
|
|
|
function formatComment($an) { /* {{{ */
|
|
|
|
|
$t = array();
|
|
|
|
|
foreach($an as $a)
|
|
|
|
|
$t[] = $a['n']." × ".$a['c'];
|
|
|
|
|
return $t;
|
|
|
|
|
} /* }}} */
|
2018-01-18 09:53:58 +00:00
|
|
|
|
|
2022-05-17 06:20:16 +00:00
|
|
|
|
/*
|
2022-05-16 13:54:04 +00:00
|
|
|
|
* Determines if a command exists on the current environment
|
|
|
|
|
*
|
|
|
|
|
* @param string $command The command to check
|
|
|
|
|
* @return bool True if the command has been found ; otherwise, false.
|
|
|
|
|
*/
|
2022-11-02 07:54:52 +00:00
|
|
|
|
function commandExists ($command) { /* {{{ */
|
2022-05-16 13:54:04 +00:00
|
|
|
|
$whereIsCommand = (PHP_OS == 'WINNT') ? 'where' : 'command -v';
|
|
|
|
|
|
|
|
|
|
$process = proc_open(
|
|
|
|
|
"$whereIsCommand $command",
|
|
|
|
|
array(
|
|
|
|
|
0 => array("pipe", "r"), //STDIN
|
|
|
|
|
1 => array("pipe", "w"), //STDOUT
|
|
|
|
|
2 => array("pipe", "w"), //STDERR
|
|
|
|
|
),
|
|
|
|
|
$pipes
|
|
|
|
|
);
|
|
|
|
|
if ($process !== false) {
|
|
|
|
|
$stdout = stream_get_contents($pipes[1]);
|
|
|
|
|
$stderr = stream_get_contents($pipes[2]);
|
|
|
|
|
fclose($pipes[1]);
|
|
|
|
|
fclose($pipes[2]);
|
|
|
|
|
proc_close($process);
|
|
|
|
|
|
|
|
|
|
return $stdout != '';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
2022-11-02 07:54:52 +00:00
|
|
|
|
} /* }}} */
|
2022-05-16 13:54:04 +00:00
|
|
|
|
|
2018-01-18 07:48:32 +00:00
|
|
|
|
/**
|
|
|
|
|
* Send a file from disk to the browser
|
|
|
|
|
*
|
|
|
|
|
* This function uses either readfile() or the xѕendfile apache module if
|
|
|
|
|
* it is installed.
|
|
|
|
|
*
|
|
|
|
|
* @param string $filename
|
|
|
|
|
*/
|
|
|
|
|
function sendFile($filename) { /* {{{ */
|
2019-01-18 12:08:21 +00:00
|
|
|
|
global $settings;
|
|
|
|
|
if($settings->_enableXsendfile && function_exists('apache_get_modules') && in_array('mod_xsendfile',apache_get_modules())) {
|
2018-01-18 07:48:32 +00:00
|
|
|
|
header("X-Sendfile: ".$filename);
|
|
|
|
|
} else {
|
2020-12-23 05:20:58 +00:00
|
|
|
|
|
|
|
|
|
$size = filesize($filename);
|
|
|
|
|
if (isset($_SERVER['HTTP_RANGE'])) {
|
|
|
|
|
$fp = @fopen($filename, 'rb');
|
|
|
|
|
$length = $size; // Content length
|
|
|
|
|
$start = 0; // Start byte
|
|
|
|
|
$end = $size - 1; // End byte
|
|
|
|
|
|
2021-04-06 20:04:02 +00:00
|
|
|
|
// header("Accept-Ranges: 0-$length");
|
|
|
|
|
header("Accept-Ranges: bytes");
|
2020-12-23 05:20:58 +00:00
|
|
|
|
|
|
|
|
|
$c_start = $start;
|
|
|
|
|
$c_end = $end;
|
|
|
|
|
|
|
|
|
|
list($unit, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2);
|
|
|
|
|
if (trim($unit) !== 'bytes') {
|
|
|
|
|
header('HTTP/1.1 416 Requested Range Not Satisfiable');
|
|
|
|
|
header("Content-Range: bytes $start-$end/$size");
|
|
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
|
if (strpos($range, ',') !== false) {
|
|
|
|
|
header('HTTP/1.1 416 Requested Range Not Satisfiable');
|
|
|
|
|
header("Content-Range: bytes $start-$end/$size");
|
|
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
|
if ($range == '-') {
|
|
|
|
|
$c_start = $size - substr($range, 1);
|
|
|
|
|
} else {
|
|
|
|
|
$range = explode('-', $range);
|
|
|
|
|
$c_start = $range[0];
|
|
|
|
|
$c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $size;
|
|
|
|
|
}
|
|
|
|
|
$c_end = ($c_end > $end) ? $end : $c_end;
|
|
|
|
|
if ($c_start > $c_end || $c_start > $size - 1 || $c_end >= $size) {
|
|
|
|
|
header('HTTP/1.1 416 Requested Range Not Satisfiable');
|
|
|
|
|
header("Content-Range: bytes $start-$end/$size");
|
|
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
|
$start = $c_start;
|
|
|
|
|
$end = $c_end;
|
|
|
|
|
$length = $end - $start + 1;
|
|
|
|
|
fseek($fp, $start);
|
|
|
|
|
header('HTTP/1.1 206 Partial Content');
|
|
|
|
|
header("Content-Range: bytes $start-$end/$size");
|
2021-04-06 20:04:02 +00:00
|
|
|
|
header("Content-Length: " . $length);
|
2020-12-23 05:20:58 +00:00
|
|
|
|
|
|
|
|
|
$buffer = 1024 * 8;
|
|
|
|
|
while(!feof($fp) && ($p = ftell($fp)) <= $end) {
|
|
|
|
|
if ($p + $buffer > $end) {
|
|
|
|
|
$buffer = $end - $p + 1;
|
|
|
|
|
}
|
|
|
|
|
set_time_limit(0);
|
|
|
|
|
echo fread($fp, $buffer);
|
|
|
|
|
flush();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fclose($fp);
|
|
|
|
|
} else {
|
2021-04-06 20:04:02 +00:00
|
|
|
|
header("Content-Length: " . $size);
|
2020-12-23 05:20:58 +00:00
|
|
|
|
/* Make sure output buffering is off */
|
|
|
|
|
if (ob_get_level()) {
|
|
|
|
|
ob_end_clean();
|
|
|
|
|
}
|
|
|
|
|
readfile($filename);
|
2018-01-18 07:48:32 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} /* }}} */
|
2019-07-12 14:40:38 +00:00
|
|
|
|
|
2019-11-28 09:00:52 +00:00
|
|
|
|
/**
|
|
|
|
|
* Return protocol and host of url
|
|
|
|
|
*
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
|
|
|
|
function getBaseUrl() { /* {{{ */
|
2023-01-26 12:18:40 +00:00
|
|
|
|
global $settings;
|
|
|
|
|
|
|
|
|
|
if(!empty($settings->_baseUrl))
|
|
|
|
|
return $settings->_baseUrl;
|
|
|
|
|
|
2023-02-18 14:49:04 +00:00
|
|
|
|
if(isset($_SERVER['HTTP_X_FORWARDED_HOST']))
|
|
|
|
|
$host = $_SERVER['HTTP_X_FORWARDED_HOST'];
|
2023-01-26 12:18:40 +00:00
|
|
|
|
else
|
|
|
|
|
$host = $_SERVER['HTTP_HOST'];
|
2023-02-18 14:49:04 +00:00
|
|
|
|
if(isset($_SERVER['HTTP_X_FORWARDED_PROTO']))
|
|
|
|
|
$ssl = $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https';
|
2023-01-26 12:18:40 +00:00
|
|
|
|
else
|
|
|
|
|
$ssl = (isset($_SERVER['HTTPS']) && (strcmp($_SERVER['HTTPS'],'off')!=0));
|
|
|
|
|
|
|
|
|
|
return "http".($ssl ? "s" : "")."://".$host;
|
2019-11-28 09:00:52 +00:00
|
|
|
|
} /* }}} */
|
|
|
|
|
|
2020-07-30 08:55:13 +00:00
|
|
|
|
function getToken($length){ /* {{{ */
|
2020-02-06 10:32:27 +00:00
|
|
|
|
$token = "";
|
|
|
|
|
$codeAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
|
|
|
$codeAlphabet.= "abcdefghijklmnopqrstuvwxyz";
|
|
|
|
|
$codeAlphabet.= "0123456789";
|
|
|
|
|
$max = strlen($codeAlphabet);
|
|
|
|
|
|
|
|
|
|
for ($i=0; $i < $length; $i++) {
|
|
|
|
|
$token .= $codeAlphabet[random_int(0, $max-1)];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $token;
|
2020-07-30 08:55:13 +00:00
|
|
|
|
} /* }}} */
|
|
|
|
|
|
2020-12-07 09:24:30 +00:00
|
|
|
|
function isAjax() { /* {{{ */
|
|
|
|
|
if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest')
|
|
|
|
|
return true;
|
|
|
|
|
else
|
|
|
|
|
return false;
|
2020-07-30 08:55:13 +00:00
|
|
|
|
} /* }}} */
|
|
|
|
|
|
|
|
|
|
/**
|
2024-02-08 20:02:12 +00:00
|
|
|
|
* Hash a password
|
2020-07-30 08:55:13 +00:00
|
|
|
|
*
|
|
|
|
|
* @param string $password
|
|
|
|
|
* @return string hashed password
|
|
|
|
|
*/
|
|
|
|
|
function seed_pass_hash($password) { /* {{{ */
|
|
|
|
|
return md5($password);
|
|
|
|
|
} /* }}} */
|
|
|
|
|
|
|
|
|
|
/**
|
2024-02-08 20:02:12 +00:00
|
|
|
|
* Verify a password
|
2020-07-30 08:55:13 +00:00
|
|
|
|
*
|
|
|
|
|
* @param string $password
|
|
|
|
|
* @return string hashed password
|
|
|
|
|
*/
|
|
|
|
|
function seed_pass_verify($password, $hash) { /* {{{ */
|
2024-01-10 19:36:53 +00:00
|
|
|
|
return $hash === md5($password);
|
2020-07-30 08:55:13 +00:00
|
|
|
|
} /* }}} */
|
2020-02-06 10:32:27 +00:00
|
|
|
|
|
2023-03-12 08:18:30 +00:00
|
|
|
|
function resolveTask($task) { /* {{{ */
|
2021-10-16 15:44:45 +00:00
|
|
|
|
global $dms, $user, $settings, $logger, $fulltextservice, $notifier, $conversionmgr;
|
2020-06-28 11:58:32 +00:00
|
|
|
|
|
|
|
|
|
if(is_object($task))
|
|
|
|
|
return $task;
|
|
|
|
|
if(is_string($task)) {
|
|
|
|
|
if(class_exists($task)) {
|
2021-10-16 15:44:45 +00:00
|
|
|
|
$task = new $task($dms, $user, $settings, $logger, $fulltextservice, $notifier, $conversionmgr);
|
2020-06-28 11:58:32 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $task;
|
2023-03-12 08:18:30 +00:00
|
|
|
|
} /* }}} */
|
2020-06-28 11:58:32 +00:00
|
|
|
|
|
2020-09-15 10:13:51 +00:00
|
|
|
|
/**
|
|
|
|
|
* Return nonce for CSP
|
|
|
|
|
*
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
|
|
|
|
function createNonce() { /* {{{ */
|
|
|
|
|
$length = 16;
|
|
|
|
|
$usable = true;
|
|
|
|
|
$bytes = openssl_random_pseudo_bytes($length, $usable);
|
|
|
|
|
if ($usable === false) {
|
|
|
|
|
// weak
|
|
|
|
|
// @TODO do something?
|
|
|
|
|
}
|
|
|
|
|
return base64_encode($bytes);
|
|
|
|
|
} /* }}} */
|
|
|
|
|
|
2022-11-02 07:54:52 +00:00
|
|
|
|
/**
|
|
|
|
|
* Create a real uniqid for cryptographic purposes
|
|
|
|
|
*
|
|
|
|
|
* @ return string
|
|
|
|
|
*/
|
|
|
|
|
function uniqidReal($lenght = 13) {
|
|
|
|
|
// uniqid gives 13 chars, but you could adjust it to your needs.
|
|
|
|
|
if (function_exists("random_bytes")) {
|
|
|
|
|
$bytes = random_bytes(ceil($lenght / 2));
|
|
|
|
|
} elseif (function_exists("openssl_random_pseudo_bytes")) {
|
|
|
|
|
$bytes = openssl_random_pseudo_bytes(ceil($lenght / 2));
|
|
|
|
|
} else {
|
|
|
|
|
throw new Exception("no cryptographically secure random function available");
|
|
|
|
|
}
|
|
|
|
|
return substr(bin2hex($bytes), 0, $lenght);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-30 05:57:27 +00:00
|
|
|
|
/**
|
|
|
|
|
* Compare function for sorting users by login
|
|
|
|
|
*
|
|
|
|
|
* Use this for usort()
|
|
|
|
|
*
|
|
|
|
|
* <code>
|
|
|
|
|
* $users = $dms->getAllUsers();
|
|
|
|
|
* usort($users, 'cmp_user_login');
|
|
|
|
|
* </code>
|
|
|
|
|
*/
|
|
|
|
|
function cmp_user_login($a, $b) { /* {{{ */
|
|
|
|
|
$as = strtolower($a->getLogin());
|
|
|
|
|
$bs = strtolower($b->getLogin());
|
|
|
|
|
if ($as == $bs) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return ($as < $bs) ? -1 : 1;
|
|
|
|
|
} /* }}} */
|
|
|
|
|
|
|
|
|
|
/**
|
2024-02-08 20:02:12 +00:00
|
|
|
|
* Compare function for sorting users by name
|
2021-04-30 05:57:27 +00:00
|
|
|
|
*
|
|
|
|
|
* Use this for usort()
|
|
|
|
|
*
|
|
|
|
|
* <code>
|
|
|
|
|
* $users = $dms->getAllUsers();
|
|
|
|
|
* usort($users, 'cmp_user_fullname');
|
|
|
|
|
* </code>
|
|
|
|
|
*/
|
|
|
|
|
function cmp_user_fullname($a, $b) { /* {{{ */
|
|
|
|
|
$as = strtolower($a->getFullName());
|
|
|
|
|
$bs = strtolower($b->getFullName());
|
|
|
|
|
if ($as == $bs) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return ($as < $bs) ? -1 : 1;
|
|
|
|
|
} /* }}} */
|
|
|
|
|
|
2021-02-24 12:22:03 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns the mandatory reviewers
|
|
|
|
|
*
|
|
|
|
|
* This function checks if the reviewers have at least read access
|
2024-02-08 20:02:12 +00:00
|
|
|
|
* on the folder containing the document. It also checks if the
|
|
|
|
|
* mandatory reviewer is an admin or the uploading user and if
|
|
|
|
|
* those are allowed to review/approve a document.
|
2024-02-21 15:04:01 +00:00
|
|
|
|
* Mandatory groups will only be added if they are not empty
|
2021-02-24 12:22:03 +00:00
|
|
|
|
*
|
|
|
|
|
* @param $folder folder where document is located
|
2024-02-08 20:02:12 +00:00
|
|
|
|
* @param $document document which is updated, null when adding a new document
|
2021-02-24 12:22:03 +00:00
|
|
|
|
* @param $user user creating the new version or document
|
2024-02-08 20:02:12 +00:00
|
|
|
|
* @return array containing the elements 'i' and 'g'. Each is a list of user/group ids
|
2021-02-24 12:22:03 +00:00
|
|
|
|
*/
|
2024-02-08 20:02:12 +00:00
|
|
|
|
function getMandatoryReviewers($folder, $document, $user) { /* {{{ */
|
2021-02-24 12:22:03 +00:00
|
|
|
|
global $settings;
|
|
|
|
|
|
2024-02-08 20:02:12 +00:00
|
|
|
|
/* Get mandatory reviewers of user */
|
|
|
|
|
$res = $user->getMandatoryReviewers();
|
|
|
|
|
$revi = $revg = [];
|
2021-02-24 12:22:03 +00:00
|
|
|
|
foreach ($res as $r){
|
|
|
|
|
if ($r['reviewerUserID']!=0){
|
2024-02-08 20:02:12 +00:00
|
|
|
|
$revi[] = $r['reviewerUserID'];
|
2021-02-24 12:22:03 +00:00
|
|
|
|
} elseif ($r['reviewerGroupID']!=0){
|
2024-02-08 20:02:12 +00:00
|
|
|
|
$revg[] = $r['reviewerGroupID'];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add managers of groups as mandatory reviewers */
|
|
|
|
|
if(!empty($settings->_addManagerAsReviewer)) {
|
|
|
|
|
$groups = $user->getGroups();
|
|
|
|
|
foreach($groups as $group) {
|
|
|
|
|
$managers = $group->getManagers();
|
|
|
|
|
foreach($managers as $manager) {
|
|
|
|
|
$revi[] = $manager->getId();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add global reviewers as mandatory reviewers */
|
|
|
|
|
if(!empty($settings->_globalReviewer)) {
|
|
|
|
|
$revi = array_merge($revi, $settings->_globalReviewer);
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-12 13:06:53 +00:00
|
|
|
|
/* Add global group reviewers as mandatory reviewers */
|
|
|
|
|
if(!empty($settings->_globalGroupReviewer)) {
|
|
|
|
|
$revg = array_merge($revg, $settings->_globalGroupReviewer);
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-08 20:02:12 +00:00
|
|
|
|
/* Check if reviewers are allowed to review */
|
|
|
|
|
$revi = array_unique($revi);
|
|
|
|
|
$revg = array_unique($revg);
|
|
|
|
|
$reviewers["i"] = []; // users
|
|
|
|
|
$reviewers["g"] = []; // groups
|
|
|
|
|
$reviewers["ni"] = []; // users being filtered out
|
|
|
|
|
$reviewers["ng"] = []; // groups being filtered out
|
|
|
|
|
$dms = $user->getDMS();
|
|
|
|
|
foreach($revi as $uid) {
|
|
|
|
|
if($u = $dms->getUser($uid)) {
|
|
|
|
|
/* need at least read access on parent folder */
|
2024-02-21 15:04:01 +00:00
|
|
|
|
if($document)
|
|
|
|
|
$accessmode = $document->getAccessMode($u);
|
|
|
|
|
else
|
|
|
|
|
$accessmode = $folder->getAccessMode($u);
|
|
|
|
|
if($accessmode < M_READ)
|
2024-02-08 20:02:12 +00:00
|
|
|
|
$reviewers["ni"][] = $u->getId();
|
|
|
|
|
/* admins as reviewers must be enabled */
|
|
|
|
|
elseif(!$settings->_enableAdminRevApp && $u->isAdmin())
|
|
|
|
|
$reviewers["ni"][] = $u->getId();
|
|
|
|
|
/* the owner of the document as a reviewer must be enabled */
|
|
|
|
|
elseif(!$settings->_enableOwnerRevApp && $document && $document->getOwner()->getId() == $u->getId())
|
|
|
|
|
$reviewers["ni"][] = $u->getId();
|
|
|
|
|
/* the updloader as a reviewer must be enabled */
|
|
|
|
|
elseif(!$settings->_enableSelfRevApp && $u->getId() == $user->getId())
|
|
|
|
|
$reviewers["ni"][] = $u->getId();
|
|
|
|
|
else
|
|
|
|
|
$reviewers["i"][] = $u->getId();
|
2021-02-24 12:22:03 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2024-02-08 20:02:12 +00:00
|
|
|
|
foreach($revg as $gid) {
|
|
|
|
|
if($g = $dms->getGroup($gid)) {
|
2024-02-21 15:04:01 +00:00
|
|
|
|
if($document)
|
|
|
|
|
$accessmode = $document->getGroupAccessMode($u);
|
|
|
|
|
else
|
|
|
|
|
$accessmode = $folder->getGroupAccessMode($u);
|
|
|
|
|
if($accessmode < M_READ || !$g->getUsers())
|
2024-02-08 20:02:12 +00:00
|
|
|
|
$reviewers["ng"][] = $g->getId();
|
|
|
|
|
else
|
|
|
|
|
$reviewers["g"][] = $g->getId();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-24 12:22:03 +00:00
|
|
|
|
return $reviewers;
|
|
|
|
|
} /* }}} */
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the mandatory approvers
|
|
|
|
|
*
|
|
|
|
|
* This function checks if the approvers have at least read access
|
2024-02-08 20:02:12 +00:00
|
|
|
|
* on the folder containing the document. It also checks if the
|
|
|
|
|
* mandatory approver is an admin or the uploading user and if
|
|
|
|
|
* those are allowed to review/approve a document.
|
2024-02-21 15:04:01 +00:00
|
|
|
|
* Mandatory groups will only be added if they are not empty
|
2021-02-24 12:22:03 +00:00
|
|
|
|
*
|
|
|
|
|
* @param $folder folder where document is located
|
2024-02-08 20:02:12 +00:00
|
|
|
|
* @param $document document which is updated, null when adding a new document
|
2021-02-24 12:22:03 +00:00
|
|
|
|
* @param $user user creating the new version or document
|
2024-02-08 20:02:12 +00:00
|
|
|
|
* @return array containing the elements 'i' and 'g'. Each is a list of user/group ids
|
2021-02-24 12:22:03 +00:00
|
|
|
|
*/
|
2024-02-08 20:02:12 +00:00
|
|
|
|
function getMandatoryApprovers($folder, $document, $user) { /* {{{ */
|
2021-02-24 12:22:03 +00:00
|
|
|
|
global $settings;
|
|
|
|
|
|
2024-02-08 20:02:12 +00:00
|
|
|
|
/* Get mandatory approvers of user */
|
|
|
|
|
$res = $user->getMandatoryApprovers();
|
|
|
|
|
$appi = $appg = [];
|
2021-02-24 12:22:03 +00:00
|
|
|
|
foreach ($res as $r){
|
|
|
|
|
if ($r['approverUserID']!=0){
|
2024-02-08 20:02:12 +00:00
|
|
|
|
$appi[] = $r['approverUserID'];
|
|
|
|
|
} elseif ($r['approverGroupID']!=0){
|
|
|
|
|
$appg[] = $r['approverGroupID'];
|
2021-02-24 12:22:03 +00:00
|
|
|
|
}
|
2024-02-08 20:02:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add managers of groups as mandatory approvers */
|
|
|
|
|
if(!empty($settings->_addManagerAsApprover)) {
|
|
|
|
|
$groups = $user->getGroups();
|
|
|
|
|
foreach($groups as $group) {
|
|
|
|
|
$managers = $group->getManagers();
|
|
|
|
|
foreach($managers as $manager) {
|
|
|
|
|
$appi[] = $manager->getId();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add global approvers as mandatory approvers */
|
|
|
|
|
if(!empty($settings->_globalApprover)) {
|
|
|
|
|
$appi = array_merge($appi, $settings->_globalApprover);
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-12 13:06:53 +00:00
|
|
|
|
/* Add global group approvers as mandatory approvers */
|
|
|
|
|
if(!empty($settings->_globalGroupApprover)) {
|
|
|
|
|
$appg = array_merge($appg, $settings->_globalGroupApprover);
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-08 20:02:12 +00:00
|
|
|
|
/* Check if approvers are allowed to approve */
|
|
|
|
|
$appi = array_unique($appi);
|
|
|
|
|
$appg = array_unique($appg);
|
|
|
|
|
$approvers["i"] = []; // users
|
|
|
|
|
$approvers["g"] = []; // groups
|
|
|
|
|
$approvers["ni"] = []; // users being filtered out
|
|
|
|
|
$approvers["ng"] = []; // groups being filtered out
|
|
|
|
|
$dms = $user->getDMS();
|
|
|
|
|
foreach($appi as $uid) {
|
|
|
|
|
if($u = $dms->getUser($uid)) {
|
|
|
|
|
/* need at least read access on parent folder */
|
2024-02-21 15:04:01 +00:00
|
|
|
|
if($document)
|
|
|
|
|
$accessmode = $document->getAccessMode($u);
|
|
|
|
|
else
|
|
|
|
|
$accessmode = $folder->getAccessMode($u);
|
|
|
|
|
if($accessmode < M_READ)
|
2024-02-08 20:02:12 +00:00
|
|
|
|
$approvers["ni"][] = $u->getId();
|
|
|
|
|
/* admins as approvers must be enabled */
|
|
|
|
|
elseif(!$settings->_enableAdminRevApp && $u->isAdmin())
|
|
|
|
|
$approvers["ni"][] = $u->getId();
|
|
|
|
|
/* the owner of the document as a approver must be enabled */
|
|
|
|
|
elseif(!$settings->_enableOwnerRevApp && $document && $document->getOwner()->getId() == $u->getId())
|
|
|
|
|
$approvers["ni"][] = $u->getId();
|
|
|
|
|
/* the updloader as a approver must be enabled */
|
|
|
|
|
elseif(!$settings->_enableSelfRevApp && $u->getId() == $user->getId())
|
|
|
|
|
$approvers["ni"][] = $u->getId();
|
|
|
|
|
else
|
|
|
|
|
$approvers["i"][] = $u->getId();
|
2021-02-24 12:22:03 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2024-02-08 20:02:12 +00:00
|
|
|
|
foreach($appg as $gid) {
|
|
|
|
|
if($g = $dms->getGroup($gid)) {
|
2024-02-21 15:04:01 +00:00
|
|
|
|
if($document)
|
|
|
|
|
$accessmode = $document->getGroupAccessMode($u);
|
|
|
|
|
else
|
|
|
|
|
$accessmode = $folder->getGroupAccessMode($u);
|
|
|
|
|
if($accessmode < M_READ || !$g->getUsers())
|
2024-02-08 20:02:12 +00:00
|
|
|
|
$approvers["ng"][] = $g->getId();
|
|
|
|
|
else
|
|
|
|
|
$approvers["g"][] = $g->getId();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-24 12:22:03 +00:00
|
|
|
|
return $approvers;
|
|
|
|
|
} /* }}} */
|
|
|
|
|
|
2020-08-01 11:47:49 +00:00
|
|
|
|
/**
|
|
|
|
|
* Class for creating encrypted api keys
|
|
|
|
|
*
|
|
|
|
|
* <code>
|
|
|
|
|
* <?php
|
|
|
|
|
* $CSRF = new SeedDMS_CSRF($settings->_encryptionKey);
|
|
|
|
|
* $kkk = $CSRF->create_api_key();
|
|
|
|
|
* echo $kkk;
|
|
|
|
|
* echo $CSRF->check_api_key($kkk) ? 'valid' : 'invalid';
|
|
|
|
|
* ?>
|
|
|
|
|
* </code>
|
|
|
|
|
*/
|
2020-07-30 08:55:13 +00:00
|
|
|
|
class SeedDMS_CSRF { /* {{{ */
|
2019-07-12 14:40:38 +00:00
|
|
|
|
|
|
|
|
|
protected $secret;
|
|
|
|
|
|
2020-07-30 08:55:13 +00:00
|
|
|
|
public function __construct($secret) { /* {{{ */
|
2019-07-12 14:40:38 +00:00
|
|
|
|
$this->secret = $secret;
|
2020-07-30 08:55:13 +00:00
|
|
|
|
} /* }}} */
|
2019-07-12 14:40:38 +00:00
|
|
|
|
|
2020-07-30 08:55:13 +00:00
|
|
|
|
public function create_api_key() { /* {{{ */
|
2019-07-12 14:40:38 +00:00
|
|
|
|
return base64_encode($this->encrypt(time().'|'.$_SERVER['REMOTE_ADDR'])); // !change if you dont want IP check
|
2020-07-30 08:55:13 +00:00
|
|
|
|
} /* }}} */
|
2019-07-12 14:40:38 +00:00
|
|
|
|
|
2020-07-30 08:55:13 +00:00
|
|
|
|
public function check_api_key($key, $timeout = 5) { /* {{{ */
|
2019-07-12 14:40:38 +00:00
|
|
|
|
if (empty($key)) exit('Invalid Key');
|
|
|
|
|
|
|
|
|
|
$keys = explode('|', $this->decrypt(base64_decode($key)));
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
isset($key, $keys[0], $keys[1]) &&
|
|
|
|
|
$keys[0] >= (time() - $timeout) &&
|
|
|
|
|
$keys[1] == $_SERVER['REMOTE_ADDR'] // !change if you dont want IP check
|
|
|
|
|
);
|
2020-07-30 08:55:13 +00:00
|
|
|
|
} /* }}} */
|
2019-07-12 14:40:38 +00:00
|
|
|
|
|
2020-07-30 08:55:13 +00:00
|
|
|
|
public function encrypt($string, $key = 'PrivateKey', $method = 'AES-256-CBC') { /* {{{ */
|
2019-07-12 14:40:38 +00:00
|
|
|
|
// hash
|
|
|
|
|
$key = hash('sha256', $key);
|
|
|
|
|
// create iv - encrypt method AES-256-CBC expects 16 bytes
|
|
|
|
|
$iv = substr(hash('sha256', $this->secret), 0, 16);
|
|
|
|
|
// encrypt
|
|
|
|
|
$output = openssl_encrypt($string, $method, $key, 0, $iv);
|
|
|
|
|
// encode
|
|
|
|
|
return base64_encode($output);
|
2020-07-30 08:55:13 +00:00
|
|
|
|
} /* }}} */
|
2019-07-12 14:40:38 +00:00
|
|
|
|
|
2020-07-30 08:55:13 +00:00
|
|
|
|
public function decrypt($string, $key = 'PrivateKey', $method = 'AES-256-CBC') { /* {{{ */
|
2019-07-12 14:40:38 +00:00
|
|
|
|
// hash
|
|
|
|
|
$key = hash('sha256', $key);
|
|
|
|
|
// create iv - encrypt method AES-256-CBC expects 16 bytes
|
|
|
|
|
$iv = substr(hash('sha256', $this->secret), 0, 16);
|
|
|
|
|
// decode
|
|
|
|
|
$string = base64_decode($string);
|
|
|
|
|
// decrypt
|
|
|
|
|
return openssl_decrypt($string, $method, $key, 0, $iv);
|
2020-07-30 08:55:13 +00:00
|
|
|
|
} /* }}} */
|
|
|
|
|
} /* }}} */
|
2019-07-12 14:40:38 +00:00
|
|
|
|
|
2021-05-07 11:22:57 +00:00
|
|
|
|
/**
|
|
|
|
|
* Class to represent a jwt token
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* @category DMS
|
|
|
|
|
* @package SeedDMS
|
|
|
|
|
* @author Uwe Steinmann <uwe@steinmann.cx>
|
|
|
|
|
* @copyright 2016 Uwe Steinmann
|
|
|
|
|
* @version Release: @package_version@
|
|
|
|
|
*/
|
|
|
|
|
class SeedDMS_JwtToken { /* {{{ */
|
|
|
|
|
protected $jwtsecret;
|
|
|
|
|
|
|
|
|
|
public function __construct($jwtsecret = '') { /* {{{ */
|
|
|
|
|
$this->jwtsecret = $jwtsecret;
|
|
|
|
|
} /* }}} */
|
|
|
|
|
|
|
|
|
|
public function jwtEncode($payload) { /* {{{ */
|
|
|
|
|
$header = [
|
|
|
|
|
"alg" => "HS256",
|
|
|
|
|
"typ" => "JWT"
|
|
|
|
|
];
|
|
|
|
|
$encHeader = self::base64UrlEncode(json_encode($header));
|
|
|
|
|
$encPayload = self::base64UrlEncode(json_encode($payload));
|
|
|
|
|
$hash = self::base64UrlEncode(self::calculateHash($encHeader, $encPayload));
|
|
|
|
|
|
|
|
|
|
return "$encHeader.$encPayload.$hash";
|
|
|
|
|
} /* }}} */
|
|
|
|
|
|
|
|
|
|
public function jwtDecode($token) { /* {{{ */
|
|
|
|
|
if (!$this->jwtsecret) return "";
|
|
|
|
|
|
|
|
|
|
$split = explode(".", $token);
|
|
|
|
|
if (count($split) != 3) return "";
|
|
|
|
|
|
|
|
|
|
$hash = self::base64UrlEncode(self::calculateHash($split[0], $split[1]));
|
|
|
|
|
|
|
|
|
|
if (strcmp($hash, $split[2]) != 0) return "";
|
|
|
|
|
return self::base64UrlDecode($split[1]);
|
|
|
|
|
} /* }}} */
|
|
|
|
|
|
|
|
|
|
protected function calculateHash($encHeader, $encPayload) { /* {{{ */
|
|
|
|
|
return hash_hmac("sha256", "$encHeader.$encPayload", $this->jwtsecret, true);
|
|
|
|
|
} /* }}} */
|
|
|
|
|
|
|
|
|
|
protected function base64UrlEncode($str) { /* {{{ */
|
|
|
|
|
return str_replace("/", "_", str_replace("+", "-", trim(base64_encode($str), "=")));
|
|
|
|
|
} /* }}} */
|
|
|
|
|
|
|
|
|
|
protected function base64UrlDecode($payload) { /* {{{ */
|
|
|
|
|
$b64 = str_replace("_", "/", str_replace("-", "+", $payload));
|
|
|
|
|
switch (strlen($b64) % 4) {
|
|
|
|
|
case 2:
|
|
|
|
|
$b64 = $b64 . "=="; break;
|
|
|
|
|
case 3:
|
|
|
|
|
$b64 = $b64 . "="; break;
|
|
|
|
|
}
|
|
|
|
|
return base64_decode($b64);
|
|
|
|
|
} /* }}} */
|
|
|
|
|
} /* }}} */
|
|
|
|
|
|
2020-08-01 11:47:49 +00:00
|
|
|
|
class SeedDMS_FolderTree { /* {{{ */
|
|
|
|
|
|
|
|
|
|
public function __construct($folder, $callback) { /* {{{ */
|
2022-11-18 10:20:38 +00:00
|
|
|
|
$iter = new \SeedDMS\Core\RecursiveFolderIterator($folder);
|
2021-09-30 05:56:50 +00:00
|
|
|
|
$iter2 = new RecursiveIteratorIterator($iter, RecursiveIteratorIterator::SELF_FIRST);
|
2020-08-01 11:47:49 +00:00
|
|
|
|
foreach($iter2 as $ff) {
|
2023-02-23 06:17:17 +00:00
|
|
|
|
call_user_func($callback, $ff, $iter2->getDepth()+1);
|
2020-08-01 11:47:49 +00:00
|
|
|
|
// echo $ff->getID().': '.$ff->getFolderPathPlain().'-'.$ff->getName()."<br />";
|
2021-09-30 05:52:47 +00:00
|
|
|
|
}
|
2020-08-01 11:47:49 +00:00
|
|
|
|
} /* }}} */
|
|
|
|
|
|
|
|
|
|
} /* }}} */
|