path_config = PATH_CORE . 'config/'; $this->path_languages = PATH_CORE . 'content/languages/'; $this->path_plugins = PATH_CORE . 'plugins/'; $this->path_xmlforms = PATH_CORE . 'xmlform/'; $this->path_public = PATH_HOME . 'public_html/index.html'; $this->path_shared = PATH_TRUNK . 'shared/'; $this->path_sep = PATH_SEP; $this->systemName = ''; //$this->path_documents = ; $this->path_translations = PATH_CORE . 'js/labels/'; $this->path_translationsMafe = PATH_HOME . 'public_html/translations/'; } public function index($httpData) { if (file_exists(FILE_PATHS_INSTALLED)) { $this->setJSVar('messageError', G::LoadTranslation('ID_PROCESSMAKER_ALREADY_INSTALLED')); $this->includeExtJS('installer/stopInstall'); $this->setView('installer/mainStopInstall'); G::RenderPage('publish', 'extJs'); return; } if ((strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') && (file_exists($this->path_shared . 'partner.info'))) { $this->setJSVar('messageError', G::LoadTranslation('ID_NO_INSTALL')); $this->includeExtJS('installer/stopInstall'); $this->setView('installer/mainStopInstall'); G::RenderPage('publish', 'extJs'); return; } $licenseContent = file_get_contents(PATH_TRUNK . 'LICENSE.txt'); $this->includeExtJS('installer/CardLayout', false); $this->includeExtJS('installer/Wizard', false); $this->includeExtJS('installer/Header', false); $this->includeExtJS('installer/Card', false); $this->includeExtJS('installer/installer_cards'); $this->includeExtJS('installer/main', false); $this->setJSVar('licenseTxt', $licenseContent); $this->setJSVar('path_config', $this->path_config); $this->setJSVar('path_languages', $this->path_languages); $this->setJSVar('path_plugins', $this->path_plugins); $this->setJSVar('path_xmlforms', $this->path_xmlforms); $this->setJSVar('path_public', $this->path_public); $this->setJSVar('path_shared', $this->path_shared); $this->setJSVar('path_sep', $this->path_sep); $this->setJSVar('path_translations', $this->path_translations); $this->setJSVar('path_translationsMafe', $this->path_translationsMafe); $this->setView('installer/main'); G::RenderPage('publish', 'extJs'); } /** * This function can be create a new workspace * The user need permission PM_SETUP_ADVANCE for this action * @return void */ public function newSite() { if (!$this->pmIsInstalled()) { $textStep1 = G::LoadTranslation('ID_PROCESSMAKER_REQUIREMENTS_DESCRIPTION_STEP4_1'); $textStep2 = G::LoadTranslation('ID_PROCESSMAKER_REQUIREMENTS_DESCRIPTION_STEP5'); $this->includeExtJS('installer/CardLayout', false); $this->includeExtJS('installer/Wizard', false); $this->includeExtJS('installer/Header', false); $this->includeExtJS('installer/Card', false); $this->includeExtJS('installer/newSite', false); $this->setJSVar('textStep1', $textStep1); $this->setJSVar('textStep2', $textStep2); $this->setJSVar('DB_ADAPTER', DB_ADAPTER); $aux = explode(':', DB_HOST); $this->setJSVar('DB_HOST', $aux[0]); $this->setJSVar('DB_PORT', isset($aux[1]) ? $aux[1] : '3306'); $this->setJSVar('DB_NAME', 'workflow'); $this->setJSVar('DB_USER', ''); $this->setJSVar('DB_PASS', ''); $this->setJSVar('pathConfig', PATH_CORE . 'config' . PATH_SEP); $this->setJSVar('pathLanguages', PATH_LANGUAGECONT); $this->setJSVar('pathPlugins', PATH_PLUGINS); $this->setJSVar('pathXmlforms', PATH_XMLFORM); $this->setJSVar('pathShared', PATH_DATA); $this->setView('installer/newSite'); G::RenderPage('publish', 'extJs'); } else { $this->displayError(); } } /** * Set config connection * * @param string $nameConnection name Connection * @param string $host * @param string $user * @param string $pass * @param string $database * @param int $port * @param array $options * * @throws Exception */ public static function setNewConnection($nameConnection, $host, $user, $pass, $database, $port, $options = []) { try { if (empty($port)) { $dbHost = explode(':', $host); $port = 3306; if (count($dbHost) > 1) { $port = $dbHost[1]; } $host = $dbHost[0]; } config(['database.connections.' . $nameConnection => [ 'driver' => 'mysql', 'host' => $host, 'port' => $port, 'database' => $database, 'username' => $user, 'password' => $pass, 'unix_socket' => '', 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci', 'prefix' => '', 'strict' => false, 'engine' => 'InnoDB', 'options' => $options ]]); DB::connection($nameConnection)->getPdo(); } catch (Exception $e) { throw new Exception(G::LoadTranslation('ID_MYSQL_CREDENTIALS_WRONG')); } } /** * Get system information for review the requirements to install ProcessMaker * * @return object */ public function getSystemInfo() { $this->setResponseType('json'); // PHP info and verification $phpVer = phpversion(); preg_match('/[0-9\.]+/', $phpVer, $match); $phpVerNum = (float)$match[0]; $info = new stdclass(); $info->php = new stdclass(); $info->mysql = new stdclass(); $info->openssl = new stdclass(); $info->curl = new stdclass(); $info->dom = new stdclass(); $info->gd = new stdclass(); $info->multibyte = new stdclass(); $info->soap = new stdclass(); $info->ldap = new stdclass(); $info->memory = new stdclass(); $info->php->version = $phpVer; $info->php->result = ( version_compare(phpversion(), self::PHP_VERSION_MINIMUM_SUPPORTED, '>=') && version_compare(phpversion(), self::PHP_VERSION_NOT_SUPPORTED, '<')) ? true : false; // MYSQL info and verification $info->mysql->result = false; if (function_exists('mysqli_query')) { $mysqlVer = mysqli_get_client_info(); preg_match('/[0-9\.]+/', $mysqlVer, $match); $mysqlNum = (float)$match[0]; $info->mysql->version = 'Client API version ' . $mysqlVer; $info->mysql->result = $mysqlNum >= 5.0; } // OpenSSL info $info->openssl->result = false; $info->openssl->version = G::LoadTranslation('ID_NOT_ENABLED'); if (function_exists('openssl_open')) { $info->openssl->result = true; $info->openssl->version = G::LoadTranslation('ID_ENABLED'); } // Curl info $info->curl->result = false; $info->curl->version = G::LoadTranslation('ID_NOT_ENABLED'); if (function_exists('curl_version')) { $info->curl->result = true; $version = curl_version(); $info->curl->version = 'cURL ' . $version['version']; $info->openssl->version = $version['ssl_version']; } // DOMDocument info $info->dom->result = false; $info->dom->version = G::LoadTranslation('ID_NOT_ENABLED'); if (class_exists('DOMDocument')) { $info->dom->result = true; $info->dom->version = G::LoadTranslation('ID_ENABLED'); } // GD info $info->gd->result = false; $info->gd->version = G::LoadTranslation('ID_NOT_ENABLED'); if (function_exists('gd_info')) { $info->gd->result = true; $gdinfo = gd_info(); $info->gd->version = $gdinfo['GD Version']; } // Multibyte info $info->multibyte->result = false; $info->multibyte->version = G::LoadTranslation('ID_NOT_ENABLED'); if (function_exists('mb_check_encoding')) { $info->multibyte->result = true; $info->multibyte->version = G::LoadTranslation('ID_ENABLED'); } // soap info $info->soap->result = false; $info->soap->version = G::LoadTranslation('ID_NOT_ENABLED'); if (class_exists('SoapClient')) { $info->soap->result = true; $info->soap->version = G::LoadTranslation('ID_ENABLED'); } // ldap info $info->ldap->result = false; $info->ldap->version = G::LoadTranslation('ID_NOT_ENABLED'); if (function_exists('ldap_connect')) { $info->ldap->result = true; $info->ldap->version = G::LoadTranslation('ID_ENABLED'); } // memory limit verification $memory = (int)ini_get('memory_limit'); $info->memory->version = changeAbbreviationOfDirectives(ini_get('memory_limit')); $info->memory->result = $memory > 255; return $info; } public function is_dir_writable($path) { return G::is_writable_r($path); } public function getPermissionInfo() { $this->setResponseType('json'); $info = new StdClass(); $info->success = true; $noWritableFiles = []; $noWritable = G::LoadTranslation('ID_INDEX_NOT_WRITEABLE'); $writable = G::LoadTranslation('ID_WRITEABLE'); // pathConfig $info->pathConfig = new stdclass(); $info->pathConfig->message = $noWritable; $info->pathConfig->result = G::is_writable_r($_REQUEST['pathConfig'], $noWritableFiles); if ($info->pathConfig->result) { $info->pathConfig->message = $writable; } else { $info->success = false; } $info->pathLanguages = new stdclass(); $info->pathLanguages->message = $noWritable; $info->pathLanguages->result = G::is_writable_r($_REQUEST['pathLanguages'], $noWritableFiles); if ($info->pathLanguages->result) { $info->pathLanguages->message = $writable; } else { $info->success = false; } $info->pathPlugins = new stdclass(); $info->pathPlugins->message = $noWritable; $info->pathPlugins->result = G::is_writable_r($_REQUEST['pathPlugins'], $noWritableFiles); if ($info->pathPlugins->result) { $info->pathPlugins->message = $writable; } else { $info->success = false; } $info->pathXmlforms = new stdclass(); $info->pathXmlforms->message = $noWritable; $info->pathXmlforms->result = G::is_writable_r($_REQUEST['pathXmlforms'], $noWritableFiles); if ($info->pathXmlforms->result) { $info->pathXmlforms->message = $writable; } else { $info->success = false; } $info->pathTranslations = new stdclass(); $info->pathTranslations->message = G::LoadTranslation('ID_TRANSLATION_NOT_WRITEABLE'); $info->pathTranslations->result = G::is_writable_r($_REQUEST['pathTranslations'], $noWritableFiles); if ($info->pathTranslations->result) { $info->pathTranslations->message = $writable; } else { $info->success = false; } $info->pathTranslationsMafe = new stdclass(); $info->pathTranslationsMafe->message = G::LoadTranslation('ID_MAFE_TRANSLATION_NOT_WRITEABLE'); $info->pathTranslationsMafe->result = G::is_writable_r($_REQUEST['pathTranslationsMafe'], $noWritableFiles); if ($info->pathTranslationsMafe->result) { $info->pathTranslationsMafe->message = $writable; } else { $info->success = false; } $info->pathPublic = new stdclass(); $info->pathShared = new stdclass(); $info->pathPublic->message = $noWritable; $info->pathPublic->result = G::is_writable_r($_REQUEST['pathPublic'], $noWritableFiles); if ($info->pathPublic->result) { $info->pathShared->message = $writable; } else { $info->success = false; } $info->pathShared->message = $noWritable; $info->pathShared->result = G::is_writable_r($_REQUEST['pathShared'], $noWritableFiles); if ($info->pathShared->result) { $info->pathShared->message = $writable; } else { //Verify and create the shared path G::verifyPath($_REQUEST['pathShared'], true); $info->pathShared->result = G::is_writable_r($_REQUEST['pathShared'], $noWritableFiles); if ($info->pathShared->result) { $info->pathShared->message = $writable; $info->success = $this->verifySharedFrameworkPaths($_REQUEST['pathShared']); } else { $info->success = false; } } $filter = new InputFilter(); $pathShared = $filter->validateInput($_REQUEST['pathShared'], 'path'); if ($info->pathShared->result) { $aux = pathinfo($_REQUEST['pathLogFile']); G::verifyPath($aux['dirname'], true); if (is_dir($aux['dirname'])) { if (!file_exists($_REQUEST['pathLogFile'])) { @file_put_contents($_REQUEST['pathLogFile'], ''); @chmod($pathShared, 0770); } } } $info->pathLogFile = new stdclass(); $info->pathLogFile->message = G::LoadTranslation('ID_CREATE_LOG_INSTALLATION'); $info->pathLogFile->result = file_exists($_REQUEST['pathLogFile']); if ($info->pathLogFile->result) { $info->pathLogFile->message = G::LoadTranslation('ID_INSTALLATION_FILE_LOG'); } $info->notify = $info->success ? G::LoadTranslation('ID_SUCCESS_DIRECTORIES_WRITABLE') : G::LoadTranslation('ID_DIRECTORIES_NOT_WRITABLE'); $info->noWritableFiles = $noWritableFiles; return $info; } /** * Test db connection * * @return StdClass */ public function testConnection() { $this->setResponseType('json'); $info = new StdClass(); try { $info = $this->testMySQLConnection(); } catch (Exception $e) { $info->result = false; $info->message = G::LoadTranslation('DBCONNECTIONS_MSGA'); } return $info; } /** * log the queries and other information to install.log, * the install.log files should be placed in shared/logs * for that reason we are using the $_REQUEST of pathShared */ private function installLog($text) { //if this function is called outside the createWorkspace, just returns and do nothing if (!isset($_REQUEST['pathShared'])) { return; } //log file is in shared/logs $pathShared = trim($_REQUEST['pathShared']); if (substr($pathShared, -1) !== '/') { $pathShared .= '/'; } $pathSharedLog = $pathShared . 'log/'; G::verifyPath($pathSharedLog, true); $logFile = $pathSharedLog . 'install.log'; if (!is_file($logFile)) { G::mk_dir(dirname($pathShared)); $fpt = fopen($logFile, 'w'); if ($fpt !== null) { fwrite($fpt, sprintf("%s %s\n", date('Y:m:d H:i:s'), '----- ' . G::LoadTranslation('ID_STARTING_LOG_FILE') . ' ------')); fclose($fpt); } else { throw new Exception(G::LoadTranslation('ID_FILE_NOT_WRITEABLE', SYS_LANG, [$logFile])); return $false; } } $filter = new InputFilter(); $logFile = $filter->validateInput($logFile, 'path'); $fpt = fopen($logFile, 'a'); fwrite($fpt, sprintf("%s %s\n", date('Y:m:d H:i:s'), trim($text))); fclose($fpt); return true; } /** * function to create a workspace * in fact this function is calling appropriate functions for mysql * need permission PM_SETUP_ADVANCE for this action * @return stdClass information create a workspace. */ public function createWorkspace() { if (!$this->pmIsInstalled()) { $pathSharedPartner = trim($_REQUEST['pathShared']); if (file_exists(trim($pathSharedPartner, PATH_SEP) . PATH_SEP . 'partner.info')) { $this->systemName = $this->getSystemName($pathSharedPartner); $_REQUEST['PARTNER_FLAG'] = true; } $this->setResponseType('json'); $info = new StdClass(); try { $info = $this->createMySQLWorkspace(); } catch (Exception $e) { $info->result = false; $info->message = G::LoadTranslation('DBCONNECTIONS_MSGA'); } return $info; } else { $this->displayError(); } } /** * We check if processMaker is not installed * * @return boolean */ private function pmIsInstalled() { return file_exists(FILE_PATHS_INSTALLED); } /** * Display an error when processMaker is already installed * * @return void */ private function displayError() { $this->setJSVar('messageError', G::LoadTranslation('ID_PROCESSMAKER_ALREADY_INSTALLED')); $this->includeExtJS('installer/stopInstall'); $this->setView('installer/mainStopInstall'); G::RenderPage('publish', 'extJs'); } public function forceTogenerateTranslationsFiles($url) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, G::browserCacheFilesUrl(System::getServerProtocolHost() . "/js/ext/translation.en.js?r=" . rand(1, 10000))); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_FRESH_CONNECT, 1); curl_setopt($ch, CURLOPT_TIMEOUT, 60); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20); curl_exec($ch); curl_close($ch); } /** * query_sql_file send many statements to server * * @param string $file * @param string $connection * @return array $report */ public function mysqlFileQuery($file) { if (!is_file($file)) { throw new Exception(G::LoadTranslation('ID_SQL_FILE_INVALID', SYS_LANG, [$file])); return $false; } $this->installLog(G::LoadTranslation('ID_PROCESING', SYS_LANG, [$file])); $startTime = microtime(true); //New Update, to support more complex queries $lines = file($file); $previous = null; DB::connection(self::CONNECTION_INSTALL) ->statement("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, ';')); DB::connection(self::CONNECTION_INSTALL) ->statement($line); } $endTime = microtime(true); $this->installLog(G::LoadTranslation('ID_FILE_PROCESSED', SYS_LANG, [basename($file), $endTime - $startTime])); return true; } /** * set Grant Privileges for MySQL * * @param string $psUser * @param string $psPassword * @param string $psDatabase * @param string $host * * @throws Exception */ private function setGrantPrivilegesMySQL($psUser, $psPassword, $psDatabase, $host) { try { $host = $host === 'localhost' || $host === '127.0.0.1' ? 'localhost' : '%'; $query = "CREATE USER '$psUser'@'$host' IDENTIFIED WITH mysql_native_password BY '$psPassword'"; DB::connection(self::CONNECTION_INSTALL) ->statement($query); $query = "GRANT ALL PRIVILEGES ON `$psDatabase`.* TO '$psUser'@'$host' WITH GRANT OPTION"; DB::connection(self::CONNECTION_INSTALL) ->statement($query); $this->installLog($query); } catch (QueryException $e) { $this->installLog(G::LoadTranslation('ID_MYSQL_ERROR', SYS_LANG, [$e->getMessage()])); throw new Exception($e->getMessage()); } } /** * Create a workspace in a MySQL database * * @return StdClass object */ public function createMySQLWorkspace() { $filter = new InputFilter(); ini_set('max_execution_time', '0'); $info = new StdClass(); $info->result = false; $info->message = ''; $info->canRedirect = true; $db_hostname = trim($_REQUEST['db_hostname']); $db_port = trim($_REQUEST['db_port']); $db_port = $filter->validateInput($db_port); $db_username = trim($_REQUEST['db_username']); $db_username = $filter->validateInput($db_username); $db_password = urlencode(trim($_REQUEST['db_password'])); $db_password = urldecode($filter->validateInput($db_password)); $wf = trim($_REQUEST['wfDatabase']); $workspace = trim($_REQUEST['workspace']); $pathShared = trim($_REQUEST['pathShared']); $adminPassword = trim($_REQUEST['adminPassword']); $adminPassword = $filter->validateInput($adminPassword); $adminUsername = trim($_REQUEST['adminUsername']); $adminUsername = $filter->validateInput($adminUsername); $deleteDB = $_REQUEST['deleteDB'] === 'true'; $userLogged = isset($_REQUEST['userLogged']) ? $_REQUEST['userLogged'] === 'true' : false; $userLogged = $filter->validateInput($userLogged); if (substr($pathShared, -1) !== '/') { $pathShared .= '/'; } $this->installLog('-------------------------------------------'); $this->installLog(G::LoadTranslation('ID_CREATING_WORKSPACE', SYS_LANG, [$workspace])); try { self::setNewConnection(self::CONNECTION_TEST_INSTALL, $db_hostname, $db_username, $db_password, '', $db_port); $db_host = ($db_port != '' && $db_port != 3306) ? $db_hostname . ':' . $db_port : $db_hostname; $this->installLog(G::LoadTranslation('ID_CONNECT_TO_SERVER', SYS_LANG, [$db_hostname, $db_port, $db_username])); if ($deleteDB) { $query = sprintf('DROP DATABASE IF EXISTS %s', $wf); DB::connection(self::CONNECTION_TEST_INSTALL)->statement($query); } // CREATE databases wf_workflow DB::connection(self::CONNECTION_TEST_INSTALL) ->statement("CREATE DATABASE IF NOT EXISTS $wf DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci"); self::setNewConnection(self::CONNECTION_INSTALL, $db_hostname, $db_username, $db_password, $wf, $db_port); // CREATE users and GRANT Privileges $wf_workspace = $wf; $wfGrantUser = uniqid('wf_'); if (!$userLogged) { $wfPass = G::generate_password(15); $this->setGrantPrivilegesMySQL($wfGrantUser, $wfPass, $wf, $db_hostname); } else { $wfPass = $db_password; $wf = $db_username; $wfGrantUser = $db_username; } // Generate the db.php file and folders $path_site = $pathShared . '/sites/' . $workspace . '/'; @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_file = $path_site . 'db.php'; $dbText = "systemName)) { $dbText .= " define ('SYSTEM_NAME', '" . $this->systemName . "');\n"; } } $this->installLog(G::LoadTranslation('ID_CREATING', SYS_LANG, [$db_file])); file_put_contents($db_file, $dbText); /*----------------------------------********---------------------------------*/ //Generate the env.ini file $envIniFile = $path_site . 'env.ini'; $content = 'system_utc_time_zone = 1' . "\n"; $this->installLog(G::LoadTranslation('ID_CREATING', SYS_LANG, [$envIniFile])); file_put_contents($envIniFile, $content); /*----------------------------------********---------------------------------*/ //Generate the databases.php file $databases_file = $path_site . 'databases.php'; $dbData = sprintf("\$dbAdapter = '%s';\n", 'mysql'); $dbData .= sprintf("\$dbHost = '%s';\n", $db_host); $dbData .= sprintf("\$dbName = '%s';\n", $wf_workspace); $dbData .= sprintf("\$dbUser = '%s';\n", $wf); $dbData .= sprintf("\$dbPass = '%s';\n", $wfPass); $dbData .= sprintf("\$dbRbacHost = '%s';\n", $db_host); $dbData .= sprintf("\$dbRbacName = '%s';\n", $wf_workspace); $dbData .= sprintf("\$dbRbacUser = '%s';\n", $wf); $dbData .= sprintf("\$dbRbacPass = '%s';\n", $wfPass); $dbData .= sprintf("\$dbReportHost = '%s';\n", $db_host); $dbData .= sprintf("\$dbReportName = '%s';\n", $wf_workspace); $dbData .= sprintf("\$dbReportUser = '%s';\n", $wf); $dbData .= sprintf("\$dbReportPass = '%s';\n", $wfPass); $databasesText = str_replace('{dbData}', $dbData, @file_get_contents(PATH_HOME . 'engine/templates/installer/databases.tpl')); $this->installLog(G::LoadTranslation('ID_CREATING', SYS_LANG, array($databases_file))); file_put_contents($databases_file, $databasesText); $this->mysqlFileQuery(PATH_RBAC_HOME . 'engine/data/mysql/schema.sql'); $this->mysqlFileQuery(PATH_RBAC_HOME . 'engine/data/mysql/insert.sql'); $this->mysqlFileQuery(PATH_HOME . 'engine/data/mysql/schema.sql'); $this->mysqlFileQuery(PATH_HOME . 'engine/data/mysql/insert.sql'); if (defined('PARTNER_FLAG') || isset($_REQUEST['PARTNER_FLAG'])) { $this->setPartner(); } // Create the triggers if (file_exists(PATH_HOME . 'engine/methods/setup/setupSchemas/triggerAppDelegationInsert.sql') && file_exists(PATH_HOME . 'engine/methods/setup/setupSchemas/triggerAppDelegationUpdate.sql') && file_exists(PATH_HOME . 'engine/methods/setup/setupSchemas/triggerApplicationUpdate.sql') && file_exists(PATH_HOME . 'engine/methods/setup/setupSchemas/triggerApplicationDelete.sql') && file_exists(PATH_HOME . 'engine/methods/setup/setupSchemas/triggerSubApplicationInsert.sql') && file_exists(PATH_HOME . 'engine/methods/setup/setupSchemas/triggerContentUpdate.sql')) { DB::connection(self::CONNECTION_INSTALL)->unprepared(file_get_contents(PATH_HOME . 'engine/methods/setup/setupSchemas/triggerAppDelegationInsert.sql')); DB::connection(self::CONNECTION_INSTALL)->unprepared(file_get_contents(PATH_HOME . 'engine/methods/setup/setupSchemas/triggerAppDelegationUpdate.sql')); DB::connection(self::CONNECTION_INSTALL)->unprepared(file_get_contents(PATH_HOME . 'engine/methods/setup/setupSchemas/triggerApplicationUpdate.sql')); DB::connection(self::CONNECTION_INSTALL)->unprepared(file_get_contents(PATH_HOME . 'engine/methods/setup/setupSchemas/triggerApplicationDelete.sql')); DB::connection(self::CONNECTION_INSTALL)->unprepared(file_get_contents(PATH_HOME . 'engine/methods/setup/setupSchemas/triggerSubApplicationInsert.sql')); DB::connection(self::CONNECTION_INSTALL)->unprepared(file_get_contents(PATH_HOME . 'engine/methods/setup/setupSchemas/triggerContentUpdate.sql')); DB::connection(self::CONNECTION_INSTALL) ->table('CONFIGURATION') ->insert([ 'CFG_UID' => 'APP_CACHE_VIEW_ENGINE', 'CFG_VALUE' => serialize(['LANG' => 'en', 'STATUS' => 'active']) ]); DB::connection(self::CONNECTION_INSTALL) ->table('EMAIL_SERVER') ->insert([ 'MESS_UID' => Common::generateUID(), 'MESS_ENGINE' => 'MAIL' ]); } // Change admin user DB::connection(self::CONNECTION_INSTALL) ->table('USERS') ->where('USR_UID', '00000000000000000000000000000001') ->update([ 'USR_USERNAME' => $adminUsername, 'USR_LASTNAME' => $adminUsername, 'USR_PASSWORD' => G::encryptHash($adminPassword) ]); DB::connection(self::CONNECTION_INSTALL) ->table('RBAC_USERS') ->where('USR_UID', '00000000000000000000000000000001') ->update([ 'USR_USERNAME' => $adminUsername, 'USR_LASTNAME' => $adminUsername, 'USR_PASSWORD' => G::encryptHash($adminPassword) ]); // Write the paths_installed.php file (contains all the information configured so far) if (!file_exists(FILE_PATHS_INSTALLED)) { $sh = G::encryptOld(filemtime(PATH_GULLIVER . '/class.g.php')); $h = G::encrypt($db_host . $sh . $db_username . $sh . $db_password, $sh); $dbText = "installLog(G::LoadTranslation('ID_CREATING', SYS_LANG, [FILE_PATHS_INSTALLED])); file_put_contents(FILE_PATHS_INSTALLED, $dbText); } // for new env conf handling $envFile = PATH_CONFIG . 'env.ini'; // getting configuration from env.ini $sysConf = System::getSystemConfiguration($envFile); $langUri = 'en'; if (isset($sysConf['default_lang'])) { $langUri = $sysConf['default_lang']; } $skinUri = 'neoclassic'; if (isset($sysConf['default_skin'])) { $skinUri = $sysConf['default_skin']; } $updatedConf['default_lang'] = $langUri; $updatedConf['default_skin'] = $skinUri; $info->uri = PATH_SEP . 'sys' . $_REQUEST['workspace'] . PATH_SEP . $langUri . PATH_SEP . $skinUri . PATH_SEP . 'login' . PATH_SEP . 'login'; //register PMDesigner Client $http = G::is_https() ? 'https' : 'http'; $host = $_SERVER['SERVER_NAME'] . ($_SERVER['SERVER_PORT'] !== '80' ? ':' . $_SERVER['SERVER_PORT'] : ''); $endpoint = sprintf( '%s://%s/sys%s/%s/%s/oauth2/grant', $http, $host, $workspace, $langUri, $skinUri ); // inserting the outh_client DB::connection(self::CONNECTION_INSTALL) ->table('OAUTH_CLIENTS') ->insert([ 'CLIENT_ID' => 'x-pm-local-client', 'CLIENT_SECRET' => '179ad45c6ce2cb97cf1029e212046e81', 'CLIENT_NAME' => 'PM Web Designer', 'CLIENT_DESCRIPTION' => 'ProcessMaker Web Designer App', 'CLIENT_WEBSITE' => 'www.processmaker.com', 'REDIRECT_URI' => $endpoint, 'USR_UID' => '00000000000000000000000000000001' ]); if (!empty(config('oauthClients.mobile.clientId'))) { DB::connection(self::CONNECTION_INSTALL) ->table('OAUTH_CLIENTS') ->insert([ 'CLIENT_ID' => config('oauthClients.mobile.clientId'), 'CLIENT_SECRET' => config('oauthClients.mobile.clientSecret'), 'CLIENT_NAME' => config('oauthClients.mobile.clientName'), 'CLIENT_DESCRIPTION' => config('oauthClients.mobile.clientDescription'), 'CLIENT_WEBSITE' => config('oauthClients.mobile.clientWebsite'), 'REDIRECT_URI' => $endpoint, 'USR_UID' => '00000000000000000000000000000001' ]); } $indexFileUpdated = true; if (defined('PARTNER_FLAG') || isset($_REQUEST['PARTNER_FLAG'])) { $this->buildParternExtras($adminUsername, $adminPassword, $_REQUEST['workspace'], $langUri, $skinUri); } else { try { G::update_php_ini($envFile, $updatedConf); } catch (Exception $e) { $info->result = false; $info->message = G::LoadTranslation('ID_PROCESSMAKER_WRITE_CONFIG_INDEX', SYS_LANG, [$envFile]); $info->message .= G::LoadTranslation('ID_PROCESSMAKER_UI_NOT_INSTALL'); $this->installLog(G::LoadTranslation('ID_INSTALL_BUT_ERROR', SYS_LANG, ['env.ini'])); return $info; } try { // update the main index file $indexFileUpdated = System::updateIndexFile(['lang' => 'en', 'skin' => $updatedConf['default_skin']]); } catch (Exception $e) { $info->result = false; $info->message = G::LoadTranslation('ID_PROCESSMAKER_WRITE_CONFIG_INDEX', SYS_LANG, [PATH_HTML . "index.html."]); $info->message .= G::LoadTranslation('ID_PROCESSMAKER_UI_NOT_INSTALL'); $this->installLog(G::LoadTranslation('ID_INSTALL_BUT_ERROR', SYS_LANG, ['index.html'])); return $info; } } $this->installLog(G::LoadTranslation('ID_INDEX_FILE_UPDATED', SYS_LANG, [$indexFileUpdated, $sysConf['default_lang'], $sysConf['default_skin']])); $this->installLog(G::LoadTranslation('ID_INSTALL_SUCESS')); $info->result = true; $info->message = G::LoadTranslation('ID_INSTALL_SUCESS'); $info->messageFinish = G::LoadTranslation('ID_PROCESSMAKER_SUCCESS_INSTALLED', SYS_LANG, [$workspace]); } catch (Exception $e) { $info->canRedirect = false; $info->result = false; $info->message = $e->getMessage(); } return $info; } public function getSystemName($siteShared) { $systemName = ''; if (substr($siteShared, -1) != '/') { $siteShared .= '/'; } if (file_exists($siteShared . 'partner.info')) { $dataInfo = parse_ini_file($siteShared . 'partner.info'); if (isset($dataInfo['system_name'])) { $systemName = trim($dataInfo['system_name']); } } return $systemName; } /** * Get the Database engines list * * @return object */ public function getEngines() { $this->setResponseType('json'); $engines = []; if (function_exists('mysqli_query')) { $engine = new stdclass(); $engine->id = 'mysql'; $engine->label = 'MySQL'; $engines[] = $engine; } return $engines; } public function checkDatabases() { $filter = new InputFilter(); $this->setResponseType('json'); $info = new stdclass(); $db_hostname = $filter->validateInput($_REQUEST['db_hostname']); $db_username = $filter->validateInput($_REQUEST['db_username']); $db_password = urlencode($_REQUEST['db_password']); $db_password = urldecode($filter->validateInput($db_password)); $db_port = $filter->validateInput($_REQUEST['db_port']); switch ($_REQUEST['db_engine']) { case 'mysql': $wfDatabase = $filter->validateInput($_REQUEST['wfDatabase'], 'nosql'); self::setNewConnection(self::CONNECTION_TEST_INSTALL, $db_hostname, $db_username, $db_password, '', $db_port); $response = DB::connection(self::CONNECTION_TEST_INSTALL) ->select("show databases like '$wfDatabase'"); $info->wfDatabaseExists = count($response) > 0; break; case 'sqlsrv': $arguments = array("UID" => $db_username, "PWD" => $db_password); $link = @sqlsrv_connect($db_hostname, $arguments); $wfDatabase = $filter->validateInput($_REQUEST['wfDatabase'], 'nosql'); $query = "select * from sys.databases where name = '%s' "; $query = $filter->preventSqlInjection($query, array($wfDatabase)); $dataSet = @sqlsrv_query($link, $query); $info->wfDatabaseExists = (@sqlsrv_num_rows($dataSet) > 0); break; default: break; } $info->errMessage = G::LoadTranslation('ID_DATABASE_EXISTS_OVERWRITE'); return $info; } /** * Privates functions section, non callable by http request */ private function testMySQLConnection() { try { $filter = new InputFilter(); $info = new StdClass(); $info->result = false; $info->message = ''; if (!function_exists('mysqli_connect')) { $info->message = G::LoadTranslation('ID_PHP_MYSQLI_NOT_INSTALL'); return $info; } $dataRequest = $_REQUEST; $db_hostname = $filter->validateInput($dataRequest['db_hostname']); $db_port = $filter->validateInput($dataRequest['db_port']); $db_username = $filter->validateInput($dataRequest['db_username']); $db_password = urlencode($dataRequest['db_password']); $db_password = urldecode($filter->validateInput($db_password)); $fp = @fsockopen($db_hostname, $db_port, $errno, $errstr, 30); if (!$fp) { $info->message .= G::LoadTranslation('ID_CONNECTION_ERROR', SYS_LANG, ["$errstr ($errno)"]); return $info; } $db_username = $filter->validateInput($db_username, 'nosql'); $db_hostname = $filter->validateInput($db_hostname, 'nosql'); self::setNewConnection(self::CONNECTION_TEST_INSTALL, $db_hostname, $db_username, $db_password, '', $db_port); $query = "SELECT * FROM `information_schema`.`USER_PRIVILEGES` where (GRANTEE = \"'$db_username'@'$db_hostname'\" OR GRANTEE = \"'$db_username'@'%%'\") "; $response = DB::connection(self::CONNECTION_TEST_INSTALL)->select($query); if (!is_array($response)) { $info->message .= G::LoadTranslation('ID_CONNECTION_ERROR_PRIVILEGE', SYS_LANG, [$db_username]); return $info; } $info->message .= G::LoadTranslation('ID_MYSQL_SUCCESS_CONNECT'); $info->result = true; } catch (Exception $e) { $info->result = false; $info->message = G::LoadTranslation('ID_MYSQL_CREDENTIALS_WRONG'); } return $info; } /** * This function define the partner behaviour when the PARTNER_FLAG is defined * Execute to change of skin * * @return void */ private function setPartner() { if (defined('PARTNER_FLAG') || isset($_REQUEST['PARTNER_FLAG'])) { // Execute sql for partner $pathMysqlPartner = PATH_CORE . 'data' . PATH_SEP . 'partner' . PATH_SEP . 'mysql' . PATH_SEP; if (G::verifyPath($pathMysqlPartner)) { $filesSlq = glob($pathMysqlPartner . '*.sql'); foreach ($filesSlq as $value) { $this->mysqlFileQuery($value); } } // Execute to change of skin $pathSkinPartner = PATH_CORE . 'data' . PATH_SEP . 'partner' . PATH_SEP . 'skin' . PATH_SEP; if (G::verifyPath($pathSkinPartner)) { $fileTar = glob($pathSkinPartner . '*.tar'); foreach ($fileTar as $value) { $dataFile = pathinfo($value); $nameSkinTmp = $dataFile['filename']; $tar = new Archive_Tar($value); $pathSkinTmp = $pathSkinPartner . 'tmp' . PATH_SEP; G::rm_dir($pathSkinTmp); G::verifyPath($pathSkinTmp, true); chmod($pathSkinTmp, 0777); $tar->extract($pathSkinTmp); $pathSkinName = $pathSkinTmp . $nameSkinTmp . PATH_SEP; chmod($pathSkinName, 0777); G::verifyPath(PATH_CORE . 'skinEngine' . PATH_SEP . 'tmp', true); $skinClassic = PATH_CORE . 'skinEngine' . PATH_SEP . 'tmp' . PATH_SEP; if (is_dir($pathSkinName)) { $this->copyFile($pathSkinName, $skinClassic); } G::rm_dir(PATH_CORE . 'skinEngine' . PATH_SEP . 'base'); rename(PATH_CORE . 'skinEngine' . PATH_SEP . 'tmp', PATH_CORE . 'skinEngine' . PATH_SEP . 'base'); G::rm_dir(PATH_CORE . 'skinEngine' . PATH_SEP . 'tmp'); break; } } } } /** * Copy a directory or file * * @param string $fromDir * @param string $toDir * @param integer $chmod * * @return void */ public function copyFile($fromDir, $toDir, $chmod = 0777) { $errors = []; $messages = []; if (!is_writable($toDir)) { $errors[] = 'target ' . $toDir . ' is not writable'; } if (!is_dir($toDir)) { $errors[] = 'target ' . $toDir . ' is not a directory'; } if (!is_dir($fromDir)) { $errors[] = 'source ' . $fromDir . ' is not a directory'; } if (!empty($errors)) { return false; } $exceptions = array('.', '..'); $handle = opendir($fromDir); while (false !== ($item = readdir($handle))) { if (!in_array($item, $exceptions)) { $from = str_replace('//', '/', $fromDir . '/' . $item); $to = str_replace('//', '/', $toDir . '/' . $item); if (is_file($from)) { if (@copy($from, $to)) { chmod($to, $chmod); touch($to, filemtime($from)); } } if (is_dir($from)) { if (@mkdir($to)) { chmod($to, $chmod); } $this->copyFile($from, $to, $chmod); } } } closedir($handle); } /** * Define build Pattern Extras related to: * Upload translation .po file * Upload skin file * Upload plugin file * Active plugins to enterprise * * @param string $username * @param string $password * @param string $workspace * @param string $lang * @param string $skinName * * @return void */ private function buildParternExtras($username, $password, $workspace, $lang, $skinName) { $filter = new InputFilter(); ini_set('max_execution_time', '0'); $serv = 'http://'; if (isset($_SERVER['HTTPS']) && !empty(trim($_SERVER['HTTPS']))) { $serv = 'https://'; } $serv .= $_SERVER['SERVER_NAME']; if (isset($_SERVER['SERVER_PORT']) && !empty(trim($_SERVER['SERVER_PORT']))) { $serv .= ':' . $_SERVER['SERVER_PORT']; } // create session $cookiefile = sys_get_temp_dir() . PATH_SEP . 'curl-session'; $fp = fopen($cookiefile, "w"); fclose($fp); chmod($cookiefile, 0777); $user = urlencode($username); $user = $filter->validateInput($user); $pass = urlencode($password); $pass = $filter->validateInput($pass); $lang = urlencode($lang); $lang = $filter->validateInput($lang); $ch = curl_init(); // set URL and other appropriate options curl_setopt($ch, CURLOPT_URL, "$serv/sys{$workspace}/{$lang}/{$skinName}/login/authentication"); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_COOKIEFILE, $cookiefile); curl_setopt($ch, CURLOPT_COOKIEJAR, $cookiefile); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POSTFIELDS, "form[USR_USERNAME]=$user&form[USR_PASSWORD]=$pass&form[USER_LANG]=$lang"); curl_setopt($ch, CURLOPT_TIMEOUT, 90); $output = curl_exec($ch); curl_close($ch); /** * Upload translation .po file */ $ch = curl_init(); $postData = []; // File to upload/post $postData['form[LANGUAGE_FILENAME]'] = "@" . PATH_CORE . "content/translations/processmaker.$lang.po"; curl_setopt($ch, CURLOPT_URL, "$serv/sys{$workspace}/{$lang}/{$skinName}/setup/languages_Import"); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_VERBOSE, 0); curl_setopt($ch, CURLOPT_COOKIEFILE, $cookiefile); curl_setopt($ch, CURLOPT_COOKIEJAR, $cookiefile); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); curl_setopt($ch, CURLOPT_TIMEOUT, 90); $output = curl_exec($ch); curl_close($ch); /** * Upload skin file */ $ch = curl_init(); $postData = []; $skins = glob(PATH_CORE . "data/partner/*.tar"); if (count($skins) > 0) { $skin = $skins[0]; $postData['overwrite_files'] = "on"; $postData['workspace'] = "global"; $postData['option'] = "standardupload"; $postData['action'] = "importSkin"; // File to upload/post $postData['uploadedFile'] = "@" . $skin; curl_setopt($ch, CURLOPT_URL, "$serv/sys{$workspace}/{$lang}/{$skinName}/setup/skin_Ajax"); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_VERBOSE, 0); curl_setopt($ch, CURLOPT_COOKIEFILE, $cookiefile); curl_setopt($ch, CURLOPT_COOKIEJAR, $cookiefile); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); curl_setopt($ch, CURLOPT_TIMEOUT, 90); $output = curl_exec($ch); curl_close($ch); } /** * Upload plugin file */ $ch = curl_init(); $postData = []; // resolv the plugin name $plugins = glob(PATH_CORE . "plugins/*.tar"); if (count($plugins) > 0) { $pluginName = $plugins[0]; // File to upload/post $postData['form[PLUGIN_FILENAME]'] = "@{$pluginName}"; curl_setopt($ch, CURLOPT_URL, "$serv/sys{$workspace}/{$lang}/{$skinName}/setup/pluginsImportFile"); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_VERBOSE, 0); curl_setopt($ch, CURLOPT_COOKIEFILE, $cookiefile); curl_setopt($ch, CURLOPT_COOKIEJAR, $cookiefile); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); curl_setopt($ch, CURLOPT_TIMEOUT, 90); $output = curl_exec($ch); curl_close($ch); } /** * Active plugins to enterprise */ if (!defined("PATH_PM_ENTERPRISE")) { define("PATH_PM_ENTERPRISE", PATH_CORE . "/plugins/enterprise/"); } set_include_path(PATH_PM_ENTERPRISE . PATH_SEPARATOR . get_include_path()); require_once('classes/model/AddonsManager.php'); $plugins = glob(PATH_CORE . "plugins/*.php"); foreach ($plugins as $value) { $dataPlugin = pathinfo($value); $namePlugin = $dataPlugin['filename']; if ($value !== 'enterprise') { $db_hostname = trim($_REQUEST['db_hostname']); $db_hostname = $filter->validateInput($db_hostname); $db_port = trim($_REQUEST['db_port']); $db_port = $filter->validateInput($db_port); $db_username = trim($_REQUEST['db_username']); $db_username = $filter->validateInput($db_username); $db_password = urlencode(trim($_REQUEST['db_password'])); $db_password = urldecode($filter->validateInput($db_password)); $wf = trim($_REQUEST['wfDatabase']); $wf = $filter->validateInput($wf); $db_host = ($db_port != '' && $db_port != 3306) ? $db_hostname . ':' . $db_port : $db_hostname; $row = DB::connection(self::CONNECTION_INSTALL) ->table('ADDONS_MANAGER') ->select('STORE_ID') ->where('ADDON_NAME', $namePlugin) ->toArray(); if ($row) { $ch = curl_init(); $postData = []; $postData['action'] = "enable"; $postData['addon'] = $namePlugin; $postData['store'] = $row['STORE_ID']; curl_setopt($ch, CURLOPT_URL, "$serv/sys{$workspace}/{$lang}/{$skinName}/enterprise/addonsStoreAction"); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_VERBOSE, 0); curl_setopt($ch, CURLOPT_COOKIEFILE, $cookiefile); curl_setopt($ch, CURLOPT_COOKIEJAR, $cookiefile); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); curl_setopt($ch, CURLOPT_TIMEOUT, 90); $output = curl_exec($ch); curl_close($ch); } } } } /** * Verify/create framework shared directory structure * */ private function verifySharedFrameworkPaths($sharedPath) { $paths = [ $sharedPath . 'framework' => 0770, $sharedPath . 'framework' . DIRECTORY_SEPARATOR . 'cache' => 0770, ]; foreach ($paths as $path => $permission) { if (!file_exists($path)) { G::mk_dir($path, $permission); } if (!file_exists($path)) { return false; } } return true; } }