* @author Brady Miller * @author Ranganath Pathak * @author Jerry Padgett * @author Stephen Nielson * @copyright Copyright (c) 2010 Rod Roark * @copyright Copyright (c) 2016-2019 Brady Miller * @copyright Copyright (c) 2019 Ranganath Pathak * @copyright Copyright (c) 2020 Jerry Padgett * @copyright Copyright (c) 2022 Discover and Change * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 */ require_once("../globals.php"); require_once("../../custom/code_types.inc.php"); require_once("$srcdir/globals.inc.php"); require_once("$srcdir/user.inc"); use OpenEMR\Common\Acl\AclMain; use OpenEMR\Common\Auth\AuthHash; use OpenEMR\Common\Crypto\CryptoGen; use OpenEMR\Common\Csrf\CsrfUtils; use OpenEMR\Common\Logging\EventAuditLogger; use OpenEMR\Common\Twig\TwigContainer; use OpenEMR\Core\Header; use OpenEMR\OeUI\OemrUI; use OpenEMR\Services\Globals\GlobalSetting; use Ramsey\Uuid\Uuid; // Set up crypto object $cryptoGen = new CryptoGen(); $userMode = (array_key_exists('mode', $_GET) && $_GET['mode'] == 'user'); if (!$userMode) { // Check authorization. $thisauth = AclMain::aclCheckCore('admin', 'super'); if (!$thisauth) { echo (new TwigContainer(null, $GLOBALS['kernel']))->getTwig()->render('core/unauthorized.html.twig', ['pageTitle' => xl("Global Settings")]); exit; } } function checkCreateCDB() { $globalsres = sqlStatement("SELECT gl_name, gl_index, gl_value FROM globals WHERE gl_name IN ('couchdb_host','couchdb_user','couchdb_pass','couchdb_port','couchdb_dbase','document_storage_method')"); $options = array(); while ($globalsrow = sqlFetchArray($globalsres)) { $GLOBALS[$globalsrow['gl_name']] = $globalsrow['gl_value']; } $directory_created = false; if (!empty($GLOBALS['document_storage_method'])) { // /documents/temp/ folder is required for CouchDB if (!is_dir($GLOBALS['OE_SITE_DIR'] . '/documents/temp/')) { $directory_created = mkdir($GLOBALS['OE_SITE_DIR'] . '/documents/temp/', 0777, true); if (!$directory_created) { echo xlt("Failed to create temporary folder. CouchDB will not work."); } } $couch = new CouchDB(); if (!$couch->check_connection()) { echo ""; return false; } if ($GLOBALS['couchdb_host'] || $GLOBALS['couchdb_port'] || $GLOBALS['couchdb_dbase']) { $couch->createDB(); } } return true; } /** * Update background_services table for a specific service following globals save. * @author EMR Direct */ function updateBackgroundService($name, $active, $interval) { //order important here: next_run change dependent on _old_ value of execute_interval so it comes first $sql = 'UPDATE background_services SET active=?, ' . 'next_run = next_run + INTERVAL (? - execute_interval) MINUTE, execute_interval=? WHERE name=?'; return sqlStatement($sql, array($active,$interval,$interval,$name)); } /** * Make any necessary changes to background_services table when globals are saved. * To prevent an unexpected service call during startup or shutdown, follow these rules: * 1. Any "startup" operations should occur _before_ the updateBackgroundService() call. * 2. Any "shutdown" operations should occur _after_ the updateBackgroundService() call. If these operations * would cause errors in a running service call, it would be best to make the shutdown function itself is * a background service that is activated here, does nothing if active=1 or running=1 for the * parent service. Then it deactivates itself by setting active=0 when it is done shutting the parent service * down. This will prevent non-responsiveness to the user by waiting for a service to finish. * 3. If any "previous" values for globals are required for startup/shutdown logic, they need to be * copied to a temp variable before the while($globalsrow...) loop. * @author EMR Direct */ function checkBackgroundServices() { //load up any necessary globals $bgservices = sqlStatement("SELECT gl_name, gl_index, gl_value FROM globals WHERE gl_name IN ('phimail_enable','phimail_interval')"); while ($globalsrow = sqlFetchArray($bgservices)) { $GLOBALS[$globalsrow['gl_name']] = $globalsrow['gl_value']; } //Set up phimail service $phimail_active = empty($GLOBALS['phimail_enable']) ? '0' : '1'; $phimail_interval = max(0, (int) $GLOBALS['phimail_interval']); updateBackgroundService('phimail', $phimail_active, $phimail_interval); // When auto SFTP is enabled in globals, set up background task to run every minute // to check for claims in the 'waiting' status. // See library/billing_sftp_service.php for the entry point to this service. // It is very lightweight if there is no work to do, so running every minute should // be OK to provider users with the best experience. $auto_sftp_x12 = empty($GLOBALS['auto_sftp_claims_to_x12_partner']) ? '0' : '1'; updateBackgroundService('X12_SFTP', $auto_sftp_x12, 1); /** * Setup background services for Weno when it is enabled * this is to sync the prescription logs */ $wenoservices = $GLOBALS['weno_rx_enable'] == 1 ? '1' : '0'; updateBackgroundService('WenoExchange', $wenoservices, 1); } ?> $grparr) { if (in_array($grpname, $USER_SPECIFIC_TABS)) { foreach ($grparr as $fldid => $fldarr) { if (in_array($fldid, $USER_SPECIFIC_GLOBALS)) { list($fldname, $fldtype, $flddef, $flddesc) = $fldarr; $label = "global:" . $fldid; if ($fldtype == "encrypted") { if (empty(trim($_POST["form_$i"]))) { $fldvalue = ''; } else { $fldvalue = $cryptoGen->encryptStandard(trim($_POST["form_$i"])); } } elseif ($fldtype == "encrypted_hash") { $tmpValue = trim($_POST["form_$i"]); if (empty($tmpValue)) { $fldvalue = ''; } else { if (!AuthHash::hashValid($tmpValue)) { // a new value has been inputted, so create the hash that will then be stored $tmpValue = (new AuthHash())->passwordHash($tmpValue); } $fldvalue = $cryptoGen->encryptStandard($tmpValue); } } else { $fldvalue = trim($_POST["form_$i"] ?? ''); } setUserSetting($label, $fldvalue, $_SESSION['authUserID'], false); if ($_POST["toggle_$i"] ?? '' == "YES") { removeUserSetting($label); } ++$i; } } } } echo ""; } ?> $grparr) { foreach ($grparr as $fldid => $fldarr) { list($fldname, $fldtype, $flddef, $flddesc) = $fldarr; /* Multiple choice fields - do not compare , overwrite */ if (!is_array($fldtype) && substr($fldtype, 0, 2) == 'm_') { if (isset($_POST["form_$i"])) { $fldindex = 0; sqlStatement("DELETE FROM globals WHERE gl_name = ?", array( $fldid )); foreach ($_POST["form_$i"] as $fldvalue) { $fldvalue = trim($fldvalue); sqlStatement('INSERT INTO `globals` ( gl_name, gl_index, gl_value ) VALUES ( ?,?,?)', array( $fldid, $fldindex, $fldvalue )); ++$fldindex; } } } else { /* check value of single field. Don't update if the database holds the same value */ if (isset($_POST["form_$i"])) { $fldvalue = trim($_POST["form_$i"]); } else { $fldvalue = ""; } if ($fldtype == 'encrypted') { if (empty(trim($fldvalue))) { $fldvalue = ''; } else { $fldvalue = $cryptoGen->encryptStandard($fldvalue); } } elseif ($fldtype == 'encrypted_hash') { $tmpValue = trim($fldvalue); if (empty($tmpValue)) { $fldvalue = ''; } else { if (!AuthHash::hashValid($tmpValue)) { // a new value has been inputted, so create the hash that will then be stored $tmpValue = (new AuthHash())->passwordHash($tmpValue); } $fldvalue = $cryptoGen->encryptStandard($tmpValue); } } // We rely on the fact that set of keys in globals.inc === set of keys in `globals` table! if ( !isset($old_globals[$fldid]) // if the key not found in database - update database || ( isset($old_globals[$fldid]) && $old_globals[ $fldid ]['gl_value'] !== $fldvalue ) // if the value in database is different ) { // special treatment for some vars switch ($fldid) { case 'first_day_week': // update PostCalendar config as well sqlStatement("UPDATE openemr_module_vars SET pn_value = ? WHERE pn_name = 'pcFirstDayOfWeek'", array($fldvalue)); break; } // Replace old values sqlStatement('DELETE FROM `globals` WHERE gl_name = ?', array( $fldid )); sqlStatement('INSERT INTO `globals` ( gl_name, gl_index, gl_value ) VALUES ( ?, ?, ? )', array( $fldid, 0, $fldvalue )); } else { //error_log("No need to update $fldid"); } } ++$i; } } // end of transaction sqlStatementNoLog('COMMIT'); sqlStatementNoLog('SET autocommit=1'); checkCreateCDB(); checkBackgroundServices(); // July 1, 2014: Ensoftek: For Auditable events and tamper-resistance (MU2) // If Audit Logging status has changed, log it. $auditLogStatusNew = sqlQuery("SELECT `gl_value` FROM `globals` WHERE `gl_name` = 'enable_auditlog'"); $auditLogStatusFieldNew = $auditLogStatusNew['gl_value']; if ($auditLogStatusFieldOld != $auditLogStatusFieldNew) { EventAuditLogger::instance()->auditSQLAuditTamper('enable_auditlog', $auditLogStatusFieldNew); } $forceBreakglassLogStatusNew = sqlQuery("SELECT `gl_value` FROM `globals` WHERE `gl_name` = 'gbl_force_log_breakglass'"); $forceBreakglassLogStatusFieldNew = $forceBreakglassLogStatusNew['gl_value']; if ($forceBreakglassLogStatusFieldOld != $forceBreakglassLogStatusFieldNew) { EventAuditLogger::instance()->auditSQLAuditTamper('gbl_force_log_breakglass', $forceBreakglassLogStatusFieldNew); } echo ""; } $title = ($userMode) ? xlt("User Settings") : xlt("Global Settings"); ?> <?php echo $title; ?> $heading_title, 'include_patient_name' => false,// use only in appropriate pages 'expandable' => true, 'expandable_files' => array("edit_globals_xpd"),//all file names need suffix _xpd 'action' => "",//conceal, reveal, search, reset, link or back 'action_title' => "", 'action_href' => "",//only for actions - reset, link or back 'show_help_icon' => false, 'help_file_name' => "" ); $oemr_ui = new OemrUI($arrOeUiSettings); ?> >
pageHeading() . "\r\n"; ?>
' />

    $grparr) { if (!$userMode || in_array($grpname, $USER_SPECIFIC_TABS)) { echo " " . xlt($grpname) . "\n"; ++$i; } } ?>
