You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1653 lines
65 KiB

<?php
/**
*
* Installer class.
*
* @package OpenEMR
* @link https://www.open-emr.org
* @author Andrew Moore <amoore@cpan.org>
* @author Ranganath Pathak <pathak@scrs1.org>
* @author Brady Miller <brady.g.miller@gmail.com>
* @copyright Copyright (c) 2010 Andrew Moore <amoore@cpan.org>
* @copyright Copyright (c) 2019 Ranganath Pathak <pathak@scrs1.org>
* @copyright Copyright (c) 2019 Brady Miller <brady.g.miller@gmail.com>
* @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
*/
use OpenEMR\Gacl\GaclApi;
class Installer
{
public function __construct($cgi_variables)
{
// Installation variables
// For a good explanation of these variables, see documentation in
// the contrib/util/installScripts/InstallerAuto.php file.
$this->iuser = isset($cgi_variables['iuser']) ? ($cgi_variables['iuser']) : '';
$this->iuserpass = isset($cgi_variables['iuserpass']) ? ($cgi_variables['iuserpass']) : '';
$this->iuname = isset($cgi_variables['iuname']) ? ($cgi_variables['iuname']) : '';
$this->iufname = isset($cgi_variables['iufname']) ? ($cgi_variables['iufname']) : '';
$this->igroup = isset($cgi_variables['igroup']) ? ($cgi_variables['igroup']) : '';
$this->i2faEnable = isset($cgi_variables['i2faenable']) ? ($cgi_variables['i2faenable']) : '';
$this->i2faSecret = isset($cgi_variables['i2fasecret']) ? ($cgi_variables['i2fasecret']) : '';
$this->server = isset($cgi_variables['server']) ? ($cgi_variables['server']) : ''; // mysql server (usually localhost)
$this->loginhost = isset($cgi_variables['loginhost']) ? ($cgi_variables['loginhost']) : ''; // php/apache server (usually localhost)
$this->port = isset($cgi_variables['port']) ? ($cgi_variables['port']) : '';
$this->root = isset($cgi_variables['root']) ? ($cgi_variables['root']) : '';
$this->rootpass = isset($cgi_variables['rootpass']) ? ($cgi_variables['rootpass']) : '';
$this->login = isset($cgi_variables['login']) ? ($cgi_variables['login']) : '';
$this->pass = isset($cgi_variables['pass']) ? ($cgi_variables['pass']) : '';
$this->dbname = isset($cgi_variables['dbname']) ? ($cgi_variables['dbname']) : '';
$this->collate = isset($cgi_variables['collate']) ? ($cgi_variables['collate']) : '';
$this->site = isset($cgi_variables['site']) ? ($cgi_variables['site']) : '';
$this->source_site_id = isset($cgi_variables['source_site_id']) ? ($cgi_variables['source_site_id']) : '';
$this->clone_database = isset($cgi_variables['clone_database']) ? ($cgi_variables['clone_database']) : '';
$this->no_root_db_access = isset($cgi_variables['no_root_db_access']) ? ($cgi_variables['no_root_db_access']) : ''; // no root access to database. user/privileges pre-configured
$this->development_translations = isset($cgi_variables['development_translations']) ? ($cgi_variables['development_translations']) : '';
$this->new_theme = isset($cgi_variables['new_theme']) ? ($cgi_variables['new_theme']) : '';
// Make this true for IPPF.
$this->ippf_specific = false;
// Record name of sql access file
$GLOBALS['OE_SITES_BASE'] = dirname(__FILE__) . '/../../sites';
$GLOBALS['OE_SITE_DIR'] = $GLOBALS['OE_SITES_BASE'] . '/' . $this->site;
$this->conffile = $GLOBALS['OE_SITE_DIR'] . '/sqlconf.php';
// Record names of sql table files
$this->main_sql = dirname(__FILE__) . '/../../sql/database.sql';
$this->translation_sql = dirname(__FILE__) . '/../../contrib/util/language_translations/currentLanguage_utf8.sql';
$this->devel_translation_sql = "http://translations.openemr.io/languageTranslations_utf8.sql";
$this->ippf_sql = dirname(__FILE__) . "/../../sql/ippf_layout.sql";
$this->icd9 = dirname(__FILE__) . "/../../sql/icd9.sql";
$this->cvx = dirname(__FILE__) . "/../../sql/cvx_codes.sql";
$this->additional_users = dirname(__FILE__) . "/../../sql/official_additional_users.sql";
// Prepare the dumpfile list
$this->initialize_dumpfile_list();
// Entities to hold error and debug messages
$this->error_message = '';
$this->debug_message = '';
// Entity to hold sql connection
$this->dbh = false;
}
public function login_is_valid()
{
if (($this->login == '') || (! isset($this->login))) {
$this->error_message = "login is invalid: '$this->login'";
return false;
}
return true;
}
public function char_is_valid($input_text)
{
// to prevent php injection
trim($input_text);
if ($input_text == '') {
return false;
}
if (preg_match('@[\\\\;()<>/\'"]@', $input_text)) {
return false;
}
return true;
}
public function databaseNameIsValid($name)
{
if (preg_match('/[^A-Za-z0-9_-]/', $name)) {
return false;
}
return true;
}
public function collateNameIsValid($name)
{
if (preg_match('/[^A-Za-z0-9_-]/', $name)) {
return false;
}
return true;
}
public function iuser_is_valid()
{
if (strpos($this->iuser, " ")) {
$this->error_message = "Initial user is invalid: '$this->iuser'";
return false;
}
return true;
}
public function iuname_is_valid()
{
if ($this->iuname == "" || !isset($this->iuname)) {
$this->error_message = "Initial user last name is invalid: '$this->iuname'";
return false;
}
return true;
}
public function password_is_valid()
{
if ($this->pass == "" || !isset($this->pass)) {
$this->error_message = "The password for the new database account is invalid: '$this->pass'";
return false;
}
return true;
}
public function user_password_is_valid()
{
if ($this->iuserpass == "" || !isset($this->iuserpass)) {
$this->error_message = "The password for the user is invalid: '$this->iuserpass'";
return false;
}
return true;
}
public function root_database_connection()
{
$this->dbh = $this->connect_to_database($this->server, $this->root, $this->rootpass, $this->port);
if ($this->dbh) {
if (! $this->set_sql_strict()) {
$this->error_message = 'unable to set strict sql setting';
return false;
}
return true;
} else {
$this->error_message = 'unable to connect to database as root';
return false;
}
}
public function user_database_connection()
{
$this->dbh = $this->connect_to_database($this->server, $this->login, $this->pass, $this->port, $this->dbname);
if (! $this->dbh) {
$this->error_message = "unable to connect to database as user: '$this->login'";
return false;
}
if (! $this->set_sql_strict()) {
$this->error_message = 'unable to set strict sql setting';
return false;
}
if (! $this->set_collation()) {
$this->error_message = 'unable to set sql collation';
return false;
}
if (! mysqli_select_db($this->dbh, $this->dbname)) {
$this->error_message = "unable to select database: '$this->dbname'";
return false;
}
return true;
}
public function create_database()
{
$sql = "create database " . $this->escapeDatabaseName($this->dbname);
if (empty($this->collate) || ($this->collate == 'utf8_general_ci')) {
$this->collate = 'utf8mb4_general_ci';
}
$sql .= " character set utf8mb4 collate " . $this->escapeCollateName($this->collate);
$this->set_collation();
return $this->execute_sql($sql);
}
public function drop_database()
{
$sql = "drop database if exists " . $this->escapeDatabaseName($this->dbname);
return $this->execute_sql($sql);
}
public function create_database_user()
{
// First, check for database user in the mysql.user table (this works for all except mariadb 10.4+)
$checkUser = $this->execute_sql("SELECT user FROM mysql.user WHERE user = '" . $this->escapeSql($this->login) . "' AND host = '" . $this->escapeSql($this->loginhost) . "'", false);
if ($checkUser === false) {
// Above caused error, so is MariaDB 10.4+, and need to do below query instead in the mysql.global_priv table
$checkUser = $this->execute_sql("SELECT user FROM mysql.global_priv WHERE user = '" . $this->escapeSql($this->login) . "' AND host = '" . $this->escapeSql($this->loginhost) . "'");
}
if ($checkUser === false) {
// there was an error in the check database user query, so return false
return false;
} elseif ($checkUser->num_rows > 0) {
// the mysql user already exists, so do not need to create the user, but need to set the password
// Note need to try two different methods, first is for newer mysql versions and second is for older mysql versions (if the first method fails)
$returnSql = $this->execute_sql("ALTER USER '" . $this->escapeSql($this->login) . "'@'" . $this->escapeSql($this->loginhost) . "' IDENTIFIED BY '" . $this->escapeSql($this->pass) . "'", false);
if ($returnSql === false) {
error_log("Using older mysql version method to set password for the mysql user");
$returnSql = $this->execute_sql("SET PASSWORD FOR '" . $this->escapeSql($this->login) . "'@'" . $this->escapeSql($this->loginhost) . "' = PASSWORD('" . $this->escapeSql($this->pass) . "')");
}
return $returnSql;
} else {
// the mysql user does not yet exist, so create the user
return $this->execute_sql("CREATE USER '" . $this->escapeSql($this->login) . "'@'" . $this->escapeSql($this->loginhost) . "' IDENTIFIED BY '" . $this->escapeSql($this->pass) . "'");
}
}
public function grant_privileges()
{
return $this->execute_sql("GRANT ALL PRIVILEGES ON " . $this->escapeDatabaseName($this->dbname) . ".* TO '" . $this->escapeSql($this->login) . "'@'" . $this->escapeSql($this->loginhost) . "'");
}
public function disconnect()
{
return mysqli_close($this->dbh);
}
/**
* This method creates any dumpfiles necessary.
* This is actually only done if we're cloning an existing site
* and we need to dump their database into a file.
* @return bool indicating success
*/
public function create_dumpfiles()
{
return $this->dumpSourceDatabase();
}
public function load_dumpfiles()
{
$sql_results = ''; // information string which is returned
foreach ($this->dumpfiles as $filename => $title) {
$sql_results_temp = '';
$sql_results_temp = $this->load_file($filename, $title);
if ($sql_results_temp == false) {
return false;
}
$sql_results .= $sql_results_temp;
}
return $sql_results;
}
public function load_file($filename, $title)
{
$sql_results = ''; // information string which is returned
$sql_results .= "Creating $title tables...\n";
$fd = fopen($filename, 'r');
if ($fd == false) {
$this->error_message = "ERROR. Could not open dumpfile '$filename'.\n";
return false;
}
$query = "";
$line = "";
// Settings to drastically speed up installation with InnoDB
if (! $this->execute_sql("SET autocommit=0;")) {
return false;
}
if (! $this->execute_sql("START TRANSACTION;")) {
return false;
}
while (!feof($fd)) {
$line = fgets($fd, 1024);
$line = rtrim($line);
if (substr($line, 0, 2) == "--") { // Kill comments
continue;
}
if (substr($line, 0, 1) == "#") { // Kill comments
continue;
}
if ($line == "") {
continue;
}
$query = $query . $line; // Check for full query
$chr = substr($query, strlen($query) - 1, 1);
if ($chr == ";") { // valid query, execute
$query = rtrim($query, ";");
if (! $this->execute_sql($query)) {
return false;
}
$query = "";
}
}
// Settings to drastically speed up installation with InnoDB
if (! $this->execute_sql("COMMIT;")) {
return false;
}
if (! $this->execute_sql("SET autocommit=1;")) {
return false;
}
$sql_results .= "<span class='text-success'><b>OK</b></span>.<br>\n";
fclose($fd);
return $sql_results;
}
public function add_version_info()
{
include dirname(__FILE__) . "/../../version.php";
if ($this->execute_sql("UPDATE version SET v_major = '" . $this->escapeSql($v_major) . "', v_minor = '" . $this->escapeSql($v_minor) . "', v_patch = '" . $this->escapeSql($v_patch) . "', v_realpatch = '" . $this->escapeSql($v_realpatch) . "', v_tag = '" . $this->escapeSql($v_tag) . "', v_database = '" . $this->escapeSql($v_database) . "', v_acl = '" . $this->escapeSql($v_acl) . "'") == false) {
$this->error_message = "ERROR. Unable insert version information into database\n" .
"<p>" . mysqli_error($this->dbh) . " (#" . mysqli_errno($this->dbh) . ")\n";
return false;
}
return true;
}
public function add_initial_user()
{
if ($this->execute_sql("INSERT INTO `groups` (id, name, user) VALUES (1,'" . $this->escapeSql($this->igroup) . "','" . $this->escapeSql($this->iuser) . "')") == false) {
$this->error_message = "ERROR. Unable to add initial user group\n" .
"<p>" . mysqli_error($this->dbh) . " (#" . mysqli_errno($this->dbh) . ")\n";
return false;
}
if ($this->execute_sql("INSERT INTO users (id, username, password, authorized, lname, fname, facility_id, calendar, cal_ui) VALUES (1,'" . $this->escapeSql($this->iuser) . "','NoLongerUsed',1,'" . $this->escapeSql($this->iuname) . "','" . $this->escapeSql($this->iufname) . "',3,1,3)") == false) {
$this->error_message = "ERROR. Unable to add initial user\n" .
"<p>" . mysqli_error($this->dbh) . " (#" . mysqli_errno($this->dbh) . ")\n";
return false;
}
$hash = password_hash($this->iuserpass, PASSWORD_DEFAULT);
if (empty($hash)) {
// Something is seriously wrong
error_log('OpenEMR Error : OpenEMR is not working because unable to create a hash.');
die("OpenEMR Error : OpenEMR is not working because unable to create a hash.");
}
if ($this->execute_sql("INSERT INTO users_secure (id, username, password, last_update_password) VALUES (1,'" . $this->escapeSql($this->iuser) . "','" . $this->escapeSql($hash) . "',NOW())") == false) {
$this->error_message = "ERROR. Unable to add initial user login credentials\n" .
"<p>" . mysqli_error($this->dbh) . " (#" . mysqli_errno($this->dbh) . ")\n";
return false;
}
// Create new 2fa if enabled
if (($this->i2faEnable) && (!empty($this->i2faSecret)) && (class_exists('Totp')) && (class_exists('OpenEMR\Common\Crypto\CryptoGen'))) {
// Encrypt the new secret with the hashed password
$cryptoGen = new OpenEMR\Common\Crypto\CryptoGen();
$secret = $cryptoGen->encryptStandard($this->i2faSecret, $hash);
if ($this->execute_sql("INSERT INTO login_mfa_registrations (user_id, name, method, var1, var2) VALUES (1, 'App Based 2FA', 'TOTP', '" . $this->escapeSql($secret) . "', '')") == false) {
$this->error_message = "ERROR. Unable to add initial user's 2FA credentials\n" .
"<p>" . mysqli_error($this->dbh) . " (#" . mysqli_errno($this->dbh) . ")\n";
return false;
}
}
return true;
}
/**
* Handle the additional users now that our gacl's have finished installing.
* @return bool
*/
public function install_additional_users()
{
// Add the official openemr users (services)
if ($this->load_file($this->additional_users, "Additional Official Users") == false) {
return false;
}
return true;
}
public function on_care_coordination()
{
$resource = $this->execute_sql("SELECT `mod_id` FROM `modules` WHERE `mod_name` = 'Carecoordination' LIMIT 1");
$resource_array = mysqli_fetch_array($resource, MYSQLI_ASSOC);
$modId = $resource_array['mod_id'];
if (empty($modId)) {
$this->error_message = "ERROR configuring Care Coordination module. Unable to get mod_id for Carecoordination module\n";
return false;
}
$resource = $this->execute_sql("SELECT `section_id` FROM `module_acl_sections` WHERE `section_identifier` = 'carecoordination' LIMIT 1");
$resource_array = mysqli_fetch_array($resource, MYSQLI_ASSOC);
$sectionId = $resource_array['section_id'];
if (empty($sectionId)) {
$this->error_message = "ERROR configuring Care Coordination module. Unable to get section_id for carecoordination module section\n";
return false;
}
$resource = $this->execute_sql("SELECT `id` FROM `gacl_aro_groups` WHERE `value` = 'admin' LIMIT 1");
$resource_array = mysqli_fetch_array($resource, MYSQLI_ASSOC);
$groupId = $resource_array['id'];
if (empty($groupId)) {
$this->error_message = "ERROR configuring Care Coordination module. Unable to get id for gacl_aro_groups admin section\n";
return false;
}
if ($this->execute_sql("INSERT INTO `module_acl_group_settings` (`module_id`, `group_id`, `section_id`, `allowed`) VALUES ('" . $this->escapeSql($modId) . "', '" . $this->escapeSql($groupId) . "', '" . $this->escapeSql($sectionId) . "', 1)") == false) {
$this->error_message = "ERROR configuring Care Coordination module. Unable to add the module_acl_group_settings acl entry\n";
return false;
}
return true;
}
/**
* Generates the initial user's 2FA QR Code
* @return bool|string|void
*/
public function get_initial_user_2fa_qr()
{
if (($this->i2faEnable) && (!empty($this->i2faSecret)) && (class_exists('Totp'))) {
$adminTotp = new Totp($this->i2faSecret, $this->iuser);
$qr = $adminTotp->generateQrCode();
return $qr;
}
return false;
}
/**
* Create site directory if it is missing.
* @global string $GLOBALS['OE_SITE_DIR'] contains the name of the site directory to create
* @return name of the site directory or False
*/
public function create_site_directory()
{
if (!file_exists($GLOBALS['OE_SITE_DIR'])) {
$source_directory = $GLOBALS['OE_SITES_BASE'] . "/" . $this->source_site_id;
$destination_directory = $GLOBALS['OE_SITE_DIR'];
if (! $this->recurse_copy($source_directory, $destination_directory)) {
$this->error_message = "unable to copy directory: '$source_directory' to '$destination_directory'. " . $this->error_message;
return false;
}
// the new site will create it's own keys so okay to delete these copied from the source site
if (!$this->clone_database) {
array_map('unlink', glob($destination_directory . "/documents/logs_and_misc/methods/*"));
}
}
return true;
}
public function write_configuration_file()
{
@touch($this->conffile); // php bug
$fd = @fopen($this->conffile, 'w');
if (! $fd) {
$this->error_message = 'unable to open configuration file for writing: ' . $this->conffile;
return false;
}
$string = '<?php
// OpenEMR
// MySQL Config
';
$it_died = 0; //fmg: variable keeps running track of any errors
fwrite($fd, $string) or $it_died++;
fwrite($fd, "global \$disable_utf8_flag;\n") or $it_died++;
fwrite($fd, "\$disable_utf8_flag = false;\n\n") or $it_died++;
fwrite($fd, "\$host\t= '$this->server';\n") or $it_died++;
fwrite($fd, "\$port\t= '$this->port';\n") or $it_died++;
fwrite($fd, "\$login\t= '$this->login';\n") or $it_died++;
fwrite($fd, "\$pass\t= '$this->pass';\n") or $it_died++;
fwrite($fd, "\$dbase\t= '$this->dbname';\n") or $it_died++;
fwrite($fd, "\$db_encoding\t= 'utf8mb4';\n") or $it_died++;
$string = '
$sqlconf = array();
global $sqlconf;
$sqlconf["host"]= $host;
$sqlconf["port"] = $port;
$sqlconf["login"] = $login;
$sqlconf["pass"] = $pass;
$sqlconf["dbase"] = $dbase;
$sqlconf["db_encoding"] = $db_encoding;
//////////////////////////
//////////////////////////
//////////////////////////
//////DO NOT TOUCH THIS///
$config = 1; /////////////
//////////////////////////
//////////////////////////
//////////////////////////
?>
';
fwrite($fd, $string) or $it_died++;
fclose($fd) or $it_died++;
//it's rather irresponsible to not report errors when writing this file.
if ($it_died != 0) {
$this->error_message = "ERROR. Couldn't write $it_died lines to config file '$this->conffile'.\n";
return false;
}
// Tell PHP that its cached bytecode version of sqlconf.php is no longer usable.
if (function_exists('opcache_invalidate')) {
opcache_invalidate($this->conffile, true);
}
return true;
}
public function insert_globals()
{
if (!(function_exists('xl'))) {
function xl($s)
{
return $s;
}
} else {
$GLOBALS['temp_skip_translations'] = true;
}
$skipGlobalEvent = true; //use in globals.inc.php script to skip event stuff
require(dirname(__FILE__) . '/../globals.inc.php');
foreach ($GLOBALS_METADATA as $grpname => $grparr) {
foreach ($grparr as $fldid => $fldarr) {
list($fldname, $fldtype, $flddef, $flddesc) = $fldarr;
if (is_array($fldtype) || substr($fldtype, 0, 2) !== 'm_') {
$res = $this->execute_sql("SELECT count(*) AS count FROM globals WHERE gl_name = '" . $this->escapeSql($fldid) . "'");
$row = mysqli_fetch_array($res, MYSQLI_ASSOC);
if (empty($row['count'])) {
$this->execute_sql("INSERT INTO globals ( gl_name, gl_index, gl_value ) " .
"VALUES ( '" . $this->escapeSql($fldid) . "', '0', '" . $this->escapeSql($flddef) . "' )");
}
}
}
}
return true;
}
public function install_gacl()
{
$gacl = new GaclApi();
// Create the ACO sections. Every ACO must have a section.
//
if ($gacl->add_object_section('Accounting', 'acct', 10, 0, 'ACO') === false) {
$this->error_message = "ERROR, Unable to create the access controls for OpenEMR.";
return false;
}
// xl('Accounting')
$gacl->add_object_section('Administration', 'admin', 10, 0, 'ACO');
// xl('Administration')
$gacl->add_object_section('Encounters', 'encounters', 10, 0, 'ACO');
// xl('Encounters')
$gacl->add_object_section('Lists', 'lists', 10, 0, 'ACO');
// xl('Lists')
$gacl->add_object_section('Patients', 'patients', 10, 0, 'ACO');
// xl('Patients')
$gacl->add_object_section('Squads', 'squads', 10, 0, 'ACO');
// xl('Squads')
$gacl->add_object_section('Sensitivities', 'sensitivities', 10, 0, 'ACO');
// xl('Sensitivities')
$gacl->add_object_section('Placeholder', 'placeholder', 10, 0, 'ACO');
// xl('Placeholder')
$gacl->add_object_section('Nation Notes', 'nationnotes', 10, 0, 'ACO');
// xl('Nation Notes')
$gacl->add_object_section('Patient Portal', 'patientportal', 10, 0, 'ACO');
// xl('Patient Portal')
$gacl->add_object_section('Menus', 'menus', 10, 0, 'ACO');
// xl('Menus')
$gacl->add_object_section('Groups', 'groups', 10, 0, 'ACO');
// xl('Groups')
$gacl->add_object_section('Inventory', 'inventory', 10, 0, 'ACO');
// xl('Inventory')
// Create Accounting ACOs.
//
$gacl->add_object('acct', 'Billing (write optional)', 'bill', 10, 0, 'ACO');
// xl('Billing (write optional)')
$gacl->add_object('acct', 'Price Discounting', 'disc', 10, 0, 'ACO');
// xl('Price Discounting')
$gacl->add_object('acct', 'EOB Data Entry', 'eob', 10, 0, 'ACO');
// xl('EOB Data Entry')
$gacl->add_object('acct', 'Financial Reporting - my encounters', 'rep', 10, 0, 'ACO');
// xl('Financial Reporting - my encounters')
$gacl->add_object('acct', 'Financial Reporting - anything', 'rep_a', 10, 0, 'ACO');
// xl('Financial Reporting - anything')
// Create Administration ACOs.
//
$gacl->add_object('admin', 'Superuser', 'super', 10, 0, 'ACO');
// xl('Superuser')
$gacl->add_object('admin', 'Calendar Settings', 'calendar', 10, 0, 'ACO');
// xl('Calendar Settings')
$gacl->add_object('admin', 'Database Reporting', 'database', 10, 0, 'ACO');
// xl('Database Reporting')
$gacl->add_object('admin', 'Forms Administration', 'forms', 10, 0, 'ACO');
// xl('Forms Administration')
$gacl->add_object('admin', 'Practice Settings', 'practice', 10, 0, 'ACO');
// xl('Practice Settings')
$gacl->add_object('admin', 'Superbill Codes Administration', 'superbill', 10, 0, 'ACO');
// xl('Superbill Codes Administration')
$gacl->add_object('admin', 'Users/Groups/Logs Administration', 'users', 10, 0, 'ACO');
// xl('Users/Groups/Logs Administration')
$gacl->add_object('admin', 'Batch Communication Tool', 'batchcom', 10, 0, 'ACO');
// xl('Batch Communication Tool')
$gacl->add_object('admin', 'Language Interface Tool', 'language', 10, 0, 'ACO');
// xl('Language Interface Tool')
$gacl->add_object('admin', 'Inventory Administration', 'drugs', 10, 0, 'ACO');
// xl('Inventory Administration')
$gacl->add_object('admin', 'ACL Administration', 'acl', 10, 0, 'ACO');
// xl('ACL Administration')
$gacl->add_object('admin', 'Multipledb', 'multipledb', 10, 0, 'ACO');
// xl('Multipledb')
$gacl->add_object('admin', 'Menu', 'menu', 10, 0, 'ACO');
// xl('Menu')
$gacl->add_object('admin', 'Manage modules', 'manage_modules', 10, 0, 'ACO');
// xl('Manage modules')
// Create ACOs for encounters.
//
$gacl->add_object('encounters', 'Authorize - my encounters', 'auth', 10, 0, 'ACO');
// xl('Authorize - my encounters')
$gacl->add_object('encounters', 'Authorize - any encounters', 'auth_a', 10, 0, 'ACO');
// xl('Authorize - any encounters')
$gacl->add_object('encounters', 'Coding - my encounters (write,wsome optional)', 'coding', 10, 0, 'ACO');
// xl('Coding - my encounters (write,wsome optional)')
$gacl->add_object('encounters', 'Coding - any encounters (write,wsome optional)', 'coding_a', 10, 0, 'ACO');
// xl('Coding - any encounters (write,wsome optional)')
$gacl->add_object('encounters', 'Notes - my encounters (write,addonly optional)', 'notes', 10, 0, 'ACO');
// xl('Notes - my encounters (write,addonly optional)')
$gacl->add_object('encounters', 'Notes - any encounters (write,addonly optional)', 'notes_a', 10, 0, 'ACO');
// xl('Notes - any encounters (write,addonly optional)')
$gacl->add_object('encounters', 'Fix encounter dates - any encounters', 'date_a', 10, 0, 'ACO');
// xl('Fix encounter dates - any encounters')
$gacl->add_object('encounters', 'Less-private information (write,addonly optional)', 'relaxed', 10, 0, 'ACO');
// xl('Less-private information (write,addonly optional)')
// Create ACOs for lists.
//
$gacl->add_object('lists', 'Default List (write,addonly optional)', 'default', 10, 0, 'ACO');
// xl('Default List (write,addonly optional)')
$gacl->add_object('lists', 'State List (write,addonly optional)', 'state', 10, 0, 'ACO');
// xl('State List (write,addonly optional)')
$gacl->add_object('lists', 'Country List (write,addonly optional)', 'country', 10, 0, 'ACO');
// xl('Country List (write,addonly optional)')
$gacl->add_object('lists', 'Language List (write,addonly optional)', 'language', 10, 0, 'ACO');
// xl('Language List (write,addonly optional)')
$gacl->add_object('lists', 'Ethnicity-Race List (write,addonly optional)', 'ethrace', 10, 0, 'ACO');
// xl('Ethnicity-Race List (write,addonly optional)')
// Create ACOs for patientportal.
//
$gacl->add_object('patientportal', 'Patient Portal', 'portal', 10, 0, 'ACO');
// xl('Patient Portal')
// Create ACOs for modules.
//
$gacl->add_object('menus', 'Modules', 'modle', 10, 0, 'ACO');
// xl('Modules')
// Create ACOs for patients.
//
$gacl->add_object('patients', 'Appointments (write,wsome optional)', 'appt', 10, 0, 'ACO');
// xl('Appointments (write,wsome optional)')
$gacl->add_object('patients', 'Demographics (write,addonly optional)', 'demo', 10, 0, 'ACO');
// xl('Demographics (write,addonly optional)')
$gacl->add_object('patients', 'Medical/History (write,addonly optional)', 'med', 10, 0, 'ACO');
// xl('Medical/History (write,addonly optional)')
$gacl->add_object('patients', 'Transactions (write optional)', 'trans', 10, 0, 'ACO');
// xl('Transactions (write optional)')
$gacl->add_object('patients', 'Documents (write,addonly optional)', 'docs', 10, 0, 'ACO');
// xl('Documents (write,addonly optional)')
$gacl->add_object('patients', 'Documents Delete', 'docs_rm', 10, 0, 'ACO');
// xl('Documents Delete')
$gacl->add_object('patients', 'Patient Notes (write,addonly optional)', 'notes', 10, 0, 'ACO');
// xl('Patient Notes (write,addonly optional)')
$gacl->add_object('patients', 'Sign Lab Results (write,addonly optional)', 'sign', 10, 0, 'ACO');
// xl('Sign Lab Results (write,addonly optional)')
$gacl->add_object('patients', 'Patient Reminders (write,addonly optional)', 'reminder', 10, 0, 'ACO');
// xl('Patient Reminders (write,addonly optional)')
$gacl->add_object('patients', 'Clinical Reminders/Alerts (write,addonly optional)', 'alert', 10, 0, 'ACO');
// xl('Clinical Reminders/Alerts (write,addonly optional)')
$gacl->add_object('patients', 'Disclosures (write,addonly optional)', 'disclosure', 10, 0, 'ACO');
// xl('Disclosures (write,addonly optional)')
$gacl->add_object('patients', 'Prescriptions (write,addonly optional)', 'rx', 10, 0, 'ACO');
// xl('Prescriptions (write,addonly optional)')
$gacl->add_object('patients', 'Amendments (write,addonly optional)', 'amendment', 10, 0, 'ACO');
// xl('Amendments (write,addonly optional)')
$gacl->add_object('patients', 'Lab Results (write,addonly optional)', 'lab', 10, 0, 'ACO');
// xl('Lab Results (write,addonly optional)')
$gacl->add_object('patients', 'Patient Report', 'pat_rep', 10, 0, 'ACO');
// xl('Patient Report')
$gacl->add_object('groups', 'View/Add/Update groups', 'gadd', 10, 0, 'ACO');
// xl('View/Add/Update groups')
$gacl->add_object('groups', 'View/Create/Update groups appointment in calendar', 'gcalendar', 10, 0, 'ACO');
// xl('View/Create/Update groups appointment in calendar')
$gacl->add_object('groups', 'Group encounter log', 'glog', 10, 0, 'ACO');
// xl('Group encounter log')
$gacl->add_object('groups', 'Group detailed log of appointment in patient record', 'gdlog', 10, 0, 'ACO');
// xl('Group detailed log of appointment in patient record')
$gacl->add_object('groups', 'Send message from the permanent group therapist to the personal therapist', 'gm', 10, 0, 'ACO');
// xl('Send message from the permanent group therapist to the personal therapist')
// Create ACOs for sensitivities.
//
$gacl->add_object('sensitivities', 'Normal', 'normal', 10, 0, 'ACO');
// xl('Normal')
$gacl->add_object('sensitivities', 'High', 'high', 20, 0, 'ACO');
// xl('High')
// Create ACO for placeholder.
//
$gacl->add_object('placeholder', 'Placeholder (Maintains empty ACLs)', 'filler', 10, 0, 'ACO');
// xl('Placeholder (Maintains empty ACLs)')
// Create ACO for nationnotes.
//
$gacl->add_object('nationnotes', 'Nation Notes Configure', 'nn_configure', 10, 0, 'ACO');
// xl('Nation Notes Configure')
// Create ACOs for Inventory.
//
$gacl->add_object('inventory', 'Lots', 'lots', 10, 0, 'ACO');
// xl('Lots')
$gacl->add_object('inventory', 'Sales', 'sales', 20, 0, 'ACO');
// xl('Sales')
$gacl->add_object('inventory', 'Purchases', 'purchases', 30, 0, 'ACO');
// xl('Purchases')
$gacl->add_object('inventory', 'Transfers', 'transfers', 40, 0, 'ACO');
// xl('Transfers')
$gacl->add_object('inventory', 'Adjustments', 'adjustments', 50, 0, 'ACO');
// xl('Adjustments')
$gacl->add_object('inventory', 'Consumption', 'consumption', 60, 0, 'ACO');
// xl('Consumption')
$gacl->add_object('inventory', 'Destruction', 'destruction', 70, 0, 'ACO');
// xl('Destruction')
$gacl->add_object('inventory', 'Reporting', 'reporting', 80, 0, 'ACO');
// xl('Reporting')
// Create ARO groups.
//
$users = $gacl->add_group('users', 'OpenEMR Users', 0, 'ARO');
// xl('OpenEMR Users')
$admin = $gacl->add_group('admin', 'Administrators', $users, 'ARO');
// xl('Administrators')
$clin = $gacl->add_group('clin', 'Clinicians', $users, 'ARO');
// xl('Clinicians')
$doc = $gacl->add_group('doc', 'Physicians', $users, 'ARO');
// xl('Physicians')
$front = $gacl->add_group('front', 'Front Office', $users, 'ARO');
// xl('Front Office')
$back = $gacl->add_group('back', 'Accounting', $users, 'ARO');
// xl('Accounting')
$breakglass = $gacl->add_group('breakglass', 'Emergency Login', $users, 'ARO');
// xl('Emergency Login')
// Create a Users section for the AROs (humans).
//
$gacl->add_object_section('Users', 'users', 10, 0, 'ARO');
// xl('Users')
// Create the Administrator in the above-created "users" section
// and add him/her to the above-created "admin" group.
// If this script is being used by OpenEMR's setup, then will
// incorporate the installation values. Otherwise will
// hardcode the 'admin' user.
if (isset($this) && isset($this->iuser)) {
$gacl->add_object('users', $this->iuname, $this->iuser, 10, 0, 'ARO');
$gacl->add_group_object($admin, 'users', $this->iuser, 'ARO');
} else {
$gacl->add_object('users', 'Administrator', 'admin', 10, 0, 'ARO');
$gacl->add_group_object($admin, 'users', 'admin', 'ARO');
}
// Declare return terms for language translations
// xl('write') xl('wsome') xl('addonly') xl('view')
// Set permissions for administrators.
//
$gacl->add_acl(
array(
'acct' => array('bill', 'disc', 'eob', 'rep', 'rep_a'),
'admin' => array('calendar', 'database', 'forms', 'practice', 'superbill', 'users', 'batchcom', 'language', 'super', 'drugs', 'acl','multipledb','menu','manage_modules'),
'encounters' => array('auth_a', 'auth', 'coding_a', 'coding', 'notes_a', 'notes', 'date_a', 'relaxed'),
'inventory' => array('lots', 'sales', 'purchases', 'transfers', 'adjustments', 'consumption', 'destruction', 'reporting'),
'lists' => array('default','state','country','language','ethrace'),
'patients' => array('appt', 'demo', 'med', 'trans', 'docs', 'notes', 'sign', 'reminder', 'alert', 'disclosure', 'rx', 'amendment', 'lab', 'docs_rm','pat_rep'),
'sensitivities' => array('normal', 'high'),
'nationnotes' => array('nn_configure'),
'patientportal' => array('portal'),
'menus' => array('modle'),
'groups' => array('gadd','gcalendar','glog','gdlog','gm')
),
null,
array($admin),
null,
null,
1,
1,
'write',
'Administrators can do anything'
);
// xl('Administrators can do anything')
// Set permissions for physicians.
//
$gacl->add_acl(
array(
'patients' => array('pat_rep')
),
null,
array($doc),
null,
null,
1,
1,
'view',
'Things that physicians can only read'
);
// xl('Things that physicians can only read')
$gacl->add_acl(
array(
'placeholder' => array('filler')
),
null,
array($doc),
null,
null,
1,
1,
'addonly',
'Things that physicians can read and enter but not modify'
);
// xl('Things that physicians can read and enter but not modify')
$gacl->add_acl(
array(
'placeholder' => array('filler')
),
null,
array($doc),
null,
null,
1,
1,
'wsome',
'Things that physicians can read and partly modify'
);
// xl('Things that physicians can read and partly modify')
$gacl->add_acl(
array(
'acct' => array('disc', 'rep'),
'admin' => array('drugs'),
'encounters' => array('auth_a', 'auth', 'coding_a', 'coding', 'notes_a', 'notes', 'date_a', 'relaxed'),
'patients' => array('appt', 'demo', 'med', 'trans', 'docs', 'notes', 'sign', 'reminder', 'alert',
'disclosure', 'rx', 'amendment', 'lab'),
'sensitivities' => array('normal', 'high'),
'groups' => array('gcalendar','glog')
),
null,
array($doc),
null,
null,
1,
1,
'write',
'Things that physicians can read and modify'
);
// xl('Things that physicians can read and modify')
// Set permissions for clinicians.
//
$gacl->add_acl(
array(
'patients' => array('pat_rep')
),
null,
array($clin),
null,
null,
1,
1,
'view',
'Things that clinicians can only read'
);
// xl('Things that clinicians can only read')
$gacl->add_acl(
array(
'encounters' => array('notes', 'relaxed'),
'patients' => array('demo', 'med', 'docs', 'notes','trans', 'reminder', 'alert', 'disclosure', 'rx', 'amendment', 'lab'),
'sensitivities' => array('normal')
),
null,
array($clin),
null,
null,
1,
1,
'addonly',
'Things that clinicians can read and enter but not modify'
);
// xl('Things that clinicians can read and enter but not modify')
$gacl->add_acl(
array(
'placeholder' => array('filler')
),
null,
array($clin),
null,
null,
1,
1,
'wsome',
'Things that clinicians can read and partly modify'
);
// xl('Things that clinicians can read and partly modify')
$gacl->add_acl(
array(
'admin' => array('drugs'),
'encounters' => array('auth', 'coding', 'notes'),
'patients' => array('appt'),
'groups' => array('gcalendar', 'glog')
),
null,
array($clin),
null,
null,
1,
1,
'write',
'Things that clinicians can read and modify'
);
// xl('Things that clinicians can read and modify')
// Set permissions for front office staff.
//
$gacl->add_acl(
array(
'patients' => array('alert')
),
null,
array($front),
null,
null,
1,
1,
'view',
'Things that front office can only read'
);
// xl('Things that front office can only read')
$gacl->add_acl(
array(
'placeholder' => array('filler')
),
null,
array($front),
null,
null,
1,
1,
'addonly',
'Things that front office can read and enter but not modify'
);
// xl('Things that front office can read and enter but not modify')
$gacl->add_acl(
array(
'placeholder' => array('filler')
),
null,
array($front),
null,
null,
1,
1,
'wsome',
'Things that front office can read and partly modify'
);
// xl('Things that front office can read and partly modify')
$gacl->add_acl(
array(
'patients' => array('appt', 'demo'),
'groups' => array('gcalendar')
),
null,
array($front),
null,
null,
1,
1,
'write',
'Things that front office can read and modify'
);
// xl('Things that front office can read and modify')
// Set permissions for back office staff.
//
$gacl->add_acl(
array(
'patients' => array('alert')
),
null,
array($back),
null,
null,
1,
1,
'view',
'Things that back office can only read'
);
// xl('Things that back office can only read')
$gacl->add_acl(
array(
'placeholder' => array('filler')
),
null,
array($back),
null,
null,
1,
1,
'addonly',
'Things that back office can read and enter but not modify'
);
// xl('Things that back office can read and enter but not modify')
$gacl->add_acl(
array(
'placeholder' => array('filler')
),
null,
array($back),
null,
null,
1,
1,
'wsome',
'Things that back office can read and partly modify'
);
// xl('Things that back office can read and partly modify')
$gacl->add_acl(
array(
'acct' => array('bill', 'disc', 'eob', 'rep', 'rep_a'),
'admin' => array('practice', 'superbill'),
'encounters' => array('auth_a', 'coding_a', 'date_a'),
'patients' => array('appt', 'demo')
),
null,
array($back),
null,
null,
1,
1,
'write',
'Things that back office can read and modify'
);
// xl('Things that back office can read and modify')
// Set permissions for Emergency Login.
//
$gacl->add_acl(
array(
'acct' => array('bill', 'disc', 'eob', 'rep', 'rep_a'),
'admin' => array('calendar', 'database', 'forms', 'practice', 'superbill', 'users', 'batchcom', 'language', 'super', 'drugs', 'acl','multipledb','menu','manage_modules'),
'encounters' => array('auth_a', 'auth', 'coding_a', 'coding', 'notes_a', 'notes', 'date_a', 'relaxed'),
'inventory' => array('lots', 'sales', 'purchases', 'transfers', 'adjustments', 'consumption', 'destruction', 'reporting'),
'lists' => array('default','state','country','language','ethrace'),
'patients' => array('appt', 'demo', 'med', 'trans', 'docs', 'notes', 'sign', 'reminder', 'alert', 'disclosure', 'rx', 'amendment', 'lab', 'docs_rm','pat_rep'),
'sensitivities' => array('normal', 'high'),
'nationnotes' => array('nn_configure'),
'patientportal' => array('portal'),
'menus' => array('modle'),
'groups' => array('gadd','gcalendar','glog','gdlog','gm')
),
null,
array($breakglass),
null,
null,
1,
1,
'write',
'Emergency Login user can do anything'
);
// xl('Emergency Login user can do anything')
return true;
}
public function quick_install()
{
// Validation of OpenEMR user settings
// (applicable if not cloning from another database)
if (empty($this->clone_database)) {
if (! $this->login_is_valid()) {
return false;
}
if (! $this->iuser_is_valid()) {
return false;
}
if (! $this->user_password_is_valid()) {
return false;
}
}
// Validation of mysql database password
if (! $this->password_is_valid()) {
return false;
}
if (! $this->no_root_db_access) {
// Connect to mysql via root user
if (! $this->root_database_connection()) {
return false;
}
// Create the dumpfile
// (applicable if cloning from another database)
if (! empty($this->clone_database)) {
if (! $this->create_dumpfiles()) {
return false;
}
}
// Create the site directory
// (applicable if mirroring another local site)
if (! empty($this->source_site_id)) {
if (! $this->create_site_directory()) {
return false;
}
}
$this->disconnect();
// Using @ in below call to hide the php warning in cases where the
// below connection does not work, which is expected behavior.
// Using try in below call to catch the mysqli exception when the
// below connection does not work, which is expected behavior (needed to
// add this try/catch clause for PHP 8.1).
try {
$checkUserDatabaseConnection = @$this->user_database_connection();
} catch (Exception $e) {
$checkUserDatabaseConnection = false;
}
if (! $checkUserDatabaseConnection) {
// Re-connect to mysql via root user
if (! $this->root_database_connection()) {
return false;
}
// Create the mysql database
if (! $this->create_database()) {
return false;
}
// Create the mysql user
if (! $this->create_database_user()) {
return false;
}
// Grant user privileges to the mysql database
if (! $this->grant_privileges()) {
return false;
}
}
$this->disconnect();
}
// Connect to mysql via created user
if (! $this->user_database_connection()) {
return false;
}
// Build the database
if (! $this->load_dumpfiles()) {
return false;
}
// Write the sql configuration file
if (! $this->write_configuration_file()) {
return false;
}
// Load the version information, globals settings,
// initial user, and set up gacl access controls.
// (applicable if not cloning from another database)
if (empty($this->clone_database)) {
if (! $this->add_version_info()) {
return false;
}
if (! $this->insert_globals()) {
return false;
}
if (! $this->add_initial_user()) {
return false;
}
if (! $this->install_gacl()) {
return false;
}
if (! $this->install_additional_users()) {
return false;
}
if (! $this->on_care_coordination()) {
return false;
}
}
return true;
}
private function escapeSql($sql)
{
return mysqli_real_escape_string($this->dbh, $sql);
}
private function escapeDatabaseName($name)
{
if (preg_match('/[^A-Za-z0-9_-]/', $name)) {
error_log("Illegal character(s) in database name");
die("Illegal character(s) in database name");
}
return $name;
}
private function escapeCollateName($name)
{
if (preg_match('/[^A-Za-z0-9_-]/', $name)) {
error_log("Illegal character(s) in collation name");
die("Illegal character(s) in collation name");
}
return $name;
}
private function execute_sql($sql, $showError = true)
{
$this->error_message = '';
if (! $this->dbh) {
$this->user_database_connection();
}
$results = mysqli_query($this->dbh, $sql);
if ($results) {
return $results;
} else {
if ($showError) {
$error_mes = mysqli_error($this->dbh);
$this->error_message = "unable to execute SQL: '$sql' due to: " . $error_mes;
error_log("ERROR IN OPENEMR INSTALL: Unable to execute SQL: " . htmlspecialchars($sql, ENT_QUOTES) . " due to: " . htmlspecialchars($error_mes, ENT_QUOTES));
}
return false;
}
}
private function connect_to_database($server, $user, $password, $port, $dbname = '')
{
$pathToCerts = __DIR__ . "/../../sites/" . $this->site . "/documents/certificates/";
$mysqlSsl = false;
$mysqli = mysqli_init();
if (defined('MYSQLI_CLIENT_SSL') && file_exists($pathToCerts . "mysql-ca")) {
$mysqlSsl = true;
if (
file_exists($pathToCerts . "mysql-key") &&
file_exists($pathToCerts . "mysql-cert")
) {
// with client side certificate/key
mysqli_ssl_set(
$mysqli,
$pathToCerts . "mysql-key",
$pathToCerts . "mysql-cert",
$pathToCerts . "mysql-ca",
null,
null
);
} else {
// without client side certificate/key
mysqli_ssl_set(
$mysqli,
null,
null,
$pathToCerts . "mysql-ca",
null,
null
);
}
}
if ($mysqlSsl) {
$ok = mysqli_real_connect($mysqli, $server, $user, $password, $dbname, (int)$port != 0 ? (int)$port : 3306, '', MYSQLI_CLIENT_SSL);
} else {
$ok = mysqli_real_connect($mysqli, $server, $user, $password, $dbname, (int)$port != 0 ? (int)$port : 3306);
}
if (!$ok) {
$this->error_message = 'unable to connect to sql server because of: (' . mysqli_connect_errno() . ') ' . mysqli_connect_error();
return false;
}
return $mysqli;
}
private function set_sql_strict()
{
// Turn off STRICT SQL
return $this->execute_sql("SET sql_mode = ''");
}
private function set_collation()
{
return $this->execute_sql("SET NAMES 'utf8mb4'");
}
/**
* innitialize $this->dumpfiles, an array of the dumpfiles that will
* be loaded into the database, including the correct translation
* dumpfile.
* The keys are the paths of the dumpfiles, and the values are the titles
* @return array
*/
private function initialize_dumpfile_list()
{
if ($this->clone_database) {
$this->dumpfiles = array( $this->get_backup_filename() => 'clone database' );
} else {
$dumpfiles = array( $this->main_sql => 'Main' );
if (! empty($this->development_translations)) {
// Use the online development translation set
$dumpfiles[ $this->devel_translation_sql ] = "Online Development Language Translations (utf8)";
} else {
// Use the local translation set
$dumpfiles[ $this->translation_sql ] = "Language Translation (utf8)";
}
if ($this->ippf_specific) {
$dumpfiles[ $this->ippf_sql ] = "IPPF Layout";
}
// Load ICD-9 codes if present.
if (file_exists($this->icd9)) {
$dumpfiles[ $this->icd9 ] = "ICD-9";
}
// Load CVX codes if present
if (file_exists($this->cvx)) {
$dumpfiles[ $this->cvx ] = "CVX Immunization Codes";
}
$this->dumpfiles = $dumpfiles;
}
return $this->dumpfiles;
}
/**
*
* Directory copy logic borrowed from a user comment at
* http://www.php.net/manual/en/function.copy.php
* @param string $src name of the directory to copy
* @param string $dst name of the destination to copy to
* @return bool indicating success
*/
private function recurse_copy($src, $dst)
{
$dir = opendir($src);
if (! @mkdir($dst)) {
$this->error_message = "unable to create directory: '$dst'";
return false;
}
while (false !== ($file = readdir($dir))) {
if ($file != '.' && $file != '..') {
if (is_dir($src . '/' . $file)) {
$this->recurse_copy($src . '/' . $file, $dst . '/' . $file);
} else {
copy($src . '/' . $file, $dst . '/' . $file);
}
}
}
closedir($dir);
return true;
}
/**
*
* dump a site's database to a temporary file.
* @param string $source_site_id the site_id of the site to dump
* @return filename of the backup
*/
private function dumpSourceDatabase()
{
global $OE_SITES_BASE;
$source_site_id = $this->source_site_id;
include("$OE_SITES_BASE/$source_site_id/sqlconf.php");
if (empty($config)) {
die("Source site $source_site_id has not been set up!");
}
$backup_file = $this->get_backup_filename();
$cmd = "mysqldump -u " . escapeshellarg($login) .
" -h " . $host .
" -p" . escapeshellarg($pass) .
" --ignore-table=" . escapeshellarg($dbase . ".onsite_activity_view") . " --hex-blob --opt --skip-extended-insert --quote-names -r $backup_file " .
escapeshellarg($dbase);
$tmp1 = [];
$tmp0 = exec($cmd, $tmp1, $tmp2);
if ($tmp2) {
die("Error $tmp2 running \"$cmd\": $tmp0 " . implode(' ', $tmp1));
}
return $backup_file;
}
/**
* @return filename of the source backup database for cloning
*/
private function get_backup_filename()
{
if (stristr(PHP_OS, 'WIN')) {
$backup_file = 'C:/windows/temp/setup_dump.sql';
} else {
$backup_file = '/tmp/setup_dump.sql';
}
return $backup_file;
}
//RP_ADDED
public function getCurrentTheme()
{
$current_theme = $this->execute_sql("SELECT gl_value FROM globals WHERE gl_name LIKE '%css_header%'");
$current_theme = mysqli_fetch_array($current_theme);
return $current_theme[0];
}
public function setCurrentTheme()
{
$current_theme = $this->getCurrentTheme();
// for cloned sites since they're not asked about a new theme
if (!$this->new_theme) {
$this->new_theme = $current_theme;
}
return $this->execute_sql("UPDATE globals SET gl_value='" . $this->escapeSql($this->new_theme) . "' WHERE gl_name LIKE '%css_header%'");
}
public function listThemes()
{
$themes_img_dir = "public/images/stylesheets/";
$arr_themes_img = array_values(array_filter(scandir($themes_img_dir), function ($item) {
return $item[0] !== '.';
}));
return $arr_themes_img;
}
private function extractFileName($theme_file_name = '')
{
$this->theme_file_name = $theme_file_name;
$under_score = strpos($theme_file_name, '_') + 1;
$dot = strpos($theme_file_name, '.');
$theme_value = substr($theme_file_name, $under_score, ($dot - $under_score));
$theme_title = ucwords(str_replace("_", " ", $theme_value));
return array('theme_value' => $theme_value, 'theme_title' => $theme_title);
}
public function displayThemesDivs()
{
$themes_number = count($this->listThemes());
for ($i = 0; $i < $themes_number; $i++) {
$id = $i + 1;
$arr_theme_name = $this->listThemes();
$theme_file_name = $arr_theme_name[$i];
$arr_extracted_file_name = $this->extractFileName($theme_file_name);
$theme_value = $arr_extracted_file_name['theme_value'];
$theme_title = $arr_extracted_file_name['theme_title'];
$img_path = "public/images/stylesheets/";
$theme_file_path = $img_path . $theme_file_name;
$div_start = " <div class='row'>";
$div_end = " </div>";
$img_div = " <div class='col-sm-2 checkboxgroup'>
<label for='my_radio_button_id" . attr($id) . "'><img height='160px' src='" . attr($theme_file_path) . "' width='100%'></label>
<p class='m-0'>" . text($theme_title) . "</p><input id='my_radio_button_id" . attr($id) . "' name='stylesheet' type='radio' value='" . attr($theme_value) . "'>
</div>";
$theme_img_number = $i % 6; //to ensure that last file in array will always generate 5 and will end the row
switch ($theme_img_number) {
case 0: //start row
echo $div_start . "\r\n";
echo $img_div . "\r\n";
break;
case 1:
case 2:
case 3:
case 4:
echo $img_div . "\r\n";
break;
case 5://end row
echo $img_div . "\r\n";
echo $div_end . "\r\n";
echo "<br />" . "\r\n";
break;
default:
echo $div_start . "\r\n";
echo "<h5>Sorry no stylesheet images in directory</h5>";
echo $div_end . "\r\n";
break;
}
}
return;
}
public function displaySelectedThemeDiv()
{
$theme_file_name = $this->getCurrentTheme();
$arr_extracted_file_name = $this->extractFileName($theme_file_name);
$theme_value = $arr_extracted_file_name['theme_value'];
$theme_title = $arr_extracted_file_name['theme_title'];
$img_path = "public/images/stylesheets/";
$theme_file_path = $img_path . "style_" . $theme_value . ".png";
$display_selected_theme_div = <<<DSTD
<div class="row">
<div class="col-sm-12">
<h4>Current Theme:</h4>
<div class="col-sm-4 offset-sm-4 checkboxgroup">
<label for="nothing"><img id="current_theme" src="{$theme_file_path}" width="100%"></label>
<p id="current_theme_title"style="margin:0">{$theme_title}</p>
</div>
</div>
</div>
<br />
DSTD;
echo $display_selected_theme_div . "\r\n";
return;
}
public function displayNewThemeDiv()
{
// cloned sites don't get a chance to set a new theme
if (!$this->new_theme) {
$this->new_theme = $this->getCurrentTheme();
}
$theme_file_name = $this->new_theme;
$arr_extracted_file_name = $this->extractFileName($theme_file_name);
$theme_value = $arr_extracted_file_name['theme_value'];
$theme_title = $arr_extracted_file_name['theme_title'];
$img_path = "public/images/stylesheets/";
$theme_file_path = $img_path . "style_" . $theme_value . ".png";
$display_selected_theme_div = <<<DSTD
<div class="row">
<div class="col-sm-12">
<div class="col-sm-4 offset-sm-4 checkboxgroup">
<label for="nothing"><img id="current_theme" src="{$theme_file_path}" width="75%"></label>
<p id="current_theme_title"style="margin:0">{$theme_title}</p>
</div>
</div>
</div>
<br />
DSTD;
echo $display_selected_theme_div . "\r\n";
return;
}
public function setupHelpModal()
{
$setup_help_modal = <<<SETHLP
<div class="row">
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content oe-modal-content" style="height:700px">
<div class="modal-header clearfix">
<button type="button" class="close" data-dismiss="modal" aria-label=Close>
<span aria-hidden="true" style="color:var(--black); font-size:1.5em;">×</span></button>
</div>
<div class="modal-body" style="height:80%;">
<iframe src="" id="targetiframe" style="height:100%; width:100%; overflow-x: hidden; border:none"
allowtransparency="true"></iframe>
</div>
<div class="modal-footer" style="margin-top:0px;">
<button class="btn btn-link btn-cancel oe-pull-away" data-dismiss="modal" type="button">Close</button>
<!--<button class="btn btn-secondary btn-print oe-pull-away" data-dismiss="modal" id="print-help-href" type="button">Print</button>-->
</div>
</div>
</div>
</div>
</div>
<script>
$(function () {
$('#help-href').click (function(){
document.getElementById('targetiframe').src = "Documentation/help_files/openemr_installation_help.php";
})
});
$(function () {
$('#print-help-href').click (function(){
$("#targetiframe").get(0).contentWindow.print();
})
});
// Jquery draggable
$(".modal-dialog").addClass('drag-action');
$(".modal-content").addClass('resize-action');
</script>
SETHLP;
echo $setup_help_modal . "\r\n";
return;
}
}