. * * For more information, contact Colosa Inc, 2566 Le Jeune Rd., * Coral Gables, FL, 33134, USA, or email info@colosa.com. * */ // // It works with the table CONFIGURATION in a WF dataBase // // Copyright (C) 2007 COLOSA // // License: LGPL, see LICENSE //////////////////////////////////////////////////// /** * Processmaker Installer * @package workflow.engine.ProcessMaker * @author maborak * @copyright 2008 COLOSA */ class Installer { public $options = Array(); public $result = Array(); public $error = Array(); public $report = Array(); private $connection_database; /** * construct of insert * * @param string $pPRO_UID * @return void */ function __construct() { } /** * create_site * * @param array $config * @param boolean $confirmed * @return void */ public function create_site($config = Array(), $confirmed = false) { $this->options=G::array_concat(Array( 'isset'=>false, 'password' =>G::generate_password(12), 'path_data' =>@PATH_DATA, 'path_compiled' =>@PATH_C, 'name'=>$config['name'], 'database'=>Array(), 'admin'=>Array('username'=>'admin','password'=>'admin'), 'advanced'=>Array( 'ao_db_wf'=>'wf_'.$config['name'], 'ao_db_rb'=>'rb_'.$config['name'], 'ao_db_rp'=>'rp_'.$config['name'], 'ao_db_drop'=>false ) ),$config); $a = @explode(SYSTEM_HASH,G::decrypt(HASH_INSTALLATION,SYSTEM_HASH)); $this->options['database']=G::array_concat(Array( 'username'=>@$a[1], 'password'=>@$a[2], 'hostname'=>@$a[0] ),$this->options['database']); return ($confirmed===true)?$this->make_site():$this->create_site_test(); } /** * isset_site * * @param string $name Default value "workflow" * @return string file_exists(PATH_DATA."sites/".$name); */ public function isset_site($name = "workflow") { return file_exists(PATH_DATA."sites/".$name); } /** * create_site_test * * @return void */ private function create_site_test() { $name = (preg_match('/^[\w]+$/i',trim($this->options['name'])))?true:false; $result=Array( 'path_data' =>$this->is_dir_writable($this->options['path_data']), 'path_compiled' =>$this->is_dir_writable($this->options['path_compiled']), 'database' =>$this->check_connection(), 'access_level'=>$this->cc_status, 'isset'=>($this->options['isset']==true)?$this->isset_site($this->options['name']):false, 'microtime'=>microtime(), 'workspace'=>$this->options['name'], 'name'=>array( 'status'=>$name, 'message'=>($name)?'PASSED':'Workspace name invalid' ), 'admin'=>array( 'username'=>(preg_match('/^[\w@\.-]+$/i',trim($this->options['admin']['username'])))?true:false, 'password'=>((trim($this->options['admin']['password'])=='')?false:true) ) ); $result['name']['message'] = ($result['isset'])?'Workspace already exist':$result['name']['message']; $result['name']['status'] = ($result['isset'])?false:$result['name']['status']; //print_r($result); return Array( 'created'=>G::var_compare( true, $result['path_data'], $result['database']['connection'], $result['name']['status'], $result['database']['version'], $result['database']['ao']['ao_db_wf']['status'], $result['database']['ao']['ao_db_rb']['status'], $result['database']['ao']['ao_db_rp']['status'], $result['admin']['username'], (($result['isset'])?false:true), $result['admin']['password']), 'result'=>$result ); } /** * make_site * * @return array $test */ private function make_site() { $test = $this->create_site_test(); if($test["created"] == true || $this->options["advanced"]["ao_db_drop"] == true) { /* Check if the hostname is local (localhost or 127.0.0.1) */ $islocal = (strcmp(substr($this->options['database']['hostname'], 0, strlen('localhost')),'localhost')===0) || (strcmp(substr($this->options['database']['hostname'], 0, strlen('127.0.0.1')),'127.0.0.1')===0); $this->wf_site_name = $wf = $this->options['advanced']['ao_db_wf']; $this->rbac_site_name = $rb = $this->options['advanced']['ao_db_rb']; $this->report_site_name = $rp = $this->options['advanced']['ao_db_rp']; $schema = "schema.sql"; $values = "insert.sql"; if($this->options['advanced']['ao_db_drop']===true) { //Delete workspace directory if exists //Drop databases $this->run_query("DROP DATABASE IF EXISTS ".$wf, "Drop database $wf"); $this->run_query("DROP DATABASE IF EXISTS ".$rb, "Drop database $rb"); $this->run_query("DROP DATABASE IF EXISTS ".$rp, "Drop database $rp"); } $this->run_query("CREATE DATABASE IF NOT EXISTS ".$wf." DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci", "Create database $wf"); $this->run_query("CREATE DATABASE IF NOT EXISTS ".$rb." DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci", "Create database $rb"); $this->run_query("CREATE DATABASE IF NOT EXISTS ".$rp." DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci", "Create database $rp"); if($this->cc_status==1) { $host = ($islocal) ? "localhost" : "%"; $this->run_query("GRANT ALL PRIVILEGES ON `$wf`.* TO $wf@'$host' IDENTIFIED BY '{$this->options['password']}' WITH GRANT OPTION", "Grant privileges for user $wf on database $wf"); $this->run_query("GRANT ALL PRIVILEGES ON `$rb`.* TO $rb@'$host' IDENTIFIED BY '{$this->options['password']}' WITH GRANT OPTION", "Grant privileges for user $rb on database $rb"); $this->run_query("GRANT ALL PRIVILEGES ON `$rp`.* TO $rp@'$host' IDENTIFIED BY '{$this->options['password']}' WITH GRANT OPTION", "Grant privileges for user $rp on database $rp"); } /* Dump schema workflow && data */ $this->log("Import database schema:\n"); $myPortA = explode(":",$this->options['database']['hostname']); if(count($myPortA)<2) { $myPortA[1]="3306"; } $myPort = $myPortA[1]; $this->options['database']['hostname'] = $myPortA[0]; mysql_select_db($wf,$this->connection_database); $pws = PATH_WORKFLOW_MYSQL_DATA.$schema; $qws = $this->query_sql_file(PATH_WORKFLOW_MYSQL_DATA.$schema,$this->connection_database); $this->log($qws, isset($qws['errors'])); $qwv = $this->query_sql_file(PATH_WORKFLOW_MYSQL_DATA.$values,$this->connection_database); $this->log($qwv, isset($qwv['errors'])); /* Dump schema rbac && data */ $pws = PATH_RBAC_MYSQL_DATA.$schema; mysql_select_db($rb,$this->connection_database); $qrs = $this->query_sql_file(PATH_RBAC_MYSQL_DATA.$schema,$this->connection_database); $this->log($qrs, isset($qrs['errors'])); $qrv = $this->query_sql_file(PATH_RBAC_MYSQL_DATA.$values,$this->connection_database); $this->log($qrv, isset($qrv['errors'])); mysql_select_db($wf,$this->connection_database); require_once("propel/Propel.php"); require_once('classes/model/AppCacheView.php'); $appCache = new AppCacheView(); $appCache->setPathToAppCacheFiles ( PATH_METHODS . 'setup/setupSchemas/' ); $triggers = $appCache->getTriggers("en"); $this->log("Create 'cases list cache' triggers"); foreach ($triggers as $triggerName => $trigger) { $this->run_query($trigger, "-> Trigger $triggerName"); } $path_site = $this->options['path_data']."/sites/".$this->options['name']."/"; $db_file = $path_site."db.php"; @mkdir($path_site,0777,true); @mkdir($path_site."files/",0777,true); @mkdir($path_site."mailTemplates/",0777,true); @mkdir($path_site."public/",0777,true); @mkdir($path_site."reports/",0777,true); @mkdir($path_site."xmlForms",0777,true); $db_text = "options['database']['hostname'] . ":".$myPort."' );\n" . "define ('DB_NAME', '" . $wf. "' );\n" . "define ('DB_USER', '" . (($this->cc_status==1)?$wf:$this->options['database']['username']). "' );\n" . "define ('DB_PASS', '" . (($this->cc_status==1)?$this->options['password']:$this->options['database']['password']). "' );\n" . "define ('DB_RBAC_HOST', '". $this->options['database']['hostname'] .":".$myPort."' );\n" . "define ('DB_RBAC_NAME', '". $rb . "' );\n" . "define ('DB_RBAC_USER', '".(($this->cc_status==1)?$rb:$this->options['database']['username']) . "' );\n" . "define ('DB_RBAC_PASS', '". (($this->cc_status==1)?$this->options['password']:$this->options['database']['password']) . "' );\n" . "define ('DB_REPORT_HOST', '". $this->options['database']['hostname'] .":".$myPort."' );\n" . "define ('DB_REPORT_NAME', '". $rp . "' );\n" . "define ('DB_REPORT_USER', '".(($this->cc_status==1)?$rp:$this->options['database']['username']) . "' );\n" . "define ('DB_REPORT_PASS', '". (($this->cc_status==1)?$this->options['password']:$this->options['database']['password']) . "' );\n" . "?>"; $fp = @fopen($db_file, "w"); $this->log("Create: ".$db_file." => ".((!$fp)?$fp:"OK")."\n", $fp === FALSE); $ff = @fputs( $fp, $db_text, strlen($db_text)); $this->log("Write: ".$db_file." => ".((!$ff)?$ff:"OK")."\n", $ff === FALSE); fclose( $fp ); $this->set_admin(); } return $test; } /** * set_admin * * @return void */ public function set_admin() { mysql_select_db($this->wf_site_name,$this->connection_database); // The mysql_escape_string function has been DEPRECATED as of PHP 5.3.0. // $this->run_query('UPDATE USERS SET USR_USERNAME = \''.mysql_escape_string($this->options['admin']['username']).'\', `USR_PASSWORD` = \''.md5($this->options['admin']['password']).'\' WHERE `USR_UID` = \'00000000000000000000000000000001\' LIMIT 1', // "Add 'admin' user in ProcessMaker (wf)"); $this->run_query('UPDATE USERS SET USR_USERNAME = \'' . mysql_real_escape_string($this->options['admin']['username']) . '\', ' . ' `USR_PASSWORD` = \'' . md5($this->options['admin']['password']) . '\' ' . ' WHERE `USR_UID` = \'00000000000000000000000000000001\' LIMIT 1', "Add 'admin' user in ProcessMaker (wf)"); mysql_select_db($this->rbac_site_name,$this->connection_database); // The mysql_escape_string function has been DEPRECATED as of PHP 5.3.0. // $this->run_query('UPDATE USERS SET USR_USERNAME = \''.mysql_escape_string($this->options['admin']['username']).'\', `USR_PASSWORD` = \''.md5($this->options['admin']['password']).'\' WHERE `USR_UID` = \'00000000000000000000000000000001\' LIMIT 1', // "Add 'admin' user in ProcessMaker (rb)"); $this->run_query('UPDATE USERS SET USR_USERNAME = \'' . mysql_real_escape_string($this->options['admin']['username']) . '\', ' . ' `USR_PASSWORD` = \'' . md5($this->options['admin']['password']) . '\' ' . ' WHERE `USR_UID` = \'00000000000000000000000000000001\' LIMIT 1', "Add 'admin' user in ProcessMaker (rb)"); } /** * Run a mysql query on the current database and take care of logging and * error handling. * * @param string $query SQL command * @param string $description Description to log instead of $query */ private function run_query($query, $description = NULL) { $result = @mysql_query($query, $this->connection_database); $error = ($result) ? false : mysql_error(); $this->log(($description ? $description : $query) . " => " . (($error) ? $error : "OK") . "\n", $error); } /** * query_sql_file * * @param string $file * @param string $connection * @return array $report */ public function query_sql_file($file, $connection) { $lines = file($file); $previous = NULL; $errors = ''; @mysql_query("SET NAMES 'utf8';"); foreach ($lines as $j => $line) { $line = trim($line); // Remove comments from the script if (strpos($line, "--") === 0) { $line = substr($line, 0, strpos($line, "--")); } if (empty($line)) { continue; } if (strpos($line, "#") === 0) { $line = substr($line, 0, strpos($line, "#")); } if (empty($line)) { continue; } // Concatenate the previous line, if any, with the current if ($previous) { $line = $previous . " " . $line; } $previous = NULL; // If the current line doesnt end with ; then put this line together // with the next one, thus supporting multi-line statements. if (strrpos($line, ";") != strlen($line) - 1) { $previous = $line; continue; } $line = substr($line, 0, strrpos($line, ";")); @mysql_query($line, $connection); } } /** * check_path * * @return void * @todo Empty function */ private function check_path() { } /** * function find_root_path * * @param string $path * @return string $path */ private function find_root_path($path) { $i = 0; //prevent loop inifinity while(!is_dir($path) && ($path = dirname($path)) && ((strlen($path)>1) && $i<10)) { $i++; } return $path; } /** * file_permisions * * @param string $file * @param integer $def default value 777 * @return integer $def */ public function file_permisions($file, $def = 777) { if ( PHP_OS == 'WINNT' ) return $def; else return (int)substr(sprintf('%o',@fileperms($file)),-4); } /** * is_dir_writable * * @param string $dir default value empty * @return string $path */ public function is_dir_writable($dir = '') { if (PHP_OS=='WINNT') { $dir = $this->find_root_path($dir); return file_exists ( $dir ); } else { $dir = $this->find_root_path($dir); return (is_writable($dir) && is_readable($dir)); } } /** * getDirectoryFiles * * @param string $dir default value empty * @return string $path */ public function getDirectoryFiles($dir,$extension){ $filesArray=array(); if (file_exists($dir)) { if ($handle = opendir($dir)) { while (false !== ($file = readdir($handle))) { $fileParts=explode(".",$file); if($fileParts[count($fileParts)-1]==$extension) { $filesArray[]=$file; } } closedir($handle); } } return $filesArray; } /** * check_db_empty * * @param string $dbName * @return boolean true or false */ public function check_db_empty($dbName) { $a = @mysql_select_db($dbName,$this->connection_database); if(!$a) { return true; } $q = @mysql_query('SHOW TABLES',$this->connection_database); return (@mysql_num_rows($q)>0)?false:true; } /** * check_db * * @param string $dbName * @return Array Array('status' => true or false,'message' => string) */ public function check_db($dbName) { if(!$this->connection_database) { //erik: new verification if the mysql extension is enabled $error = class_exists('mysql_error') ? mysql_error() : 'Mysql Module for PHP is not enabled!'; return Array('status' => false, 'message' => $error); } else { if(!mysql_select_db($dbName,$this->connection_database) && $this->cc_status!=1) { return Array('status' => false, 'message' => mysql_error()); } else { /* var_dump($this->options['advanced']['ao_db_drop'],$this->cc_status,$this->check_db_empty($dbName)); if(($this->options['advanced']['ao_db_drop']===false && $this->cc_status!=1 && !$this->check_db_empty($dbName)) ) { return Array('status'=>false,'message'=>'Database is not empty'); } else { return Array('status'=>true,'message'=>'OK'); }*/ if($this->options['advanced']['ao_db_drop']===true || $this->check_db_empty($dbName)) { return Array('status' => true, 'message' => 'PASSED'); } else { return Array('status' => false, 'message' => 'Database is not empty'); } } } } /** * check_connection * * @return Array $rt */ private function check_connection() { if(!function_exists("mysql_connect")) { $this->cc_status = 0; $rt = Array( 'connection' => false, 'grant' => 0, 'version' => false, 'message' => "ERROR: Mysql Module for PHP is not enabled, try install php-mysql package.", 'ao'=>Array( 'ao_db_wf' => false, 'ao_db_rb' => false, 'ao_db_rp' => false ) ); } else { $this->connection_database = @mysql_connect($this->options['database']['hostname'],$this->options['database']['username'],$this->options['database']['password']); $rt = Array( 'version' => false, 'ao'=>Array( 'ao_db_wf' => false, 'ao_db_rb' => false, 'ao_db_rp' => false ) ); if(!$this->connection_database) { $this->cc_status = 0; $rt['connection'] = false; $rt['grant'] = 0; $rt['message'] = "Mysql error: ".mysql_error(); } else { preg_match('@[0-9]+\.[0-9]+\.[0-9]+@',mysql_get_server_info($this->connection_database),$version); $rt['version'] = version_compare(@$version[0],"4.1.0",">="); $rt['connection'] = true; $dbNameTest = "PROCESSMAKERTESTDC"; $db = @mysql_query("CREATE DATABASE ".$dbNameTest,$this->connection_database); if(!$db) { $this->cc_status = 3; $rt['grant'] = 3; //$rt['message'] = "Db GRANTS error: ".mysql_error(); $rt['message'] = "Successful connection"; } else { //@mysql_drop_db("processmaker_testGA"); $usrTest = "wfrbtest"; $chkG = "GRANT ALL PRIVILEGES ON `".$dbNameTest."`.* TO ".$usrTest."@'%' IDENTIFIED BY 'sample' WITH GRANT OPTION"; $ch = @mysql_query($chkG,$this->connection_database); if(!$ch) { $this->cc_status = 2; $rt['grant'] = 2; //$rt['message'] = "USER PRIVILEGES ERROR"; $rt['message'] = "Successful connection"; } else { $this->cc_status = 1; @mysql_query("DROP USER ".$usrTest."@'%'",$this->connection_database); $rt['grant'] = 1; $rt['message'] = "Successful connection"; } @mysql_query("DROP DATABASE ".$dbNameTest,$this->connection_database); } // var_dump($wf,$rb,$rp); } } $rt['ao']['ao_db_wf'] = $this->check_db($this->options['advanced']['ao_db_wf']); $rt['ao']['ao_db_rb'] = $this->check_db($this->options['advanced']['ao_db_rb']); $rt['ao']['ao_db_rp'] = $this->check_db($this->options['advanced']['ao_db_rp']); return $rt; } /** * log * * @param string $text * @return void */ public function log($text, $failed = NULL) { array_push($this->report,$text); if ($failed) throw new Exception(is_string($text) ? $text : var_export($text, true)); } } ?>