$grparr) { if (!$userMode || in_array($grpname, $USER_SPECIFIC_TABS)) { echo "
\n"; echo "
"; $addendum = $grpname == 'Appearance' ? ' (*' . xl("need to logout/login after changing these settings") . ')' : ''; echo "
" . xlt($grpname) . "  
" . text($addendum) . "
"; echo "
"; if ($userMode) { echo "
"; echo "
 
"; echo "
" . xlt('User Specific Setting') . "
"; echo "
" . xlt('Default Setting') . "
"; echo "
" . xlt('Default') . "
"; echo "
"; } foreach ($grparr as $fldid => $fldarr) { if (!$userMode || in_array($fldid, $USER_SPECIFIC_GLOBALS)) { list($fldname, $fldtype, $flddef, $flddesc) = $fldarr; // if the setting defines field options for our global setting we grab it, otherwise we default empty $fldoptions = $fldarr[4] ?? []; // mdsupport - Check for matches $srch_cl = ''; $highlight_search = false; if (!empty($_POST['srch_desc']) && (stristr(($fldname . $flddesc), $_POST['srch_desc']) !== false)) { $srch_cl = ' srch'; $srch_item++; $highlight_search = true; } // Most parameters will have a single value, but some will be arrays. // Here we cater to both possibilities. $glres = sqlStatement("SELECT gl_index, gl_value FROM globals WHERE " . "gl_name = ? ORDER BY gl_index", array($fldid)); $glarr = array(); while ($glrow = sqlFetchArray($glres)) { $glarr[] = $glrow; } // $fldvalue is meaningful only for the single-value cases. $fldvalue = count($glarr) ? $glarr[0]['gl_value'] : $flddef; // Collect user specific setting if mode set to user $userSetting = ""; $settingDefault = "checked='checked'"; if ($userMode) { $userSettingArray = sqlQuery("SELECT * FROM user_settings WHERE setting_user=? AND setting_label=?", array($_SESSION['authUserID'],"global:" . $fldid)); $userSetting = $userSettingArray['setting_value'] ?? ''; $globalValue = $fldvalue; if (!empty($userSettingArray)) { $fldvalue = $userSetting; $settingDefault = ""; } } if ($userMode) { echo "
" . ($highlight_search ? '' : '') . text($fldname) . ($highlight_search ? '' : '') . "
\n"; } else { echo "
" . ($highlight_search ? '' : '') . text($fldname) . ($highlight_search ? '' : '') . "
\n"; } if (is_array($fldtype)) { echo " \n"; } elseif ($fldtype == GlobalSetting::DATA_TYPE_BOOL) { if ($userMode) { if ($globalValue == 1) { $globalTitle = xlt('Checked'); } else { $globalTitle = xlt('Not Checked'); } } echo " \n"; } elseif ($fldtype == GlobalSetting::DATA_TYPE_NUMBER) { if ($userMode) { $globalTitle = $globalValue; } echo " \n"; } elseif ($fldtype == GlobalSetting::DATA_TYPE_TEXT) { if ($userMode) { $globalTitle = $globalValue; } echo " \n"; } elseif ($fldtype == GlobalSetting::DATA_TYPE_DEFAULT_RANDOM_UUID) { if ($userMode) { $globalTitle = $globalValue; } if (empty($fldvalue)) { // if empty, then create a random uuid $uuid4 = Uuid::uuid4(); $fldvalue = $uuid4->toString(); } echo " \n"; } elseif (($fldtype == GlobalSetting::DATA_TYPE_ENCRYPTED) || ($fldtype == GlobalSetting::DATA_TYPE_ENCRYPTED_HASH)) { if (empty($fldvalue)) { // empty value $fldvalueDecrypted = ''; } elseif ($cryptoGen->cryptCheckStandard($fldvalue)) { // normal behavior when not empty $fldvalueDecrypted = $cryptoGen->decryptStandard($fldvalue); } else { // this is used when value has not yet been encrypted (only happens once when upgrading) $fldvalueDecrypted = $fldvalue; } echo " \n"; if ($userMode) { if (empty($globalValue)) { // empty value $globalTitle = ''; } elseif ($cryptoGen->cryptCheckStandard($globalValue)) { // normal behavior when not empty $globalTitle = $cryptoGen->decryptStandard($globalValue); } else { // this is used when value has not yet been encrypted (only happens once when upgrading) $globalTitle = $globalValue; } } $fldvalueDecrypted = ''; } elseif ($fldtype == GlobalSetting::DATA_TYPE_PASS) { if ($userMode) { $globalTitle = $globalValue; } echo " \n"; } elseif ($fldtype == GlobalSetting::DATA_TYPE_LANGUAGE) { $res = sqlStatement("SELECT * FROM lang_languages ORDER BY lang_description"); echo " \n"; } elseif ($fldtype == GlobalSetting::DATA_TYPE_CODE_TYPES) { global $code_types; echo " \n"; } elseif ($fldtype == GlobalSetting::DATA_TYPE_MULTI_LANGUAGE_SELECT) { $res = sqlStatement("SELECT * FROM lang_languages ORDER BY lang_description"); echo " \n"; } elseif ($fldtype == GlobalSetting::DATA_TYPE_COLOR_CODE) { if ($userMode) { $globalTitle = $globalValue; } echo " " . "\n"; } elseif ($fldtype == GlobalSetting::DATA_TYPE_DEFAULT_VISIT_CATEGORY) { $sql = "SELECT pc_catid, pc_catname, pc_cattype FROM openemr_postcalendar_categories WHERE pc_active = 1 ORDER BY pc_seq"; $result = sqlStatement($sql); echo ""; } elseif ($fldtype == GlobalSetting::DATA_TYPE_CSS || $fldtype == GlobalSetting::DATA_TYPE_TABS_CSS) { if ($userMode) { $globalTitle = $globalValue; } $themedir = "$webserver_root/public/themes"; $dh = opendir($themedir); if ($dh) { // Collect styles $styleArray = array(); while (false !== ($tfname = readdir($dh))) { // Only show files that contain tabs_style_ or style_ as options if ($fldtype == 'tabs_css') { $patternStyle = 'tabs_style_'; } else { // $fldtype == 'css' $patternStyle = 'style_'; } if ( $tfname == 'style_blue.css' || $tfname == 'style_pdf.css' || !preg_match("/^" . $patternStyle . ".*\.css$/", $tfname) ) { continue; } if ($fldtype == GlobalSetting::DATA_TYPE_TABS_CSS) { // Drop the "tabs_style_" part and any replace any underscores with spaces $styleDisplayName = str_replace("_", " ", substr($tfname, 11)); } else { // $fldtype == 'css' // Drop the "style_" part and any replace any underscores with spaces $styleDisplayName = str_replace("_", " ", substr($tfname, 6)); } // Strip the ".css" and uppercase the first character $styleDisplayName = ucfirst(str_replace(".css", "", $styleDisplayName)); $styleArray[$tfname] = $styleDisplayName; } // Alphabetize styles asort($styleArray); // Generate style selector echo "\n"; } closedir($dh); } elseif ($fldtype == GlobalSetting::DATA_TYPE_HOUR) { if ($userMode) { $globalTitle = $globalValue; } echo " \n"; } else if ($fldtype == GlobalSetting::DATA_TYPE_MULTI_SORTED_LIST_SELECTOR) { include 'templates/field_multi_sorted_list_selector.php'; } if ($userMode) { echo "
\n"; echo "
" . text($globalTitle) . "
\n"; echo "
\n"; if (($fldtype == 'encrypted') || ($fldtype == 'encrypted_hash')) { echo "\n"; } else { echo "\n"; } echo "
\n"; } else { echo "
\n"; } ++$i; } } echo "
" . "
"; echo "
" . xlt($grpname) . "  
"; echo "
\n"; } } ?>
oeBelowContainerDiv();?> alert(" . js_escape($post_srch_desc . " - " . xl('search term was not found, please try another search')) . ");"; } ?>