Add support for php 5.2 in Solr implementation: - Exception function has two parameters - use of function call_user_func
1152 lines
37 KiB
PHP
Executable File
1152 lines
37 KiB
PHP
Executable File
<?php
|
|
/**
|
|
* upgrade_System.php
|
|
* @package workflow.engine.classes
|
|
*
|
|
* ProcessMaker Open Source Edition
|
|
* Copyright (C) 2004 - 2011 Colosa Inc.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as
|
|
* published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* For more information, contact Colosa Inc, 2566 Le Jeune Rd.,
|
|
* Coral Gables, FL, 33134, USA, or email info@colosa.com.
|
|
*
|
|
*/
|
|
|
|
/**
|
|
* class system for workflow mantanance routines
|
|
*
|
|
* author Erik A.O.<erik@colosa.com>
|
|
* date May 12th, 2010
|
|
* @package workflow.engine.classes
|
|
*
|
|
*/
|
|
|
|
class System {
|
|
|
|
var $sFilename;
|
|
var $sFilesList;
|
|
var $sUpgradeFileList;
|
|
var $aErrors;
|
|
var $aWorkspaces;
|
|
var $sRevision;
|
|
var $sPath;
|
|
var $newSystemClass;
|
|
|
|
/**
|
|
* List currently installed plugins
|
|
*
|
|
* param
|
|
* @return array with the names of the plugins
|
|
*/
|
|
public static function getPlugins() {
|
|
$plugins = array ();
|
|
|
|
foreach (glob(PATH_PLUGINS . "*") as $filename) {
|
|
$info = pathinfo($filename);
|
|
if (array_key_exists("extension", $info) && (strcmp($info["extension"], "php") == 0)) {
|
|
$plugins[] = basename($filename, ".php");
|
|
}
|
|
}
|
|
|
|
sort($plugins, SORT_STRING);
|
|
return $plugins;
|
|
}
|
|
|
|
/**
|
|
* Lists existing workspaces, returning an array of workspaceTools object
|
|
* for each.
|
|
* This is a class method, it does not require an instance.
|
|
*
|
|
* @author Alexandre Rosenfeld <alexandre@colosa.com>
|
|
* @access public
|
|
* @return array of workspace tools objects
|
|
*/
|
|
public static function listWorkspaces() {
|
|
$oDirectory = dir(PATH_DB);
|
|
$aWorkspaces = array();
|
|
foreach (glob(PATH_DB . "*") as $filename) {
|
|
if (is_dir($filename) && file_exists($filename . "/db.php"))
|
|
$aWorkspaces[] = new workspaceTools (basename($filename));
|
|
}
|
|
return $aWorkspaces;
|
|
}
|
|
|
|
/**
|
|
* Get the ProcessMaker version. If version-pmos.php is not found, try to
|
|
* retrieve the version from git.
|
|
*
|
|
* @author Alexandre Rosenfeld <alexandre@colosa.com>
|
|
* @return string system
|
|
*/
|
|
public static function getVersion() {
|
|
if (! defined ( 'PM_VERSION' )) {
|
|
if (file_exists ( PATH_METHODS . 'login/version-pmos.php' )) {
|
|
include (PATH_METHODS . 'login/version-pmos.php');
|
|
} else {
|
|
$version = self::getVersionFromGit();
|
|
if ($version === false)
|
|
$version = 'Development Version';
|
|
define ( 'PM_VERSION', $version );
|
|
}
|
|
}
|
|
return PM_VERSION;
|
|
}
|
|
|
|
/**
|
|
* Get the branch and tag information from a git repository.
|
|
*
|
|
* @author Alexandre Rosenfeld <alexandre@colosa.com>
|
|
* @return string branch and tag information
|
|
*/
|
|
public static function getVersionFromGit($dir = NULL) {
|
|
if ($dir == NULL)
|
|
$dir = PATH_TRUNK;
|
|
if (!file_exists("$dir/.git"))
|
|
return false;
|
|
if (exec("cd $dir && git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e 's/^* \(.*\)$/(Branch \\1)/'", $target)) {
|
|
exec("cd $dir && git describe", $target);
|
|
return implode(' ', $target);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Get system information
|
|
*
|
|
* param
|
|
* @return array with system information
|
|
*/
|
|
public static function getSysInfo() {
|
|
$ipe = explode(" ", $_SERVER['SSH_CONNECTION']);
|
|
|
|
if( getenv('HTTP_CLIENT_IP') ) {
|
|
$ip = getenv('HTTP_CLIENT_IP');
|
|
} elseif( getenv('HTTP_X_FORWARDED_FOR') ) {
|
|
$ip = getenv('HTTP_X_FORWARDED_FOR');
|
|
} else {
|
|
$ip = getenv('REMOTE_ADDR');
|
|
}
|
|
|
|
/* For distros with the lsb_release, this returns a one-line description of
|
|
* the distro name, such as "CentOS release 5.3 (Final)" or "Ubuntu 10.10"
|
|
*/
|
|
$distro = exec("lsb_release -d -s 2> /dev/null");
|
|
|
|
/* For distros without lsb_release, we look for *release (such as
|
|
* redhat-release, gentoo-release, SuSE-release, etc) or *version (such as
|
|
* debian_version, slackware-version, etc)
|
|
*/
|
|
if (empty($distro)) {
|
|
foreach (glob("/etc/*release") as $filename) {
|
|
$distro = trim(file_get_contents($filename));
|
|
if (!empty($distro))
|
|
break;
|
|
}
|
|
if (empty($distro)) {
|
|
foreach (glob("/etc/*version") as $filename) {
|
|
$distro = trim(file_get_contents($filename));
|
|
if (!empty($distro))
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* CentOS returns a string with quotes, remove them and append
|
|
* the OS name (such as LINUX, WINNT, DARWIN, etc)
|
|
*/
|
|
$distro = trim($distro, "\"") . " (" . PHP_OS . ")";
|
|
|
|
$Fields = array();
|
|
$Fields['SYSTEM'] = $distro;
|
|
$Fields['PHP'] = phpversion();
|
|
$Fields['PM_VERSION'] = self::getVersion();
|
|
$Fields['SERVER_ADDR'] = $ipe[2]; //lookup($ipe[2]);
|
|
$Fields['IP'] = $ipe[0]; //lookup($ipe[0]);
|
|
|
|
$Fields['PLUGINS_LIST'] = System::getPlugins();
|
|
|
|
return $Fields;
|
|
}
|
|
|
|
public static function listPoFiles() {
|
|
$folders = glob(PATH_CORE . '/content/translations/*');
|
|
|
|
$items = glob(PATH_CORE . '/content/translations/*.po');
|
|
foreach ($folders as $folder) {
|
|
if (is_dir($folder)) {
|
|
$add = glob($folder . "/*.po");
|
|
$items = array_merge($items, $add);
|
|
}
|
|
}
|
|
|
|
return $items;
|
|
}
|
|
|
|
public static function verifyChecksum() {
|
|
if (!file_exists(PATH_TRUNK . "checksum.txt"))
|
|
return false;
|
|
$lines = explode("\n", file_get_contents(PATH_TRUNK . "checksum.txt"));
|
|
$result = array("diff" => array(), "missing" => array());
|
|
foreach ($lines as $line) {
|
|
if (empty($line))
|
|
continue;
|
|
list($checksum, $empty, $filename) = explode(" ", $line);
|
|
//Skip xmlform because these files always change.
|
|
if (strpos($filename, "/xmlform/") !== false)
|
|
continue;
|
|
if (file_exists(realpath($filename))) {
|
|
if (strcmp($checksum, md5_file(realpath($filename))) != 0) {
|
|
$result['diff'][] = $filename;
|
|
}
|
|
} else {
|
|
$result['missing'][] = $filename;
|
|
}
|
|
}
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* This function checks files to do updated to pm
|
|
*
|
|
*
|
|
* @name verifyFileForUpgrade
|
|
*
|
|
* param
|
|
* @return boolean
|
|
*/
|
|
function verifyFileForUpgrade()
|
|
{
|
|
$upgradeFilename = isset($_FILES['form']['name']['UPGRADE_FILENAME']) ? $_FILES['form']['name']['UPGRADE_FILENAME'] : '';
|
|
$tempFilename = isset($_FILES['form']['tmp_name']['UPGRADE_FILENAME']) ? $_FILES['form']['tmp_name']['UPGRADE_FILENAME'] : '';
|
|
$this->sRevision = str_replace('.tar.gz', '', str_replace('pmos-patch-', '', $upgradeFilename));
|
|
$sTemFilename = $tempFilename;
|
|
$this->sFilename = PATH_DATA . 'upgrade' . PATH_SEP . $upgradeFilename;
|
|
$this->sPath = dirname($this->sFilename) . PATH_SEP;
|
|
G::mk_dir(PATH_DATA . 'upgrade');
|
|
if( ! move_uploaded_file($sTemFilename, $this->sFilename) ) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* This function gets files to do updated to pm
|
|
*
|
|
*
|
|
* @name getUpgradedFilesList
|
|
*
|
|
* param
|
|
* @return void
|
|
*/
|
|
function getUpgradedFilesList()
|
|
{
|
|
G::LoadClass('archive');
|
|
$this->sFilesList = new gzip_file($this->sFilename);
|
|
$this->sFilesList->set_options(array (
|
|
'basedir' => dirname($this->sFilename),
|
|
'overwrite' => 1
|
|
));
|
|
$this->sFilesList->extract_files();
|
|
if( count($this->sFilesList->error) > 0 ) {
|
|
$msg = '';
|
|
foreach( $this->sFilesList->error as $key => $val ) {
|
|
$msg .= $val . "\n";
|
|
}
|
|
throw new Exception($msg);
|
|
}
|
|
if( count($this->sFilesList->files) == 0 ) {
|
|
throw new Exception('The uploaded file is an invalid patch file.');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This function checks to do updated for boot
|
|
*
|
|
*
|
|
* @name verifyForBootstrapUpgrade
|
|
*
|
|
* param
|
|
* @return boolean
|
|
*/
|
|
function verifyForBootstrapUpgrade()
|
|
{
|
|
foreach( $this->sFilesList->files as $sFile ) {
|
|
if( basename($sFile) == 'schema.xml' ) {
|
|
$this->newSystemClass = $sFile;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* This function updates to the files
|
|
*
|
|
*
|
|
* @name upgrade
|
|
*
|
|
* param
|
|
* @return array
|
|
*/
|
|
function upgrade()
|
|
{
|
|
//get special files
|
|
$sListFile = '';
|
|
$sCheckListFile = '';
|
|
$sPatchVersionFile = '';
|
|
$sPoFile = '';
|
|
$sSchemaFile = '';
|
|
$sSchemaRBACFile = '';
|
|
foreach( $this->sFilesList->files as $sFile ) {
|
|
if( basename($sFile) == 'schema.xml' ) {
|
|
if( strpos($sFile, '/rbac/engine/') === false ) {
|
|
$sOldSchema = '';
|
|
$sSchemaFile = $sFile;
|
|
} else {
|
|
$sOldSchemaRBAC = '';
|
|
$sSchemaRBACFile = $sFile;
|
|
}
|
|
}
|
|
|
|
//files.lst
|
|
if( basename($sFile) == 'files.lst' ) {
|
|
$this->sUpgradeFileList = $sFile;
|
|
}
|
|
|
|
//files.lst
|
|
if( basename($sFile) == 'patch.version.txt' ) {
|
|
$sPatchVersionFile = $sFile;
|
|
}
|
|
|
|
//files.rev.txt
|
|
if( substr(basename($sFile), 0, 6) == 'files.' && substr(basename($sFile), - 4) == '.txt' ) {
|
|
$sCheckListFile = $sFile;
|
|
}
|
|
|
|
//po files
|
|
$sExtension = substr($sFile, strrpos($sFile, '.') + 1, strlen($sFile));
|
|
if( $sExtension == 'po' ) {
|
|
$sPoFile = $sFile;
|
|
}
|
|
}
|
|
|
|
$pmVersion = explode('-', self::getVersion());
|
|
array_shift($pmVersion);
|
|
$patchVersion = explode('-', $this->sRevision);
|
|
|
|
if( $sPatchVersionFile != '' && file_exists($sPatchVersionFile) ) {
|
|
$this->sRevision = file_get_contents($sPatchVersionFile);
|
|
$patchVersion = explode('-', $this->sRevision);
|
|
}
|
|
|
|
if( ! file_exists(PATH_DATA . 'log' . PATH_SEP) ) {
|
|
G::mk_dir(PATH_DATA . 'log' . PATH_SEP);
|
|
}
|
|
|
|
//empty query log
|
|
$sqlLog = PATH_DATA . 'log' . PATH_SEP . "query.log";
|
|
$fp = fopen($sqlLog, "w+");
|
|
fwrite($fp, "");
|
|
fclose($fp);
|
|
|
|
$aEnvironmentsUpdated = array ();
|
|
$aEnvironmentsDiff = array ();
|
|
$aErrors = array ();
|
|
|
|
//now will verify each folder and file has permissions to write and add files.
|
|
if( $this->sUpgradeFileList != '' ) {
|
|
$bCopySchema = true;
|
|
$oFile = fopen($this->sUpgradeFileList, 'r');
|
|
while( $sLine = trim(fgets($oFile)) ) {
|
|
$sLine = substr($sLine, 1);
|
|
$aAux = explode(PATH_SEP, $sLine);
|
|
array_shift($aAux);
|
|
$sFilePath = implode(PATH_SEP, $aAux);
|
|
$targetFileName = PATH_TRUNK . $sFilePath;
|
|
if( ! is_dir($this->sPath . 'processmaker' . PATH_SEP . $sFilePath) ) {
|
|
//if we are updating or deleting a file
|
|
if( file_exists($this->sPath . 'processmaker' . PATH_SEP . $sFilePath) ) {
|
|
if( file_exists($targetFileName) ) {
|
|
if( ! is_writable($targetFileName) ) {
|
|
throw (new Exception("File $targetFileName is not writable."));
|
|
}
|
|
} else {
|
|
//verify parent folder, and ask if that folder is writable
|
|
$auxDir = explode('/', $targetFileName);
|
|
array_pop($auxDir);
|
|
$parentDir = implode('/', $auxDir);
|
|
if( ! is_dir($parentDir) ) {
|
|
//throw (new Exception("File $parentDir is an invalid directory."));
|
|
G::mk_dir($parentDir);
|
|
}
|
|
if( ! is_writable($parentDir) ) {
|
|
throw (new Exception("Directory $parentDir is not writable."));
|
|
}
|
|
}
|
|
} else {
|
|
//delete unused files
|
|
if( file_exists($targetFileName) && ! is_writable($targetFileName) ) {
|
|
throw (new Exception("File $targetFileName is not writable."));
|
|
}
|
|
}
|
|
} else {
|
|
$dirName = PATH_TRUNK . $sFilePath;
|
|
if( $dirName[strlen($dirName) - 1] == '/' )
|
|
$dirName = substr($dirName, 0, strlen($dirName) - 1);
|
|
$auxDir = explode('/', $dirName);
|
|
array_pop($auxDir);
|
|
$parentDir = implode('/', $auxDir);
|
|
if( file_exists($dirName) ) {
|
|
if( is_writable($dirName) ) {
|
|
//print "e. ok $dirName <br>";
|
|
} else {
|
|
throw (new Exception("$dirName is not writable"));
|
|
}
|
|
} else {
|
|
if( is_writable($parentDir) ) {
|
|
mkdir($dirName, 0777);
|
|
} else {
|
|
throw (new Exception("$dirName does not exist and parent folder $parentDir is not writable"));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//processing list file files.lst
|
|
if( $this->sUpgradeFileList != '' ) {
|
|
$bCopySchema = true;
|
|
$oFile = fopen($this->sUpgradeFileList, 'r');
|
|
while( $sLine = trim(fgets($oFile)) ) {
|
|
$action = substr($sLine, 0, 1);
|
|
$sLine = substr($sLine, 1);
|
|
$aAux = explode(PATH_SEP, $sLine);
|
|
array_shift($aAux);
|
|
$sFilePath = implode(PATH_SEP, $aAux);
|
|
$targetFileName = PATH_TRUNK . $sFilePath;
|
|
if( strtoupper($action) != 'D'){
|
|
if( ! is_dir($this->sPath . 'processmaker' . PATH_SEP . $sFilePath) ) {
|
|
if( file_exists($this->sPath . 'processmaker' . PATH_SEP . $sFilePath) ) {
|
|
if( strpos($sFilePath, 'schema.xml') !== false && $bCopySchema ) {
|
|
$bCopySchema = false;
|
|
$sOldSchema = str_replace('schema.xml', 'schema_' . date('Ymd') . '.xml', PATH_TRUNK . $sFilePath);
|
|
$this->pm_copy(PATH_TRUNK . $sFilePath, $sOldSchema);
|
|
}
|
|
if( file_exists($targetFileName) ) {
|
|
if( is_writable($targetFileName) ) {
|
|
$this->pm_copy($this->sPath . 'processmaker' . PATH_SEP . $sFilePath, $targetFileName);
|
|
@chmod($targetFileName, 0666);
|
|
} else
|
|
throw (new Exception("Failed to open file: Permission denied in $targetFileName."));
|
|
} else {
|
|
$this->pm_copy($this->sPath . 'processmaker' . PATH_SEP . $sFilePath, $targetFileName);
|
|
@chmod($targetFileName, 0666);
|
|
}
|
|
} else { //delete unused files
|
|
if( file_exists($targetFileName) ) {
|
|
@unlink($targetFileName);
|
|
}
|
|
}
|
|
} else {
|
|
if( ! file_exists(PATH_TRUNK . $sFilePath) ) {
|
|
mkdir(PATH_TRUNK . $sFilePath, 0777);
|
|
}
|
|
}
|
|
} else if( file_exists(PATH_TRUNK . $sFilePath) && $sFilePath != 'workflow/engine/gulliver' ) {
|
|
@unlink(PATH_TRUNK . $sFilePath);
|
|
}
|
|
}
|
|
}
|
|
|
|
//end files copied.
|
|
$missedFiles = '';
|
|
$distinctFiles = '';
|
|
$missed = 0;
|
|
$distinct = 0;
|
|
//checking files of this installation server with the files in Repository Code.
|
|
if( $sCheckListFile != '' ) {
|
|
$fp = fopen($sCheckListFile, 'r');
|
|
while( ! feof($fp) ) {
|
|
$line = explode(' ', fgets($fp));
|
|
if( count($line) == 3 ) {
|
|
$file = PATH_TRUNK . trim($line[2]);
|
|
if( is_readable($file) ) {
|
|
$size = sprintf("%07d", filesize($file));
|
|
$checksum = sprintf("%010u", crc32(file_get_contents($file)));
|
|
if( ! ($line[0] == $size && $line[1] == $checksum) && substr($file, - 4) != '.xml' ) {
|
|
$distinctFiles .= $file . "\n";
|
|
$distinct ++;
|
|
}
|
|
} else {
|
|
$missedFiles .= $file . "\n";
|
|
$missed ++;
|
|
}
|
|
}
|
|
}
|
|
fclose($fp);
|
|
}
|
|
|
|
if( $missed > 0 )
|
|
$aErrors[] = "Warning: there are $missed missed files. ";
|
|
$aErrors[] = $missedFiles;
|
|
|
|
if( $distinct > 0 ) {
|
|
$aErrors[] = "Warning: there are $distinct files with differences. ";
|
|
$aErrors[] = $distinctFiles;
|
|
}
|
|
|
|
//now include the files and classes needed for upgrade databases, dont move this files, because we
|
|
//are getting the last files in this point. Even the files was in the patch we will take the new ones.
|
|
include PATH_METHODS . PATH_SEP . 'setup' . PATH_SEP . 'upgrade_RBAC.php';
|
|
G::LoadClass('languages');
|
|
G::LoadSystem('database_mysql');
|
|
|
|
$bForceXml = true;
|
|
$bParseSchema = true;
|
|
$bParseSchemaRBAC = true;
|
|
$oDirectory = dir(PATH_DB);
|
|
|
|
//count db.php files ( workspaces )
|
|
$aWorkspaces = array ();
|
|
while( ($sObject = $oDirectory->read()) ) {
|
|
if( is_dir(PATH_DB . $sObject) && substr($sObject, 0, 1) != '.' && file_exists(PATH_DB . $sObject . PATH_SEP . 'db.php') ) {
|
|
$aWorkspaces[] = $sObject;
|
|
}
|
|
}
|
|
$aUpgradeData = array ();
|
|
$aUpgradeData['workspaces'] = $aWorkspaces;
|
|
$aUpgradeData['wsQuantity'] = count($aWorkspaces);
|
|
$aUpgradeData['sPoFile'] = $sPoFile;
|
|
$aUpgradeData['bForceXmlPoFile'] = true;
|
|
$aUpgradeData['sSchemaFile'] = $sSchemaFile;
|
|
$aUpgradeData['sSchemaRBACFile'] = $sSchemaRBACFile;
|
|
|
|
file_put_contents(PATH_DATA . 'log' . PATH_SEP . "upgrade.data.bin", serialize($aUpgradeData));
|
|
|
|
$sSchemaFile = '';
|
|
$sPoFile = '';
|
|
$sSchemaRBACFile = '';
|
|
|
|
$oDirectory = dir(PATH_DB);
|
|
while( ($sObject = $oDirectory->read()) ) {
|
|
if( is_dir(PATH_DB . $sObject) && substr($sObject, 0, 1) != '.' ) {
|
|
if( file_exists(PATH_DB . $sObject . PATH_SEP . 'db.php') ) {
|
|
|
|
eval($this->getDatabaseCredentials(PATH_DB . $sObject . PATH_SEP . 'db.php'));
|
|
|
|
}
|
|
$aEnvironmentsUpdated[] = $sObject;
|
|
$aEnvironmentsDiff[] = $sObject;
|
|
}
|
|
}
|
|
$oDirectory->close();
|
|
@unlink(PATH_CORE . 'config/_databases_.php');
|
|
|
|
//clean up smarty directory
|
|
$oDirectory = dir(PATH_SMARTY_C);
|
|
while( $sFilename = $oDirectory->read() ) {
|
|
if( ($sFilename != '.') && ($sFilename != '..') ) {
|
|
@unlink(PATH_SMARTY_C . PATH_SEP . $sFilename);
|
|
}
|
|
}
|
|
|
|
//clean up xmlform folders
|
|
$sDir = PATH_C . 'xmlform';
|
|
if( file_exists($sDir) && is_dir($sDir) ) {
|
|
$oDirectory = dir($sDir);
|
|
while( $sObjectName = $oDirectory->read() ) {
|
|
if( ($sObjectName != '.') && ($sObjectName != '..') ) {
|
|
if( is_dir($sDir . PATH_SEP . $sObjectName) ) {
|
|
$this->rm_dir($sDir . PATH_SEP . $sObjectName);
|
|
}
|
|
}
|
|
}
|
|
$oDirectory->close();
|
|
}
|
|
|
|
//changing the PM_VERSION according the patch file name
|
|
$oFile = fopen(PATH_METHODS . 'login/version-pmos.php', 'w+');
|
|
if( isset($this->sRevision) && $this->sRevision != '' ) {
|
|
fwrite($oFile, "<?php\n define ( 'PM_VERSION' , str_replace ( ' ','', '1.6-" . $this->sRevision . "' ));\n?>");
|
|
} else {
|
|
fwrite($oFile, "<?php\n define ( 'PM_VERSION' , str_replace ( ' ','', 'unknow' ));\n?>");
|
|
}
|
|
fclose($oFile);
|
|
$ver = explode("-", $this->sRevision);
|
|
$this->aErrors = $aErrors;
|
|
$this->aWorkspaces = $aWorkspaces;
|
|
|
|
return $ver;
|
|
}
|
|
|
|
/**
|
|
* This function does to clean up to the upgrate directory
|
|
*
|
|
*
|
|
* @name cleanupUpgradeDirectory
|
|
*
|
|
* param
|
|
* @return array
|
|
*/
|
|
function cleanupUpgradeDirectory()
|
|
{
|
|
$this->rm_dir(PATH_DATA . 'upgrade' . PATH_SEP . 'processmaker');
|
|
}
|
|
|
|
/**
|
|
* This function removes a directory
|
|
*
|
|
*
|
|
* @name rm_dir
|
|
*
|
|
* @param string $dirName
|
|
* @return void
|
|
*/
|
|
function rm_dir($dirName)
|
|
{
|
|
if( empty($dirName) ) {
|
|
return;
|
|
}
|
|
if( file_exists($dirName) ) {
|
|
if( ! is_readable($dirName) ) {
|
|
throw (new Exception("directory '$dirName' is not readable"));
|
|
}
|
|
$dir = dir($dirName);
|
|
while( $file = $dir->read() ) {
|
|
if( $file != '.' && $file != '..' ) {
|
|
if( is_dir($dirName . PATH_SEP . $file) ) {
|
|
$this->rm_dir($dirName . PATH_SEP . $file);
|
|
} else {
|
|
//@unlink($dirName. PATH_SEP .$file) or die('File '.$dirName. PATH_SEP .$file.' couldn\'t be deleted!');
|
|
@unlink($dirName . PATH_SEP . $file);
|
|
}
|
|
}
|
|
}
|
|
|
|
$folder = opendir($dirName . PATH_SEP . $file);
|
|
closedir($folder);
|
|
@rmdir($dirName . PATH_SEP . $file);
|
|
} else {
|
|
//
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This function creates a directory
|
|
*
|
|
*
|
|
* @name pm_copy
|
|
*
|
|
* @param string $source
|
|
* @param string $target
|
|
* @return void
|
|
*/
|
|
function pm_copy($source, $target)
|
|
{
|
|
if( ! is_dir(dirname($target)) ) {
|
|
G::mk_dir(dirname($target));
|
|
}
|
|
if( ! copy($source, $target) ) {
|
|
krumo($source);
|
|
krumo($target);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This function gets info about db
|
|
*
|
|
*
|
|
* @name getDatabaseCredentials
|
|
*
|
|
* @param string $dbFile
|
|
* @return $sContent
|
|
*/
|
|
function getDatabaseCredentials($dbFile)
|
|
{
|
|
$sContent = file_get_contents($dbFile);
|
|
$sContent = str_replace('<?php', '', $sContent);
|
|
$sContent = str_replace('<?', '', $sContent);
|
|
$sContent = str_replace('?>', '', $sContent);
|
|
$sContent = str_replace('define', '', $sContent);
|
|
$sContent = str_replace("('", '$', $sContent);
|
|
$sContent = str_replace("',", '=', $sContent);
|
|
$sContent = str_replace(");", ';', $sContent);
|
|
return $sContent;
|
|
}
|
|
|
|
/**
|
|
* Retrieves the system schema.
|
|
*
|
|
* @return schema content in an array
|
|
*/
|
|
public static function getSystemSchema() {
|
|
return System::getSchema(PATH_TRUNK . "workflow/engine/config/schema.xml");
|
|
}
|
|
|
|
/**
|
|
* Retrieves the schema for a plugin.
|
|
*
|
|
* @param string $pluginName name of the plugin
|
|
* @return $sContent
|
|
*/
|
|
public static function getPluginSchema($pluginName) {
|
|
if (file_exists(PATH_PLUGINS . $pluginName . "/config/schema.xml"))
|
|
return System::getSchema(PATH_PLUGINS . $pluginName . "/config/schema.xml");
|
|
else
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Retrieves a schema array from a file.
|
|
*
|
|
* @param string $sSchemaFile schema filename
|
|
* @return $sContent
|
|
*/
|
|
public static function getSchema($sSchemaFile) {
|
|
/* This is the MySQL mapping that Propel uses (from MysqlPlatform.php) */
|
|
$mysqlTypes = array(
|
|
'NUMERIC' => "DECIMAL",
|
|
'LONGVARCHAR' => "MEDIUMTEXT",
|
|
'TIMESTAMP' => "DATETIME",
|
|
'BU_TIMESTAMP' => "DATETIME",
|
|
'BINARY' => "BLOB",
|
|
'VARBINARY' => "MEDIUMBLOB",
|
|
'LONGVARBINARY' => "LONGBLOB",
|
|
'BLOB' => "LONGBLOB",
|
|
'CLOB' => "LONGTEXT",
|
|
/* This is not from Propel, but is required to get INT right */
|
|
'INTEGER' => "INT");
|
|
|
|
$aSchema = array();
|
|
$oXml = new DomDocument();
|
|
$oXml->load($sSchemaFile);
|
|
$aTables = $oXml->getElementsByTagName('table');
|
|
foreach ($aTables as $oTable) {
|
|
$aPrimaryKeys = array();
|
|
$sTableName = $oTable->getAttribute('name');
|
|
$aSchema[$sTableName] = array();
|
|
$aColumns = $oTable->getElementsByTagName('column');
|
|
foreach ($aColumns as $oColumn) {
|
|
$sColumName = $oColumn->getAttribute('name');
|
|
|
|
/* Get the field type. Propel uses VARCHAR if nothing else is specified */
|
|
$type = $oColumn->hasAttribute('type') ? strtoupper($oColumn->getAttribute('type')) : "VARCHAR";
|
|
|
|
/* Convert type to MySQL type according to Propel */
|
|
if (array_key_exists($type, $mysqlTypes))
|
|
$type = $mysqlTypes[$type];
|
|
|
|
$size = $oColumn->hasAttribute('size') ? $oColumn->getAttribute('size') : NULL;
|
|
/* Add default sizes from MySQL */
|
|
if ($type == "TINYINT" && !$size)
|
|
$size = "4";
|
|
if ($type == "INT" && !$size)
|
|
$size = "11";
|
|
|
|
if ($size)
|
|
$type = "$type($size)";
|
|
|
|
$required = $oColumn->hasAttribute('required') ? $oColumn->getAttribute('required') : NULL;
|
|
/* Convert $required to a bool */
|
|
$required = (in_array (strtolower ($required), array('1', 'true')));
|
|
|
|
$default = $oColumn->hasAttribute('default') ? $oColumn->getAttribute('default') : NULL;
|
|
|
|
$primaryKey = $oColumn->hasAttribute('primaryKey') ? $oColumn->getAttribute('primaryKey') : NULL;
|
|
/* Convert $primaryKey to a bool */
|
|
$primaryKey = (in_array (strtolower ($primaryKey), array('1', 'true')));
|
|
if ($primaryKey)
|
|
$aPrimaryKeys[] = $sColumName;
|
|
|
|
$aSchema[$sTableName][$sColumName] = array(
|
|
'Field' => $sColumName,
|
|
'Type' => $type,
|
|
'Null' => $required ? "NO" : "YES",
|
|
'Default' => $default
|
|
);
|
|
}
|
|
|
|
if ( is_array($aPrimaryKeys) && count($aPrimaryKeys) > 0 ) {
|
|
$aSchema[$sTableName]['INDEXES']['PRIMARY'] = $aPrimaryKeys;
|
|
}
|
|
$aIndexes = $oTable->getElementsByTagName('index');
|
|
foreach ($aIndexes as $oIndex) {
|
|
$aIndex = array();
|
|
$aIndexesColumns = $oIndex->getElementsByTagName('index-column');
|
|
foreach ($aIndexesColumns as $oIndexColumn) {
|
|
$aIndex[] = $oIndexColumn->getAttribute('name');
|
|
}
|
|
$aSchema[$sTableName]['INDEXES'][ $oIndex->getAttribute('name') ] = $aIndex;
|
|
}
|
|
}
|
|
return $aSchema;
|
|
}
|
|
|
|
/**
|
|
* Returns the difference between two schema arrays
|
|
*
|
|
* @param array $aOldSchema original schema array
|
|
* @param array $aNewSchema new schema array
|
|
* @return array with tablesToAdd, tablesToAlter, tablesWithNewIndex and tablesToAlterIndex
|
|
*/
|
|
public static function compareSchema($aOldSchema, $aNewSchema) {
|
|
//$aChanges = array('tablesToDelete' => array(), 'tablesToAdd' => array(), 'tablesToAlter' => array());
|
|
//Tables to delete, but this is disabled
|
|
//foreach ($aOldSchema as $sTableName => $aColumns) {
|
|
// if ( !isset($aNewSchema[$sTableName])) {
|
|
// if (!in_array($sTableName, array('KT_APPLICATION', 'KT_DOCUMENT', 'KT_PROCESS'))) {
|
|
// $aChanges['tablesToDelete'][] = $sTableName;
|
|
// }
|
|
// }
|
|
//}
|
|
|
|
$aChanges = array('tablesToAdd' => array(), 'tablesToAlter' => array(), 'tablesWithNewIndex' => array(), 'tablesToAlterIndex'=> array());
|
|
|
|
//new tables to create and alter
|
|
foreach ($aNewSchema as $sTableName => $aColumns) {
|
|
if (!isset($aOldSchema[$sTableName])) {
|
|
$aChanges['tablesToAdd'][$sTableName] = $aColumns;
|
|
}
|
|
else {
|
|
//drop old columns
|
|
foreach ($aOldSchema[$sTableName] as $sColumName => $aParameters) {
|
|
if (!isset($aNewSchema[$sTableName][$sColumName])) {
|
|
if (!isset($aChanges['tablesToAlter'][$sTableName])) {
|
|
$aChanges['tablesToAlter'][$sTableName] = array('DROP' => array(), 'ADD' => array(), 'CHANGE' => array());
|
|
}
|
|
$aChanges['tablesToAlter'][$sTableName]['DROP'][$sColumName] = $sColumName;
|
|
}
|
|
}
|
|
|
|
//create new columns
|
|
//foreach ($aNewSchema[$sTableName] as $sColumName => $aParameters) {
|
|
foreach ($aColumns as $sColumName => $aParameters) {
|
|
if ($sColumName != 'INDEXES') {
|
|
if (!isset($aOldSchema[$sTableName][$sColumName])) { //this column doesnt exist in oldschema
|
|
if (!isset($aChanges['tablesToAlter'][$sTableName])) {
|
|
$aChanges['tablesToAlter'][$sTableName] = array('DROP' => array(), 'ADD' => array(), 'CHANGE' => array());
|
|
}
|
|
$aChanges['tablesToAlter'][$sTableName]['ADD'][$sColumName] = $aParameters;
|
|
}
|
|
else { //the column exists
|
|
$newField = $aNewSchema[$sTableName][$sColumName];
|
|
$oldField = $aOldSchema[$sTableName][$sColumName];
|
|
//both are null, no change is required
|
|
if ( !isset($newField['Default']) && !isset($oldField['Default'])) $changeDefaultAttr = false;
|
|
//one of them is null, change IS required
|
|
if ( !isset($newField['Default']) && isset($oldField['Default']) && $oldField['Default']!= '') $changeDefaultAttr = true;
|
|
if ( isset($newField['Default']) && !isset($oldField['Default'])) $changeDefaultAttr = true;
|
|
//both are defined and they are different.
|
|
if ( isset($newField['Default']) && isset($oldField['Default']) ) {
|
|
if ( $newField['Default'] != $oldField['Default'] )
|
|
$changeDefaultAttr = true;
|
|
else
|
|
$changeDefaultAttr = false;
|
|
}
|
|
//special cases
|
|
// BLOB and TEXT columns cannot have DEFAULT values. http://dev.mysql.com/doc/refman/5.0/en/blob.html
|
|
if ( in_array(strtolower($newField['Type']), array('text','mediumtext') ) )
|
|
$changeDefaultAttr = false;
|
|
|
|
//#1067 - Invalid default value for datetime field
|
|
if ( in_array($newField['Type'], array('datetime')) && isset($newField['Default']) && $newField['Default']== '' )
|
|
$changeDefaultAttr = false;
|
|
|
|
//#1067 - Invalid default value for int field
|
|
if ( substr($newField['Type'], 0, 3 ) == "int" && isset($newField['Default']) && $newField['Default']== '' )
|
|
$changeDefaultAttr = false;
|
|
|
|
//if any difference exists, then insert the difference in aChanges
|
|
if ( strcasecmp($newField['Field'], $oldField['Field']) !== 0 ||
|
|
strcasecmp($newField['Type'], $oldField['Type']) !== 0 ||
|
|
strcasecmp($newField['Null'], $oldField['Null']) !== 0 ||
|
|
$changeDefaultAttr ) {
|
|
if (!isset($aChanges['tablesToAlter'][$sTableName])) {
|
|
$aChanges['tablesToAlter'][$sTableName] = array('DROP' => array(), 'ADD' => array(), 'CHANGE' => array());
|
|
}
|
|
$aChanges['tablesToAlter'][$sTableName]['CHANGE'][$sColumName]['Field'] = $newField['Field'];
|
|
$aChanges['tablesToAlter'][$sTableName]['CHANGE'][$sColumName]['Type'] = $newField['Type'];
|
|
$aChanges['tablesToAlter'][$sTableName]['CHANGE'][$sColumName]['Null'] = $newField['Null'];
|
|
if ( isset($newField['Default']) )
|
|
$aChanges['tablesToAlter'][$sTableName]['CHANGE'][$sColumName]['Default'] = $newField['Default'];
|
|
else
|
|
$aChanges['tablesToAlter'][$sTableName]['CHANGE'][$sColumName]['Default'] = null;
|
|
|
|
}
|
|
}
|
|
} //only columns, no the indexes column
|
|
}//foreach $aColumns
|
|
|
|
//now check the indexes of table
|
|
if ( isset($aNewSchema[$sTableName]['INDEXES']) ) {
|
|
foreach ( $aNewSchema[$sTableName]['INDEXES'] as $indexName => $indexFields ) {
|
|
if (!isset( $aOldSchema[$sTableName]['INDEXES'][$indexName]) ) {
|
|
if (!isset($aChanges['tablesWithNewIndex'][$sTableName])) {
|
|
$aChanges['tablesWithNewIndex'][$sTableName] = array();
|
|
}
|
|
$aChanges['tablesWithNewIndex'][$sTableName][$indexName] = $indexFields;
|
|
}
|
|
else {
|
|
if ( $aOldSchema[$sTableName]['INDEXES'][$indexName] != $indexFields ) {
|
|
if (!isset($aChanges['tablesToAlterIndex'][$sTableName])) {
|
|
$aChanges['tablesToAlterIndex'][$sTableName] = array();
|
|
}
|
|
$aChanges['tablesToAlterIndex'][$sTableName][$indexName] = $indexFields;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} //for-else table exists
|
|
} //for new schema
|
|
return $aChanges;
|
|
}
|
|
|
|
|
|
function getEmailConfiguration()
|
|
{
|
|
G::LoadClass('configuration');
|
|
$conf = new Configurations();
|
|
$config = $conf->load('Emails');
|
|
|
|
return $config;
|
|
}
|
|
|
|
function getSkingList()
|
|
{
|
|
//Create Skins custom folder if it doesn't exists
|
|
if(!is_dir(PATH_CUSTOM_SKINS)){
|
|
G::verifyPath(PATH_CUSTOM_SKINS, true);
|
|
}
|
|
|
|
//Get Skin Config files
|
|
$skinListArray = array();
|
|
$customSkins = glob(PATH_CUSTOM_SKINS . "*/config.xml");
|
|
|
|
// getting al base skins
|
|
$baseSkins = glob(G::ExpandPath("skinEngine") . '*/config.xml');
|
|
|
|
// filtering no public skins (uxs, simplified)
|
|
foreach ($baseSkins as $i => $skinName) {
|
|
if (strpos($skinName, 'simplified') !== false || strpos($skinName, 'uxs') !== false) {
|
|
unset($baseSkins[$i]);
|
|
}
|
|
}
|
|
|
|
$customSkins = array_merge($baseSkins, $customSkins);
|
|
|
|
//Read and parse each Configuration File
|
|
foreach ($customSkins as $key => $configInformation) {
|
|
$folderId = basename(dirname($configInformation));
|
|
|
|
if ($folderId == 'base') {
|
|
$folderId = 'classic';
|
|
}
|
|
|
|
$xmlConfiguration = file_get_contents($configInformation);
|
|
$xmlConfigurationObj = G::xmlParser($xmlConfiguration);
|
|
|
|
if (isset($xmlConfigurationObj->result['skinConfiguration'])) {
|
|
$skinInformationArray = $skinFilesArray = $xmlConfigurationObj->result['skinConfiguration']['__CONTENT__']['information']['__CONTENT__'];
|
|
$res = array();
|
|
$res['SKIN_FOLDER_ID'] = strtolower($folderId);
|
|
|
|
foreach ($skinInformationArray as $keyInfo => $infoValue) {
|
|
$res['SKIN_' . strtoupper($keyInfo)] = $infoValue['__VALUE__'];
|
|
}
|
|
|
|
$skinListArray['skins'][] = $res;
|
|
}
|
|
}
|
|
|
|
$skinListArray['currentSkin'] = SYS_SKIN;
|
|
|
|
return $skinListArray;
|
|
}
|
|
|
|
function getAllTimeZones()
|
|
{
|
|
$timezones = DateTimeZone::listAbbreviations();
|
|
|
|
$cities = array();
|
|
foreach( $timezones as $key => $zones )
|
|
{
|
|
foreach( $zones as $id => $zone )
|
|
{
|
|
/**
|
|
* Only get timezones explicitely not part of "Others".
|
|
* @see http://www.php.net/manual/en/timezones.others.php
|
|
*/
|
|
if ( preg_match( '/^(America|Antartica|Arctic|Asia|Atlantic|Africa|Europe|Indian|Pacific)\//', $zone['timezone_id'] )
|
|
&& $zone['timezone_id']) {
|
|
$cities[$zone['timezone_id']][] = $key;
|
|
}
|
|
}
|
|
}
|
|
|
|
// For each city, have a comma separated list of all possible timezones for that city.
|
|
foreach( $cities as $key => $value )
|
|
$cities[$key] = join( ', ', $value);
|
|
|
|
// Only keep one city (the first and also most important) for each set of possibilities.
|
|
$cities = array_unique( $cities );
|
|
|
|
// Sort by area/city name.
|
|
ksort( $cities );
|
|
|
|
return $cities;
|
|
}
|
|
|
|
public static function getSystemConfiguration($globalIniFile = '', $wsIniFile = '', $wsName = '')
|
|
{
|
|
$readGlobalIniFile = false;
|
|
$readWsIniFile = false;
|
|
|
|
if (empty($globalIniFile)) {
|
|
$globalIniFile = PATH_CORE . 'config' . PATH_SEP . 'env.ini';
|
|
}
|
|
|
|
if (empty($wsIniFile)) {
|
|
if (defined('PATH_DB')) { // if we're on a valid workspace env.
|
|
if (empty($wsName)) {
|
|
$uriParts = explode('/', getenv("REQUEST_URI"));
|
|
|
|
if (substr($uriParts[1], 0, 3 ) == 'sys') {
|
|
$wsName = substr($uriParts[1], 3);
|
|
}
|
|
}
|
|
|
|
$wsIniFile = PATH_DB . $wsName . PATH_SEP . 'env.ini';
|
|
}
|
|
}
|
|
|
|
$readGlobalIniFile = file_exists($globalIniFile) ? true : false;
|
|
$readWsIniFile = file_exists($wsIniFile) ? true : false;
|
|
|
|
if (isset($_SESSION['PROCESSMAKER_ENV'])) {
|
|
$md5 = array();
|
|
|
|
if ($readGlobalIniFile)
|
|
$md5[] = md5_file($globalIniFile);
|
|
|
|
if ($readWsIniFile)
|
|
$md5[] = md5_file($wsIniFile);
|
|
|
|
$hash = implode('-', $md5);
|
|
|
|
if ($_SESSION['PROCESSMAKER_ENV_HASH'] === $hash) {
|
|
$_SESSION['PROCESSMAKER_ENV']['from_cache'] = 1;
|
|
return $_SESSION['PROCESSMAKER_ENV'];
|
|
}
|
|
}
|
|
|
|
// default configuration
|
|
$config = array(
|
|
'debug' => 0,
|
|
'debug_sql' => 0,
|
|
'debug_time' => 0,
|
|
'debug_calendar' => 0,
|
|
'wsdl_cache' => 1,
|
|
'memory_limit' => '100M',
|
|
'time_zone' => 'America/La_Paz',
|
|
'memcached' => 0,
|
|
'memcached_server' => '',
|
|
'default_skin' => 'classic',
|
|
'default_lang' => 'en'
|
|
);
|
|
|
|
// read the global env.ini configuration file
|
|
if ($readGlobalIniFile && ($globalConf = @parse_ini_file($globalIniFile)) !== false) {
|
|
$config = array_merge($config, $globalConf);
|
|
}
|
|
|
|
// Workspace environment configuration
|
|
if ($readWsIniFile && ($wsConf = @parse_ini_file($wsIniFile)) !== false) {
|
|
$config = array_merge($config, $wsConf);
|
|
}
|
|
|
|
// validation debug config, only binary value is valid; debug = 1, to enable
|
|
$config['debug'] = $config['debug'] == 1 ? 1 : 0;
|
|
|
|
$md5 = array();
|
|
if ($readGlobalIniFile)
|
|
$md5[] = md5_file($globalIniFile);
|
|
|
|
if ($readWsIniFile)
|
|
$md5[] = md5_file($wsIniFile);
|
|
|
|
$hash = implode('-', $md5);
|
|
|
|
$_SESSION['PROCESSMAKER_ENV'] = $config;
|
|
$_SESSION['PROCESSMAKER_ENV_HASH'] = $hash;
|
|
|
|
return $config;
|
|
}
|
|
|
|
function updateIndexFile($conf)
|
|
{
|
|
if (!file_exists(PATH_HTML . 'index.html')) {
|
|
throw new Exception('The public index file "'.PATH_HTML . 'index.html" does not exist!');
|
|
}
|
|
else {
|
|
if (!is_writable(PATH_HTML . 'index.html')) {
|
|
throw new Exception('The index.html file is not writable on workflow/public_html directory.');
|
|
}
|
|
}
|
|
|
|
$content = file_get_contents(PATH_HTML . 'index.html');
|
|
$result = false;
|
|
|
|
$patt = '/<meta\s+http\-equiv="REFRESH"\s+content=\"0;URL=(.+)\"\s*\/>/';
|
|
|
|
@preg_match($patt, $content, $match);
|
|
|
|
if (is_array($match) && count($match) > 0 && isset($match[1])) {
|
|
$newUrl = 'sys/'.$conf['lang'].'/'.$conf['skin'].'/login/login';
|
|
|
|
$newMetaStr = str_replace($match[1], $newUrl, $match[0]);
|
|
$newContent = str_replace($match[0], $newMetaStr, $content);
|
|
|
|
$result = (@file_put_contents(PATH_HTML . 'index.html', $newContent) !== false);
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
function solrEnv($sysName = '')
|
|
{
|
|
if (empty($sysName)) {
|
|
$conf = System::getSystemConfiguration();
|
|
}
|
|
else {
|
|
$conf = System::getSystemConfiguration('', '', $sysName);
|
|
}
|
|
|
|
if (!isset($conf['solr_enabled']) || !isset($conf['solr_host']) || !isset($conf['solr_instance'])) {
|
|
return false;
|
|
}
|
|
|
|
if ($conf['solr_enabled']) {
|
|
return array(
|
|
'solr_enabled' => $conf['solr_enabled'],
|
|
'solr_host' => $conf['solr_host'],
|
|
'solr_instance' => $conf['solr_instance']
|
|
);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
}// end System class
|