Fix: delete entry in immunization (#7346)
[openemr.git] / interface / super / edit_globals.php
blob074b1508d2ad95a654e64d1ee1088c7be1fc3033
1 <?php
3 /**
4 * Script for the globals editor.
6 * @package OpenEMR
7 * @link http://www.open-emr.org
8 * @author Rod Roark <rod@sunsetsystems.com>
9 * @author Brady Miller <brady.g.miller@gmail.com>
10 * @author Ranganath Pathak <pathak@scrs1.org>
11 * @author Jerry Padgett <sjpadgett@gmail.com>
12 * @author Stephen Nielson <snielson@discoverandchange.com>
13 * @copyright Copyright (c) 2010 Rod Roark <rod@sunsetsystems.com>
14 * @copyright Copyright (c) 2016-2019 Brady Miller <brady.g.miller@gmail.com>
15 * @copyright Copyright (c) 2019 Ranganath Pathak <pathak@scrs1.org>
16 * @copyright Copyright (c) 2020-2024 Jerry Padgett <sjpadgett@gmail.com>
17 * @copyright Copyright (c) 2022 Discover and Change <snielson@discoverandchange.com>
18 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
21 require_once("../globals.php");
22 require_once("../../custom/code_types.inc.php");
23 require_once("$srcdir/globals.inc.php");
24 require_once("$srcdir/user.inc.php");
26 use OpenEMR\Common\Acl\AclMain;
27 use OpenEMR\Common\Auth\AuthHash;
28 use OpenEMR\Common\Crypto\CryptoGen;
29 use OpenEMR\Common\Csrf\CsrfUtils;
30 use OpenEMR\Common\Logging\EventAuditLogger;
31 use OpenEMR\Common\Twig\TwigContainer;
32 use OpenEMR\Core\Header;
33 use OpenEMR\FHIR\Config\ServerConfig;
34 use OpenEMR\OeUI\OemrUI;
35 use OpenEMR\Services\Globals\GlobalSetting;
36 use Ramsey\Uuid\Uuid;
39 // Set up crypto object
40 $cryptoGen = new CryptoGen();
42 $userMode = (array_key_exists('mode', $_GET) && $_GET['mode'] == 'user');
44 if (!$userMode) {
45 // Check authorization.
46 $thisauth = AclMain::aclCheckCore('admin', 'super');
47 if (!$thisauth) {
48 echo (new TwigContainer(null, $GLOBALS['kernel']))->getTwig()->render('core/unauthorized.html.twig', ['pageTitle' => xl("Configuration")]);
49 exit;
53 function checkCreateCDB()
55 $globalsres = sqlStatement("SELECT gl_name, gl_index, gl_value FROM globals WHERE gl_name IN
56 ('couchdb_host','couchdb_user','couchdb_pass','couchdb_port','couchdb_dbase','document_storage_method')");
57 $options = array();
58 while ($globalsrow = sqlFetchArray($globalsres)) {
59 $GLOBALS[$globalsrow['gl_name']] = $globalsrow['gl_value'];
62 $directory_created = false;
63 if (!empty($GLOBALS['document_storage_method'])) {
64 // /documents/temp/ folder is required for CouchDB
65 if (!is_dir($GLOBALS['OE_SITE_DIR'] . '/documents/temp/')) {
66 $directory_created = mkdir($GLOBALS['OE_SITE_DIR'] . '/documents/temp/', 0777, true);
67 if (!$directory_created) {
68 echo xlt("Failed to create temporary folder. CouchDB will not work.");
72 $couch = new CouchDB();
73 if (!$couch->check_connection()) {
74 echo "<script>alert(" . xlj("CouchDB Connection Failed.") . ");</script>";
75 return false;
78 if ($GLOBALS['couchdb_host'] || $GLOBALS['couchdb_port'] || $GLOBALS['couchdb_dbase']) {
79 $couch->createDB();
83 return true;
86 /**
87 * Update background_services table for a specific service following globals save.
88 * @author EMR Direct
90 function updateBackgroundService($name, $active, $interval)
92 //order important here: next_run change dependent on _old_ value of execute_interval so it comes first
93 $sql = 'UPDATE background_services SET active=?, '
94 . 'next_run = next_run + INTERVAL (? - execute_interval) MINUTE, execute_interval=? WHERE name=?';
95 return sqlStatement($sql, array($active,$interval,$interval,$name));
98 /**
99 * Make any necessary changes to background_services table when globals are saved.
100 * To prevent an unexpected service call during startup or shutdown, follow these rules:
101 * 1. Any "startup" operations should occur _before_ the updateBackgroundService() call.
102 * 2. Any "shutdown" operations should occur _after_ the updateBackgroundService() call. If these operations
103 * would cause errors in a running service call, it would be best to make the shutdown function itself is
104 * a background service that is activated here, does nothing if active=1 or running=1 for the
105 * parent service. Then it deactivates itself by setting active=0 when it is done shutting the parent service
106 * down. This will prevent non-responsiveness to the user by waiting for a service to finish.
107 * 3. If any "previous" values for globals are required for startup/shutdown logic, they need to be
108 * copied to a temp variable before the while($globalsrow...) loop.
109 * @author EMR Direct
111 function checkBackgroundServices()
113 //load up any necessary globals
114 $bgservices = sqlStatement(
115 "SELECT gl_name, gl_index, gl_value FROM globals WHERE gl_name IN
117 'phimail_enable',
118 'phimail_interval',
119 'auto_sftp_claims_to_x12_partner',
120 'weno_rx_enable'
123 while ($globalsrow = sqlFetchArray($bgservices)) {
124 $GLOBALS[$globalsrow['gl_name']] = $globalsrow['gl_value'];
127 //Set up phimail service
128 $phimail_active = empty($GLOBALS['phimail_enable']) ? '0' : '1';
129 $phimail_interval = max(0, (int) $GLOBALS['phimail_interval']);
130 updateBackgroundService('phimail', $phimail_active, $phimail_interval);
132 // When auto SFTP is enabled in globals, set up background task to run every minute
133 // to check for claims in the 'waiting' status.
134 // See library/billing_sftp_service.php for the entry point to this service.
135 // It is very lightweight if there is no work to do, so running every minute should
136 // be OK to provider users with the best experience.
137 $auto_sftp_x12 = empty($GLOBALS['auto_sftp_claims_to_x12_partner']) ? '0' : '1';
138 updateBackgroundService('X12_SFTP', $auto_sftp_x12, 1);
141 * Setup background services for Weno when it is enabled
142 * this is to sync the prescription logs
144 $wenoservices = ($GLOBALS['weno_rx_enable'] ?? '') == 1 ? '1' : '0';
145 updateBackgroundService('WenoExchange', $wenoservices, 60);
146 updateBackgroundService('WenoExchangePharmacies', $wenoservices, 1440);
149 <!DOCTYPE html>
150 <html>
151 <head>
152 <?php
153 // If we are saving user_specific globals.
155 if (array_key_exists('form_save', $_POST) && $_POST['form_save'] && $userMode) {
156 //verify csrf
157 if (!CsrfUtils::verifyCsrfToken($_POST["csrf_token_form"])) {
158 CsrfUtils::csrfNotVerified();
161 $i = 0;
162 foreach ($GLOBALS_METADATA as $grpname => $grparr) {
163 if (in_array($grpname, $USER_SPECIFIC_TABS)) {
164 foreach ($grparr as $fldid => $fldarr) {
165 if (in_array($fldid, $USER_SPECIFIC_GLOBALS)) {
166 list($fldname, $fldtype, $flddef, $flddesc) = $fldarr;
167 $label = "global:" . $fldid;
168 if ($fldtype == "encrypted") {
169 if (empty(trim($_POST["form_$i"]))) {
170 $fldvalue = '';
171 } else {
172 $fldvalue = $cryptoGen->encryptStandard(trim($_POST["form_$i"]));
174 } elseif ($fldtype == "encrypted_hash") {
175 $tmpValue = trim($_POST["form_$i"]);
176 if (empty($tmpValue)) {
177 $fldvalue = '';
178 } else {
179 if (!AuthHash::hashValid($tmpValue)) {
180 // a new value has been inputted, so create the hash that will then be stored
181 $tmpValue = (new AuthHash())->passwordHash($tmpValue);
183 $fldvalue = $cryptoGen->encryptStandard($tmpValue);
185 } else {
186 $fldvalue = trim($_POST["form_$i"] ?? '');
188 setUserSetting($label, $fldvalue, $_SESSION['authUserID'], false);
189 if ($_POST["toggle_$i"] ?? '' == "YES") {
190 removeUserSetting($label);
193 ++$i;
199 echo "<script>";
200 echo "if (parent.left_nav.location) {";
201 echo " parent.left_nav.location.reload();";
202 echo " parent.Title.location.reload();";
203 echo " if(self.name=='RTop'){";
204 echo " parent.RBot.location.reload();";
205 echo " }else{";
206 echo " parent.RTop.location.reload();";
207 echo " }";
208 echo "}";
209 echo "self.location.href='edit_globals.php?mode=user&unique=yes';";
210 echo "</script>";
214 <?php
215 // If we are saving main globals.
217 if (array_key_exists('form_save', $_POST) && $_POST['form_save'] && !$userMode) {
218 //verify csrf
219 if (!CsrfUtils::verifyCsrfToken($_POST["csrf_token_form"])) {
220 CsrfUtils::csrfNotVerified();
223 // Aug 22, 2014: Ensoftek: For Auditable events and tamper-resistance (MU2)
224 // Check the current status of Audit Logging
225 $auditLogStatusFieldOld = $GLOBALS['enable_auditlog'];
226 $forceBreakglassLogStatusFieldOld = $GLOBALS['gbl_force_log_breakglass'];
229 * Compare form values with old database values.
230 * Only save if values differ. Improves speed.
233 // Get all the globals from DB
234 $old_globals = sqlGetAssoc('SELECT gl_name, gl_index, gl_value FROM `globals` ORDER BY gl_name, gl_index', false, true);
235 // start transaction
236 sqlStatementNoLog('SET autocommit=0');
237 sqlStatementNoLog('START TRANSACTION');
238 $i = 0;
239 foreach ($GLOBALS_METADATA as $grpname => $grparr) {
240 foreach ($grparr as $fldid => $fldarr) {
241 list($fldname, $fldtype, $flddef, $flddesc) = $fldarr;
242 /* Multiple choice fields - do not compare , overwrite */
243 if (!is_array($fldtype) && substr($fldtype, 0, 2) == 'm_') {
244 if (isset($_POST["form_$i"])) {
245 $fldindex = 0;
247 sqlStatement("DELETE FROM globals WHERE gl_name = ?", array( $fldid ));
249 foreach ($_POST["form_$i"] as $fldvalue) {
250 $fldvalue = trim($fldvalue);
251 sqlStatement('INSERT INTO `globals` ( gl_name, gl_index, gl_value ) VALUES ( ?,?,?)', array( $fldid, $fldindex, $fldvalue ));
252 ++$fldindex;
255 } else {
256 /* check value of single field. Don't update if the database holds the same value */
257 if (isset($_POST["form_$i"])) {
258 $fldvalue = trim($_POST["form_$i"]);
259 } else {
260 $fldvalue = "";
263 if ($fldtype == 'encrypted') {
264 if (empty(trim($fldvalue))) {
265 $fldvalue = '';
266 } else {
267 $fldvalue = $cryptoGen->encryptStandard($fldvalue);
269 } elseif ($fldtype == 'encrypted_hash') {
270 $tmpValue = trim($fldvalue);
271 if (empty($tmpValue)) {
272 $fldvalue = '';
273 } else {
274 if (!AuthHash::hashValid($tmpValue)) {
275 // a new value has been inputted, so create the hash that will then be stored
276 $tmpValue = (new AuthHash())->passwordHash($tmpValue);
278 $fldvalue = $cryptoGen->encryptStandard($tmpValue);
282 // We rely on the fact that set of keys in globals.inc.php === set of keys in `globals` table!
283 if (
284 !isset($old_globals[$fldid]) // if the key not found in database - update database
286 ( isset($old_globals[$fldid]) && $old_globals[ $fldid ]['gl_value'] !== $fldvalue ) // if the value in database is different
288 // special treatment for some vars
289 switch ($fldid) {
290 case 'first_day_week':
291 // update PostCalendar config as well
292 sqlStatement("UPDATE openemr_module_vars SET pn_value = ? WHERE pn_name = 'pcFirstDayOfWeek'", array($fldvalue));
293 break;
296 // Replace old values
297 sqlStatement('DELETE FROM `globals` WHERE gl_name = ?', array( $fldid ));
298 sqlStatement('INSERT INTO `globals` ( gl_name, gl_index, gl_value ) VALUES ( ?, ?, ? )', array( $fldid, 0, $fldvalue ));
299 } else {
300 //error_log("No need to update $fldid");
304 ++$i;
307 // end of transaction
308 sqlStatementNoLog('COMMIT');
309 sqlStatementNoLog('SET autocommit=1');
311 checkCreateCDB();
312 checkBackgroundServices();
314 // July 1, 2014: Ensoftek: For Auditable events and tamper-resistance (MU2)
315 // If Audit Logging status has changed, log it.
316 $auditLogStatusNew = sqlQuery("SELECT `gl_value` FROM `globals` WHERE `gl_name` = 'enable_auditlog'");
317 $auditLogStatusFieldNew = $auditLogStatusNew['gl_value'];
318 if ($auditLogStatusFieldOld != $auditLogStatusFieldNew) {
319 EventAuditLogger::instance()->auditSQLAuditTamper('enable_auditlog', $auditLogStatusFieldNew);
321 $forceBreakglassLogStatusNew = sqlQuery("SELECT `gl_value` FROM `globals` WHERE `gl_name` = 'gbl_force_log_breakglass'");
322 $forceBreakglassLogStatusFieldNew = $forceBreakglassLogStatusNew['gl_value'];
323 if ($forceBreakglassLogStatusFieldOld != $forceBreakglassLogStatusFieldNew) {
324 EventAuditLogger::instance()->auditSQLAuditTamper('gbl_force_log_breakglass', $forceBreakglassLogStatusFieldNew);
327 echo "<script>";
328 echo "if (parent.left_nav.location) {";
329 echo " parent.left_nav.location.reload();";
330 echo " parent.Title.location.reload();";
331 echo " if(self.name=='RTop'){";
332 echo " parent.RBot.location.reload();";
333 echo " }else{";
334 echo " parent.RTop.location.reload();";
335 echo " }";
336 echo "}";
337 echo "self.location.href='edit_globals.php?unique=yes';";
338 echo "</script>";
341 $title = ($userMode) ? xlt("User Settings") : xlt("Configuration");
343 <title><?php echo $title; ?></title>
344 <?php Header::setupHeader(['common','jscolor']); ?>
346 <style>
347 #oe-nav-ul.tabNav {
348 display: flex;
349 flex-flow: column;
350 max-width: 15%;
352 @media (max-width: 576px) {
353 #oe-nav-ul.tabNav {
354 max-width: inherit;
355 width: 100%;
357 #globals-div .tabContainer {
358 width: 100%;
361 </style>
362 <?php
363 $heading_title = ($userMode) ? xl("Edit User Settings") : xl("Edit Configuration");
365 $arrOeUiSettings = array(
366 'heading_title' => $heading_title,
367 'include_patient_name' => false,// use only in appropriate pages
368 'expandable' => true,
369 'expandable_files' => array("edit_globals_xpd"),//all file names need suffix _xpd
370 'action' => "",//conceal, reveal, search, reset, link or back
371 'action_title' => "",
372 'action_href' => "",//only for actions - reset, link or back
373 'show_help_icon' => false,
374 'help_file_name' => ""
376 $oemr_ui = new OemrUI($arrOeUiSettings);
377 $serverConfig = new ServerConfig();
378 $apiUrl = $serverConfig->getInternalBaseApiUrl();
380 <script src="edit_globals.js" type="text/javascript"></script>
381 <script>
382 window.oeUI.api.setApiUrlAndCsrfToken(<?php echo js_escape($apiUrl); ?>, <?php echo js_escape(CsrfUtils::collectCsrfToken('api')); ?>);
383 </script>
384 </head>
386 <body <?php if ($userMode) {
387 echo 'style="min-width: 700px;"';
388 } ?>>
390 <div id="container_div" class="<?php echo $oemr_ui->oeContainer();?> mt-2">
391 <div class="row">
392 <div class="col-sm-12 px-0 my-2">
393 <?php echo $oemr_ui->pageHeading() . "\r\n"; ?>
394 </div>
395 </div>
396 <div class="row">
397 <div class="col-sm-12 px-0">
398 <?php if ($userMode) { ?>
399 <form method='post' name='theform' id='theform' class='form-horizontal' action='edit_globals.php?mode=user' onsubmit='return top.restoreSession()'>
400 <?php } else { ?>
401 <form method='post' name='theform' id='theform' class='form-horizontal' action='edit_globals.php' onsubmit='return top.restoreSession()'>
402 <?php } ?>
403 <input type="hidden" name="csrf_token_form" value="<?php echo attr(CsrfUtils::collectCsrfToken()); ?>" />
404 <div class="clearfix">
405 <div class="btn-group oe-margin-b-10">
406 <button type='submit' class='btn btn-primary btn-save oe-pull-toward' name='form_save' value='<?php echo xla('Save'); ?>'><?php echo xlt('Save'); ?></button>
407 </div>
408 <div class="input-group col-sm-4 oe-pull-away p-0">
409 <?php // mdsupport - Optional server based searching mechanism for large number of fields on this screen.
410 if (!$userMode) {
411 $placeholder = xla('Search configuration');
412 } else {
413 $placeholder = xla('Search user settings');
416 <input name='srch_desc' id='srch_desc' class='form-control' type='text' placeholder='<?php echo $placeholder; ?>' value='<?php echo (!empty($_POST['srch_desc']) ? attr($_POST['srch_desc']) : '') ?>' />
417 <span class="input-group-append">
418 <button class="btn btn-secondary btn-search" type='submit' id='globals_form_search' name='form_search'><?php echo xlt('Search'); ?></button>
419 </span>
420 </div><!-- /input-group -->
421 </div>
422 <br />
423 <div id="globals-div">
424 <ul class="tabNav tabWidthWide sticky-top" id="oe-nav-ul">
425 <?php
426 $i = 0;
427 foreach ($GLOBALS_METADATA as $grpname => $grparr) {
428 if (!$userMode || in_array($grpname, $USER_SPECIFIC_TABS)) {
429 echo " <li" . ($i ? "" : " class='current'") .
430 "><a href='#'>" .
431 xlt($grpname) . "</a></li>\n";
432 ++$i;
436 </ul>
437 <div class="tabContainer">
438 <?php
439 $i = 0;
440 $srch_item = 0;
441 foreach ($GLOBALS_METADATA as $grpname => $grparr) {
442 if (!$userMode || in_array($grpname, $USER_SPECIFIC_TABS)) {
443 echo " <div class='tab w-100 h-auto" . ($i ? "" : " current") . "' style='font-size: 0.9rem'>\n";
445 echo "<div class=''>";
446 $addendum = $grpname == 'Appearance' ? ' (*' . xl("need to logout/login after changing these settings") . ')' : '';
447 echo "<div class='col-sm-12 oe-global-tab-heading'><div class='oe-pull-toward' style='font-size: 1.4rem'>" . xlt($grpname) . " &nbsp;</div><div style='margin-top: 5px'>" . text($addendum) . "</div></div>";
448 echo "<div class='clearfix'></div>";
449 if ($userMode) {
450 echo "<div class='row'>";
451 echo "<div class='col-sm-4'>&nbsp</div>";
452 echo "<div class='col-sm-4 font-weight-bold'>" . xlt('User Specific Setting') . "</div>";
453 echo "<div class='col-sm-2 font-weight-bold'>" . xlt('Default Setting') . "</div>";
454 echo "<div class='col-sm-2 font-weight-bold'>" . xlt('Default') . "</div>";
455 echo "</div>";
458 foreach ($grparr as $fldid => $fldarr) {
459 if (!$userMode || in_array($fldid, $USER_SPECIFIC_GLOBALS)) {
460 list($fldname, $fldtype, $flddef, $flddesc) = $fldarr;
462 // if the setting defines field options for our global setting we grab it, otherwise we default empty
463 $fldoptions = $fldarr[4] ?? [];
465 // mdsupport - Check for matches
466 $srch_cl = '';
467 $highlight_search = false;
469 if (!empty($_POST['srch_desc']) && (stristr(($fldname . $flddesc), $_POST['srch_desc']) !== false)) {
470 $srch_cl = ' srch';
471 $srch_item++;
472 $highlight_search = true;
475 // Most parameters will have a single value, but some will be arrays.
476 // Here we cater to both possibilities.
477 $glres = sqlStatement("SELECT gl_index, gl_value FROM globals WHERE " .
478 "gl_name = ? ORDER BY gl_index", array($fldid));
479 $glarr = array();
480 while ($glrow = sqlFetchArray($glres)) {
481 $glarr[] = $glrow;
484 // $fldvalue is meaningful only for the single-value cases.
485 $fldvalue = count($glarr) ? $glarr[0]['gl_value'] : $flddef;
487 // Collect user specific setting if mode set to user
488 $userSetting = "";
489 $settingDefault = "checked='checked'";
490 if ($userMode) {
491 $userSettingArray = sqlQuery("SELECT * FROM user_settings WHERE setting_user=? AND setting_label=?", array($_SESSION['authUserID'],"global:" . $fldid));
492 $userSetting = $userSettingArray['setting_value'] ?? '';
493 $globalValue = $fldvalue;
494 if (!empty($userSettingArray)) {
495 $fldvalue = $userSetting;
496 $settingDefault = "";
499 if ($fldtype == GlobalSetting::DATA_TYPE_HTML_DISPLAY_SECTION) {
500 // if the field is an html display box we want to take over the entire real estate so we will continue from here.
501 include_once 'templates/field_html_display_section.php';
502 ++$i; // make sure we advance the iterator here...
503 continue;
506 if ($userMode) {
507 echo " <div class='row form-group" . $srch_cl . "'><div class='col-sm-4'>" . ($highlight_search ? '<mark>' : '') . text($fldname) . ($highlight_search ? '</mark>' : '') . "</div><div class='col-sm-4 oe-input' title='" . attr($flddesc) . "'>\n";
508 } else {
509 echo " <div class='row form-group" . $srch_cl . "'><div class='col-sm-6'>" . ($highlight_search ? '<mark>' : '') . text($fldname) . ($highlight_search ? '</mark>' : '') . "</div><div class='col-sm-6 oe-input' title='" . attr($flddesc) . "'>\n";
512 if (is_array($fldtype)) {
513 echo " <select class='form-control' name='form_$i' id='form_$i'>\n";
514 foreach ($fldtype as $key => $value) {
515 if ($userMode) {
516 if ($globalValue == $key) {
517 $globalTitle = $value;
521 echo " <option value='" . attr($key) . "'";
523 //Casting value to string so the comparison will be always the same type and the only thing that will check is the value
524 //Tried to use === but it will fail in already existing variables
525 if ((string)$key == (string)$fldvalue) {
526 echo " selected";
529 echo ">";
530 echo text($value);
531 echo "</option>\n";
533 echo " </select>\n";
534 } elseif ($fldtype == GlobalSetting::DATA_TYPE_BOOL) {
535 if ($userMode) {
536 if ($globalValue == 1) {
537 $globalTitle = xlt('Checked');
538 } else {
539 $globalTitle = xlt('Not Checked');
542 echo " <input type='checkbox' class='checkbox' name='form_$i' id='form_$i' value='1'";
543 if ($fldvalue) {
544 echo " checked";
546 echo " />\n";
547 } elseif ($fldtype == GlobalSetting::DATA_TYPE_NUMBER) {
548 if ($userMode) {
549 $globalTitle = $globalValue;
551 echo " <input type='text' class='form-control' name='form_$i' id='form_$i' " .
552 "maxlength='15' value='" . attr($fldvalue) . "' />\n";
553 } elseif ($fldtype == GlobalSetting::DATA_TYPE_TEXT) {
554 if ($userMode) {
555 $globalTitle = $globalValue;
557 echo " <input type='text' class='form-control' name='form_$i' id='form_$i' " .
558 "maxlength='255' value='" . attr($fldvalue) . "' />\n";
559 } elseif ($fldtype == GlobalSetting::DATA_TYPE_DEFAULT_RANDOM_UUID) {
560 if ($userMode) {
561 $globalTitle = $globalValue;
563 if (empty($fldvalue)) {
564 // if empty, then create a random uuid
565 $uuid4 = Uuid::uuid4();
566 $fldvalue = $uuid4->toString();
568 echo " <input type='text' class='form-control' name='form_$i' id='form_$i' " .
569 "maxlength='255' value='" . attr($fldvalue) . "' />\n";
570 } elseif (($fldtype == GlobalSetting::DATA_TYPE_ENCRYPTED) || ($fldtype == GlobalSetting::DATA_TYPE_ENCRYPTED_HASH)) {
571 if (empty($fldvalue)) {
572 // empty value
573 $fldvalueDecrypted = '';
574 } elseif ($cryptoGen->cryptCheckStandard($fldvalue)) {
575 // normal behavior when not empty
576 $fldvalueDecrypted = $cryptoGen->decryptStandard($fldvalue);
577 } else {
578 // this is used when value has not yet been encrypted (only happens once when upgrading)
579 $fldvalueDecrypted = $fldvalue;
581 echo " <input type='password' class='form-control' name='form_$i' id='form_$i' " .
582 "maxlength='255' value='" . attr($fldvalueDecrypted) . "' />\n";
583 if ($userMode) {
584 if (empty($globalValue)) {
585 // empty value
586 $globalTitle = '';
587 } elseif ($cryptoGen->cryptCheckStandard($globalValue)) {
588 // normal behavior when not empty
589 $globalTitle = $cryptoGen->decryptStandard($globalValue);
590 } else {
591 // this is used when value has not yet been encrypted (only happens once when upgrading)
592 $globalTitle = $globalValue;
595 $fldvalueDecrypted = '';
596 } elseif ($fldtype == GlobalSetting::DATA_TYPE_PASS) {
597 if ($userMode) {
598 $globalTitle = $globalValue;
600 echo " <input type='password' class='form-control' name='form_$i' " .
601 "maxlength='255' value='" . attr($fldvalue) . "' />\n";
602 } elseif ($fldtype == GlobalSetting::DATA_TYPE_LANGUAGE) {
603 $res = sqlStatement("SELECT * FROM lang_languages ORDER BY lang_description");
604 echo " <select class='form-control' name='form_$i' id='form_$i'>\n";
605 while ($row = sqlFetchArray($res)) {
606 echo " <option value='" . attr($row['lang_description']) . "'";
607 if ($row['lang_description'] == $fldvalue) {
608 echo " selected";
611 echo ">";
612 echo xlt($row['lang_description']);
613 echo "</option>\n";
616 echo " </select>\n";
617 } elseif ($fldtype == GlobalSetting::DATA_TYPE_CODE_TYPES) {
618 global $code_types;
619 echo " <select class='form-control' name='form_$i' id='form_$i'>\n";
620 foreach (array_keys($code_types) as $code_key) {
621 echo " <option value='" . attr($code_key) . "'";
622 if ($code_key == $fldvalue) {
623 echo " selected";
626 echo ">";
627 echo xlt($code_types[$code_key]['label']);
628 echo "</option>\n";
631 echo " </select>\n";
632 } elseif ($fldtype == GlobalSetting::DATA_TYPE_MULTI_LANGUAGE_SELECT) {
633 $res = sqlStatement("SELECT * FROM lang_languages ORDER BY lang_description");
634 echo " <select multiple class='form-control' name='form_{$i}[]' id='form_{$i}[]' size='3'>\n";
635 while ($row = sqlFetchArray($res)) {
636 echo " <option value='" . attr($row['lang_description']) . "'";
637 foreach ($glarr as $glrow) {
638 if ($glrow['gl_value'] == $row['lang_description']) {
639 echo " selected";
640 break;
643 echo ">";
644 echo xlt($row['lang_description']);
645 echo "</option>\n";
647 echo " </select>\n";
648 } elseif ($fldtype == GlobalSetting::DATA_TYPE_MULTI_DASHBOARD_CARDS) {
649 $hiddenList = [];
650 $ret = sqlStatement("SELECT gl_value FROM `globals` WHERE `gl_name` = 'hide_dashboard_cards'");
651 while ($row = sqlFetchArray($ret)) {
652 $hiddenList[] = $row['gl_value'];
654 // The list of cards to hide. For now add to array new cards.
655 $res = array(
656 ['card_abrev' => '', 'card_name' => xlt('None or Reset')],
657 ['card_abrev' => attr('card_allergies'), 'card_name' => xlt('Allergies')],
658 ['card_abrev' => attr('card_amendments'), 'card_name' => xlt('Amendments')],
659 ['card_abrev' => attr('card_disclosure'), 'card_name' => xlt('Disclosures')],
660 ['card_abrev' => attr('card_insurance'), 'card_name' => xlt('Insurance')],
661 ['card_abrev' => attr('card_lab'), 'card_name' => xlt('Labs')],
662 ['card_abrev' => attr('card_medicalproblems'), 'card_name' => xlt('Medical Problems')],
663 ['card_abrev' => attr('card_medication'), 'card_name' => xlt('Medications')],
664 ['card_abrev' => 'card_prescriptions', 'card_name' => 'Prescriptions'], // For now don't hide because can be disabled as feature.
665 ['card_abrev' => attr('card_vitals'), 'card_name' => xlt('Vitals')]
667 echo " <select multiple class='form-control' name='form_{$i}[]' id='form_{$i}[]' size='10'>\n";
668 foreach ($res as $row) {
669 echo " <option value='" . attr($row['card_abrev']) . "'";
670 foreach ($glarr as $glrow) {
671 if ($glrow['gl_value'] == $row['card_abrev']) {
672 echo " selected";
673 break;
676 echo ">";
677 echo xlt($row['card_name']);
678 echo "</option>\n";
680 echo " </select>\n";
681 } elseif ($fldtype == GlobalSetting::DATA_TYPE_COLOR_CODE) {
682 if ($userMode) {
683 $globalTitle = $globalValue;
685 echo " <input type='text' class='form-control jscolor {hash:true}' name='form_$i' id='form_$i' " .
686 "maxlength='15' value='" . attr($fldvalue) . "' />" .
687 "<input type='button' value='" . xla('Default') . "' onclick=\"document.forms[0].form_$i.jscolor.fromString(" . attr_js($flddef) . ")\">\n";
688 } elseif ($fldtype == GlobalSetting::DATA_TYPE_DEFAULT_VISIT_CATEGORY) {
689 $sql = "SELECT pc_catid, pc_catname, pc_cattype
690 FROM openemr_postcalendar_categories
691 WHERE pc_active = 1 ORDER BY pc_seq";
692 $result = sqlStatement($sql);
693 echo "<select class='form-control' name='form_{$i}' id='form_{$i}'>\n";
694 echo "<option value='_blank'>" . xlt('None{{Category}}') . "</option>";
695 while ($row = sqlFetchArray($result)) {
696 $catId = $row['pc_catid'];
697 $name = $row['pc_catname'];
698 if ($catId < 9 && $catId != "5") {
699 continue;
702 if ($row['pc_cattype'] == 3 && !$GLOBALS['enable_group_therapy']) {
703 continue;
706 $optionStr = '<option value="%pc_catid%"%selected%>%pc_catname%</option>';
707 $optionStr = str_replace("%pc_catid%", attr($catId), $optionStr);
708 $optionStr = str_replace("%pc_catname%", text(xl_appt_category($name)), $optionStr);
709 $selected = ($fldvalue == $catId) ? " selected" : "";
710 $optionStr = str_replace("%selected%", $selected, $optionStr);
711 echo $optionStr;
713 echo "</select>";
714 } elseif ($fldtype == GlobalSetting::DATA_TYPE_CSS || $fldtype == GlobalSetting::DATA_TYPE_TABS_CSS) {
715 if ($userMode) {
716 $globalTitle = $globalValue;
718 $themedir = "$webserver_root/public/themes";
719 $dh = opendir($themedir);
720 if ($dh) {
721 // Collect styles
722 $styleArray = array();
723 while (false !== ($tfname = readdir($dh))) {
724 // Only show files that contain tabs_style_ or style_ as options
725 if ($fldtype == 'tabs_css') {
726 $patternStyle = 'tabs_style_';
727 } else {
728 // $fldtype == 'css'
729 $patternStyle = 'style_';
731 if (
732 $tfname == 'style_blue.css' ||
733 $tfname == 'style_pdf.css' ||
734 !preg_match("/^" . $patternStyle . ".*\.css$/", $tfname)
736 continue;
739 if ($fldtype == GlobalSetting::DATA_TYPE_TABS_CSS) {
740 // Drop the "tabs_style_" part and any replace any underscores with spaces
741 $styleDisplayName = str_replace("_", " ", substr($tfname, 11));
742 } else { // $fldtype == 'css'
743 // Drop the "style_" part and any replace any underscores with spaces
744 $styleDisplayName = str_replace("_", " ", substr($tfname, 6));
746 // Strip the ".css" and uppercase the first character
747 $styleDisplayName = ucfirst(str_replace(".css", "", $styleDisplayName));
749 $styleArray[$tfname] = $styleDisplayName;
751 // Alphabetize styles
752 asort($styleArray);
753 // Generate style selector
754 echo "<select class='form-control' name='form_$i' id='form_$i'>\n";
755 foreach ($styleArray as $styleKey => $styleValue) {
756 echo "<option value='" . attr($styleKey) . "'";
757 if ($styleKey == $fldvalue) {
758 echo " selected";
760 echo ">";
761 echo text($styleValue);
762 echo "</option>\n";
764 echo "</select>\n";
766 closedir($dh);
767 } elseif ($fldtype == GlobalSetting::DATA_TYPE_HOUR) {
768 if ($userMode) {
769 $globalTitle = $globalValue;
772 echo " <select class='form-control' name='form_$i' id='form_$i'>\n";
773 for ($h = 0; $h < 24; ++$h) {
774 echo "<option value='$h'";
775 if ($h == $fldvalue) {
776 echo " selected";
779 echo ">";
780 if ($h == 0) {
781 echo "12 AM";
782 } elseif ($h < 12) {
783 echo "$h AM";
784 } elseif ($h == 12) {
785 echo "12 PM";
786 } else {
787 echo ($h - 12) . " PM";
790 echo "</option>\n";
793 echo " </select>\n";
794 } elseif ($fldtype == GlobalSetting::DATA_TYPE_MULTI_SORTED_LIST_SELECTOR) {
795 include 'templates/field_multi_sorted_list_selector.php';
796 } else if ($fldtype == GlobalSetting::DATA_TYPE_ADDRESS_BOOK) {
797 include 'templates/globals-address-book.php';
800 if ($userMode) {
801 echo " </div>\n";
802 echo "<div class='col-sm-2 text-danger'>" . text($globalTitle) . "</div>\n";
803 echo "<div class='col-sm-2 '><input type='checkbox' value='YES' name='toggle_" . $i . "' id='toggle_" . $i . "' " . $settingDefault . "/></div>\n";
804 if (($fldtype == 'encrypted') || ($fldtype == 'encrypted_hash')) {
805 echo "<input type='hidden' id='globaldefault_" . $i . "' value='" . attr($globalTitle) . "' />\n";
806 } else {
807 echo "<input type='hidden' id='globaldefault_" . $i . "' value='" . attr($globalValue) . "' />\n";
809 echo "</div>\n";
810 } else {
811 echo " </div></div>\n";
813 ++$i;
817 echo "<div class='btn-group oe-margin-b-10'>" .
818 "<button type='submit' class='btn btn-primary btn-save oe-pull-toward' name='form_save'" .
819 "value='" . xla('Save') . "'>" . xlt('Save') . "</button></div>";
820 echo "<div class='oe-pull-away oe-margin-t-10' style=''>" . xlt($grpname) . " &nbsp;<a href='#' class='text-dark text-decoration-none fa fa-lg fa-arrow-circle-up oe-help-redirect scroll' aria-hidden='true'></a></div><div class='clearfix'></div></div>";
821 echo " </div>\n";
825 </div><!--End of tabContainer div-->
826 </div><!--End of globals-div div-->
827 </form>
828 </div>
829 </div>
830 </div><!--End of container div-->
831 <?php $oemr_ui->oeBelowContainerDiv();?>
832 </div>
833 <?php
834 $post_srch_desc = $_POST['srch_desc'] ?? '';
835 if (!empty($post_srch_desc) && $srch_item == 0) {
836 echo "<script>alert(" . js_escape($post_srch_desc . " - " . xl('search term was not found, please try another search')) . ");</script>";
840 <script>
841 $(function () {
842 tabbify();
843 <?php // mdsupport - Highlight search results ?>
844 $('.srch div.control-label').wrapInner("<mark></mark>");
845 $('.tab .row.srch :first-child').closest('.tab').each(function() {
846 $('.tabNav li:nth-child(' + ($(this).index() + 1) + ') a').wrapInner("<mark></mark>");
848 // Use the counter ($i) to make the form user friendly for user-specific globals use
849 <?php
850 if ($userMode) {
851 for ($j = 0; $j <= $i; $j++) { ?>
852 $("#form_<?php echo $j ?>").change(function() {
853 $("#toggle_<?php echo $j ?>").prop('checked', false);
855 $("#toggle_<?php echo $j ?>").change(function() {
856 if ($('#toggle_<?php echo $j ?>').prop('checked')) {
857 var defaultGlobal = $("#globaldefault_<?php echo $j ?>").val();
858 $("#form_<?php echo $j ?>").val(defaultGlobal);
861 <?php
865 $('#srch_desc').keypress(function (event) {
866 if (event.which === 13 || event.keyCode === 13) {
867 event.preventDefault();
868 $('#globals_form_search').click();
872 $('.scroll').click(function() {
873 if ($(window).scrollTop() == 0) {
874 alert(<?php echo xlj("Already at the top of the page"); ?>);
875 } else {
876 window.parent.scrollTo({
877 top: 0,
878 behavior: 'smooth',
880 window.scrollTo({
881 top: 0,
882 behavior: 'smooth',
885 return false;
887 </script>
888 </body>
889 </html>