3 * Script for the globals editor.
5 * Copyright (C) 2010 Rod Roark <rod@sunsetsystems.com>
6 * Copyright (C) 2016 Brady Miller <brady@sparmy.com>
8 * LICENSE: This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://opensource.org/licenses/gpl-license.php>;.
20 * @author Rod Roark <rod@sunsetsystems.com>
21 * @author Brady Miller <brady@sparmy.com>
22 * @link http://www.open-emr.org
25 $fake_register_globals=false;
26 $sanitize_all_escapes=true;
28 require_once("../globals.php");
29 require_once("../../custom/code_types.inc.php");
30 require_once("$srcdir/acl.inc");
31 require_once("$srcdir/formdata.inc.php");
32 require_once("$srcdir/globals.inc.php");
33 require_once("$srcdir/user.inc");
34 require_once("$srcdir/classes/CouchDB.class.php");
35 require_once(dirname(__FILE__
)."/../../myportal/soap_service/portal_connectivity.php");
37 $userMode = (array_key_exists('mode', $_GET) && $_GET['mode'] == 'user');
40 // Check authorization.
41 $thisauth = acl_check('admin', 'super');
42 if (!$thisauth) die(xlt('Not authorized'));
45 function checkCreateCDB(){
46 $globalsres = sqlStatement("SELECT gl_name, gl_index, gl_value FROM globals WHERE gl_name IN
47 ('couchdb_host','couchdb_user','couchdb_pass','couchdb_port','couchdb_dbase','document_storage_method')");
49 while($globalsrow = sqlFetchArray($globalsres)){
50 $GLOBALS[$globalsrow['gl_name']] = $globalsrow['gl_value'];
52 $directory_created = false;
53 if( !empty($GLOBALS['document_storage_method']) ) {
54 // /documents/temp/ folder is required for CouchDB
55 if(!is_dir($GLOBALS['OE_SITE_DIR'] . '/documents/temp/')){
56 $directory_created = mkdir($GLOBALS['OE_SITE_DIR'] . '/documents/temp/',0777,true);
57 if(!$directory_created){
58 echo htmlspecialchars( xl("Failed to create temporary folder. CouchDB will not work."),ENT_NOQUOTES
);
61 $couch = new CouchDB();
62 if(!$couch->check_connection()) {
63 echo "<script type='text/javascript'>alert('".addslashes(xl("CouchDB Connection Failed."))."');</script>";
66 if($GLOBALS['couchdb_host'] ||
$GLOBALS['couchdb_port'] ||
$GLOBALS['couchdb_dbase']){
67 $couch->createDB($GLOBALS['couchdb_dbase']);
68 $couch->createView($GLOBALS['couchdb_dbase']);
75 * Update background_services table for a specific service following globals save.
78 function updateBackgroundService($name,$active,$interval) {
79 //order important here: next_run change dependent on _old_ value of execute_interval so it comes first
80 $sql = 'UPDATE background_services SET active=?, '
81 . 'next_run = next_run + INTERVAL (? - execute_interval) MINUTE, execute_interval=? WHERE name=?';
82 return sqlStatement($sql,array($active,$interval,$interval,$name));
86 * Make any necessary changes to background_services table when globals are saved.
87 * To prevent an unexpected service call during startup or shutdown, follow these rules:
88 * 1. Any "startup" operations should occur _before_ the updateBackgroundService() call.
89 * 2. Any "shutdown" operations should occur _after_ the updateBackgroundService() call. If these operations
90 * would cause errors in a running service call, it would be best to make the shutdown function itself
91 * a background service that is activated here, does nothing if active=1 or running=1 for the
92 * parent service, then deactivates itself by setting active=0 when it is done shutting the parent service
93 * down. This will prevent nonresponsiveness to the user by waiting for a service to finish.
94 * 3. If any "previous" values for globals are required for startup/shutdown logic, they need to be
95 * copied to a temp variable before the while($globalsrow...) loop.
98 function checkBackgroundServices(){
99 //load up any necessary globals
100 $bgservices = sqlStatement("SELECT gl_name, gl_index, gl_value FROM globals WHERE gl_name IN
101 ('phimail_enable','phimail_interval')");
102 while($globalsrow = sqlFetchArray($bgservices)){
103 $GLOBALS[$globalsrow['gl_name']] = $globalsrow['gl_value'];
106 //Set up phimail service
107 $phimail_active = empty($GLOBALS['phimail_enable']) ?
'0' : '1';
108 $phimail_interval = max(0, (int) $GLOBALS['phimail_interval']);
109 updateBackgroundService('phimail', $phimail_active, $phimail_interval);
120 // If we are saving user_specific globals.
122 if (array_key_exists('form_save', $_POST) && $_POST['form_save'] && $userMode) {
124 foreach ($GLOBALS_METADATA as $grpname => $grparr) {
125 if (in_array($grpname, $USER_SPECIFIC_TABS)) {
126 foreach ($grparr as $fldid => $fldarr) {
127 if (in_array($fldid, $USER_SPECIFIC_GLOBALS)) {
128 list($fldname, $fldtype, $flddef, $flddesc) = $fldarr;
129 $label = "global:".$fldid;
130 $fldvalue = trim($_POST["form_$i"]);
131 setUserSetting($label,$fldvalue,$_SESSION['authId'],FALSE);
132 if ( $_POST["toggle_$i"] == "YES" ) {
133 removeUserSetting($label);
140 echo "<script type='text/javascript'>";
141 echo "parent.left_nav.location.reload();";
142 echo "parent.Title.location.reload();";
143 echo "if(self.name=='RTop'){";
144 echo "parent.RBot.location.reload();";
146 echo "parent.RTop.location.reload();";
148 echo "self.location.href='edit_globals.php?mode=user&unique=yes';";
152 if (array_key_exists('form_download', $_POST) && $_POST['form_download']) {
153 $client = portal_connection();
155 $response = $client->getPortalConnectionFiles($credentials);
158 error_log('SoapFault Error');
159 error_log(var_dump(get_object_vars($e)));
162 error_log('Exception Error');
163 error_log(var_dump(get_object_vars($e)));
165 if(array_key_exists('status', $response) && $response['status'] == "1") {//WEBSERVICE RETURNED VALUE SUCCESSFULLY
166 $tmpfilename = realpath(sys_get_temp_dir())."/".date('YmdHis').".zip";
167 $fp = fopen($tmpfilename,"wb");
168 fwrite($fp,base64_decode($response['value']));
170 $practice_filename = $response['file_name'];//practicename.zip
173 header("Cache-Control: public");
174 header("Content-Description: File Transfer");
175 header("Content-Disposition: attachment; filename=".$practice_filename);
176 header("Content-Type: application/zip");
177 header("Content-Transfer-Encoding: binary");
178 // Read the file from disk
179 readfile($tmpfilename);
180 unlink($tmpfilename);
183 else{//WEBSERVICE CALL FAILED AND RETURNED AN ERROR MESSAGE
186 <script type
="text/javascript">
187 alert('<?php echo xls('Offsite Portal web Service Failed
').":\\n".text($response['value
']);?>');
197 // If we are saving main globals.
199 if (array_key_exists('form_save', $_POST) && $_POST['form_save'] && !$userMode) {
200 $force_off_enable_auditlog_encryption = true;
201 // Need to force enable_auditlog_encryption off if the php mycrypt module
203 if (extension_loaded('mcrypt')) {
204 $force_off_enable_auditlog_encryption = false;
207 // Aug 22, 2014: Ensoftek: For Auditable events and tamper-resistance (MU2)
208 // Check the current status of Audit Logging
209 $auditLogStatusFieldOld = $GLOBALS['enable_auditlog'];
212 * Compare form values with old database values.
213 * Only save if values differ. Improves speed.
216 // Get all the globals from DB
217 $old_globals = sqlGetAssoc( 'SELECT gl_name, gl_index, gl_value FROM `globals` ORDER BY gl_name, gl_index',false,true );
220 foreach ($GLOBALS_METADATA as $grpname => $grparr) {
221 foreach ($grparr as $fldid => $fldarr) {
222 list($fldname, $fldtype, $flddef, $flddesc) = $fldarr;
223 if($fldtype == 'pwd'){
224 $pass = sqlQuery("SELECT gl_value FROM globals WHERE gl_name = ?", array($fldid) );
225 $fldvalueold = $pass['gl_value'];
228 /* Multiple choice fields - do not compare , overwrite */
229 if (!is_array($fldtype) && substr($fldtype, 0, 2) == 'm_') {
230 if (isset($_POST["form_$i"])) {
233 sqlStatement("DELETE FROM globals WHERE gl_name = ?", array( $fldid ) );
235 foreach ($_POST["form_$i"] as $fldvalue) {
236 $fldvalue = trim($fldvalue);
237 sqlStatement('INSERT INTO `globals` ( gl_name, gl_index, gl_value ) VALUES ( ?,?,?)', array( $fldid, $fldindex, $fldvalue ) );
243 /* check value of single field. Don't update if the database holds the same value */
244 if (isset($_POST["form_$i"])) {
245 $fldvalue = trim($_POST["form_$i"]);
250 if($fldtype=='pwd') $fldvalue = $fldvalue ?
SHA1($fldvalue) : $fldvalueold; // TODO: salted passwords?
252 // We rely on the fact that set of keys in globals.inc === set of keys in `globals` table!
255 !isset( $old_globals[$fldid]) // if the key not found in database - update database
257 ( isset($old_globals[$fldid]) && $old_globals[ $fldid ]['gl_value'] !== $fldvalue ) // if the value in database is different
259 // Need to force enable_auditlog_encryption off if the php mcrypt module
261 if ( $force_off_enable_auditlog_encryption && ($fldid == "enable_auditlog_encryption") ) {
262 error_log("OPENEMR ERROR: UNABLE to support auditlog encryption since the php mcrypt module is not installed",0);
265 // special treatment for some vars
267 case 'first_day_week':
268 // update PostCalendar config as well
269 sqlStatement("UPDATE openemr_module_vars SET pn_value = ? WHERE pn_name = 'pcFirstDayOfWeek'", array($fldvalue));
272 // Replace old values
273 sqlStatement( 'DELETE FROM `globals` WHERE gl_name = ?', array( $fldid ) );
274 sqlStatement( 'INSERT INTO `globals` ( gl_name, gl_index, gl_value ) VALUES ( ?, ?, ? )', array( $fldid, 0, $fldvalue ) );
276 //error_log("No need to update $fldid");
283 checkBackgroundServices();
285 // July 1, 2014: Ensoftek: For Auditable events and tamper-resistance (MU2)
286 // If Audit Logging status has changed, log it.
287 $auditLogStatusNew = sqlQuery("SELECT gl_value FROM globals WHERE gl_name = 'enable_auditlog'");
288 $auditLogStatusFieldNew = $auditLogStatusNew['gl_value'];
289 if ( $auditLogStatusFieldOld != $auditLogStatusFieldNew )
291 auditSQLAuditTamper($auditLogStatusFieldNew);
293 echo "<script type='text/javascript'>";
294 echo "parent.left_nav.location.reload();";
295 echo "parent.Title.location.reload();";
296 echo "if(self.name=='RTop'){";
297 echo "parent.RBot.location.reload();";
299 echo "parent.RTop.location.reload();";
301 echo "self.location.href='edit_globals.php?unique=yes';";
306 <!-- supporting javascript code
-->
307 <script type
="text/javascript" src
="../../library/dialog.js"></script
>
308 <script type
="text/javascript" src
="../../library/js/jquery.1.3.2.js"></script
>
309 <script type
="text/javascript" src
="../../library/js/common.js"></script
>
310 <script type
="text/javascript" src
="../../library/js/fancybox/jquery.fancybox-1.2.6.js"></script
>
311 <script type
="text/javascript" src
="<?php echo $GLOBALS['assets_static_relative']; ?>/jscolor-1-4-5/jscolor.js"></script
>
312 <link rel
="stylesheet" type
="text/css" href
="../../library/js/fancybox/jquery.fancybox-1.2.6.css" media
="screen" />
314 <link rel
="stylesheet" href
='<?php echo $css_header ?>' type
='text/css'>
315 <?php
if ($userMode) { ?
>
316 <title
><?php
echo xlt('User Settings'); ?
></title
>
318 <title
><?php
echo xlt('Global Settings'); ?
></title
>
322 tr
.head
{ font
-size
:10pt
; background
-color
:#cccccc; text-align:center; }
323 tr
.detail
{ font
-size
:10pt
; }
324 td
{ font
-size
:10pt
; }
325 input
{ font
-size
:10pt
; }
327 <script type
="text/javascript">
328 function validate_file(){
331 url
: "<?php echo $GLOBALS['webroot']?>/library/ajax/offsite_portal_ajax.php",
333 action
: 'check_file',
336 success
: function( message
)
339 document
.getElementById('form_download').value
= 1;
340 document
.getElementById('file_error_message').innerHTML
= '';
341 document
.forms
[0].submit();
344 document
.getElementById('form_download').value
= 0;
345 document
.getElementById('file_error_message').innerHTML
= message
;
354 <body
class="body_top">
356 <?php
if ($userMode) { ?
>
357 <form method
='post' name
='theform' id
='theform' action
='edit_globals.php?mode=user' onsubmit
='return top.restoreSession()'>
359 <form method
='post' name
='theform' id
='theform' action
='edit_globals.php' onsubmit
='return top.restoreSession()'>
362 <?php
if ($userMode) { ?
>
363 <p
><b
><?php
echo xlt('Edit User Settings'); ?
></b
>
365 <p
><b
><?php
echo xlt('Edit Global Settings'); ?
></b
>
371 foreach ($GLOBALS_METADATA as $grpname => $grparr) {
372 if ( !$userMode ||
in_array($grpname, $USER_SPECIFIC_TABS) ) {
373 echo " <li" . ($i ?
"" : " class='current'") .
375 xlt($grpname) . "</a></li>\n";
382 <div
class="tabContainer">
385 foreach ($GLOBALS_METADATA as $grpname => $grparr) {
386 if ( !$userMode ||
in_array($grpname, $USER_SPECIFIC_TABS) ) {
387 echo " <div class='tab" . ($i ?
"" : " current") .
388 "' style='height:auto;width:97%;'>\n";
394 echo "<th> </th>";
395 echo "<th>" . htmlspecialchars( xl('User Specific Setting'), ENT_NOQUOTES
) . "</th>";
396 echo "<th>" . htmlspecialchars( xl('Default Setting'), ENT_NOQUOTES
) . "</th>";
397 echo "<th> </th>";
398 echo "<th>" . htmlspecialchars( xl('Set to Default'), ENT_NOQUOTES
) . "</th>";
402 foreach ($grparr as $fldid => $fldarr) {
403 if ( !$userMode ||
in_array($fldid, $USER_SPECIFIC_GLOBALS) ) {
404 list($fldname, $fldtype, $flddef, $flddesc) = $fldarr;
406 // Most parameters will have a single value, but some will be arrays.
407 // Here we cater to both possibilities.
408 $glres = sqlStatement("SELECT gl_index, gl_value FROM globals WHERE " .
409 "gl_name = ? ORDER BY gl_index", array($fldid));
411 while ($glrow = sqlFetchArray($glres)) $glarr[] = $glrow;
413 // $fldvalue is meaningful only for the single-value cases.
414 $fldvalue = count($glarr) ?
$glarr[0]['gl_value'] : $flddef;
416 // Collect user specific setting if mode set to user
418 $settingDefault = "checked='checked'";
420 $userSettingArray = sqlQuery("SELECT * FROM user_settings WHERE setting_user=? AND setting_label=?",array($_SESSION['authId'],"global:".$fldid));
421 $userSetting = $userSettingArray['setting_value'];
422 $globalValue = $fldvalue;
423 if (!empty($userSettingArray)) {
424 $fldvalue = $userSetting;
425 $settingDefault = "";
429 echo " <tr title='" . attr($flddesc) . "'><td valign='top'><b>" . text($fldname) . "</b></td><td valign='top'>\n";
431 if (is_array($fldtype)) {
432 echo " <select name='form_$i' id='form_$i'>\n";
433 foreach ($fldtype as $key => $value) {
435 if ($globalValue == $key) $globalTitle = $value;
437 echo " <option value='" . attr($key) . "'";
439 //Casting value to string so the comparison will be always the same type and the only thing that will check is the value
440 //Tried to use === but it will fail in already existing variables
441 if ((string)$key == (string)$fldvalue) echo " selected";
449 else if ($fldtype == 'bool') {
451 if ($globalValue == 1) {
452 $globalTitle = htmlspecialchars( xl('Checked'), ENT_NOQUOTES
);
455 $globalTitle = htmlspecialchars( xl('Not Checked'), ENT_NOQUOTES
);
458 echo " <input type='checkbox' name='form_$i' id='form_$i' value='1'";
459 if ($fldvalue) echo " checked";
463 else if ($fldtype == 'num') {
465 $globalTitle = $globalValue;
467 echo " <input type='text' name='form_$i' id='form_$i' " .
468 "size='6' maxlength='15' value='" . attr($fldvalue) . "' />\n";
471 else if ($fldtype == 'text') {
473 $globalTitle = $globalValue;
475 echo " <input type='text' name='form_$i' id='form_$i' " .
476 "size='50' maxlength='255' value='" . attr($fldvalue) . "' />\n";
478 else if ($fldtype == 'pwd') {
480 $globalTitle = $globalValue;
482 echo " <input type='password' name='form_$i' " .
483 "size='50' maxlength='255' value='' />\n";
486 else if ($fldtype == 'pass') {
488 $globalTitle = $globalValue;
490 echo " <input type='password' name='form_$i' " .
491 "size='50' maxlength='255' value='" . attr($fldvalue) . "' />\n";
494 else if ($fldtype == 'lang') {
495 $res = sqlStatement("SELECT * FROM lang_languages ORDER BY lang_description");
496 echo " <select name='form_$i' id='form_$i'>\n";
497 while ($row = sqlFetchArray($res)) {
498 echo " <option value='" . attr($row['lang_description']) . "'";
499 if ($row['lang_description'] == $fldvalue) echo " selected";
501 echo xlt($row['lang_description']);
507 else if ($fldtype == 'all_code_types') {
509 echo " <select name='form_$i' id='form_$i'>\n";
510 foreach (array_keys($code_types) as $code_key ) {
511 echo " <option value='" . attr($code_key) . "'";
512 if ($code_key == $fldvalue) echo " selected";
514 echo xlt($code_types[$code_key]['label']);
520 else if ($fldtype == 'm_lang') {
521 $res = sqlStatement("SELECT * FROM lang_languages ORDER BY lang_description");
522 echo " <select multiple name='form_{$i}[]' id='form_{$i}[]' size='3'>\n";
523 while ($row = sqlFetchArray($res)) {
524 echo " <option value='" . attr($row['lang_description']) . "'";
525 foreach ($glarr as $glrow) {
526 if ($glrow['gl_value'] == $row['lang_description']) {
532 echo xlt($row['lang_description']);
538 else if ($fldtype == 'color_code') {
540 $globalTitle = $globalValue;
542 echo " <input type='text' class='color {hash:true}' name='form_$i' id='form_$i' " .
543 "size='6' maxlength='15' value='" . attr($fldvalue) . "' />" .
544 "<input type='button' value='Default' onclick=\"document.forms[0].form_$i.color.fromString('" . attr($flddef) . "')\">\n";
547 else if ($fldtype == 'css') {
549 $globalTitle = $globalValue;
551 $themedir = "$webserver_root/interface/themes";
552 $dh = opendir($themedir);
554 echo " <select name='form_$i' id='form_$i'>\n";
555 while (false !== ($tfname = readdir($dh))) {
556 // Only show files that contain style_ as options
557 // Skip style_blue.css since this is used for
558 // lone scripts such as setup.php
559 // Also skip style_pdf.css which is for PDFs and not screen output
560 if (!preg_match("/^style_.*\.css$/", $tfname) ||
561 $tfname == 'style_blue.css' ||
$tfname == 'style_pdf.css')
563 echo "<option value='" . attr($tfname) . "'";
564 // Drop the "style_" part and any replace any underscores with spaces
565 $styleDisplayName = str_replace("_", " ", substr($tfname, 6));
566 // Strip the ".css" and uppercase the first character
567 $styleDisplayName = ucfirst(str_replace(".css", "", $styleDisplayName));
568 if ($tfname == $fldvalue) echo " selected";
570 echo text($styleDisplayName);
578 else if ($fldtype == 'hour') {
580 $globalTitle = $globalValue;
582 echo " <select name='form_$i' id='form_$i'>\n";
583 for ($h = 0; $h < 24; ++
$h) {
584 echo "<option value='$h'";
585 if ($h == $fldvalue) echo " selected";
587 if ($h == 0) echo "12 AM";
588 else if ($h < 12) echo "$h AM";
589 else if ($h == 12) echo "12 PM";
590 else echo ($h - 12) . " PM";
597 echo "<td align='center' style='color:red;'>" . attr($globalTitle) . "</td>\n";
598 echo "<td> </td>";
599 echo "<td align='center'><input type='checkbox' value='YES' name='toggle_" . $i . "' id='toggle_" . $i . "' " . attr($settingDefault) . "/></td>\n";
600 echo "<input type='hidden' id='globaldefault_" . $i . "' value='" . attr($globalValue) . "'>\n";
604 echo " </td></tr>\n";
608 if( trim(strtolower($fldid)) == 'portal_offsite_address_patient_link' && !empty($GLOBALS['portal_offsite_enable']) && !empty($GLOBALS['portal_offsite_providerid']) ){
609 echo "<input type='hidden' name='form_download' id='form_download'>";
610 echo "<tr><td><input onclick=\"return validate_file()\" type='button' value='".xla('Download Offsite Portal Connection Files')."' /></td><td id='file_error_message' style='color:red'></td></tr>";
621 <input type
='submit' name
='form_save' value
='<?php echo xla('Save
'); ?>' />
629 <script language
="JavaScript">
631 $
(document
).ready(function(){
635 // Use the counter ($i) to make the form user friendly for user-specific globals use
636 <?php
if ($userMode) { ?
>
637 <?php
for ($j = 0; $j <= $i; $j++
) { ?
>
638 $
("#form_<?php echo $j ?>").change(function() {
639 $
("#toggle_<?php echo $j ?>").attr('checked',false);
641 $
("#toggle_<?php echo $j ?>").change(function() {
642 if ($
('#toggle_<?php echo $j ?>').attr('checked')) {
643 var defaultGlobal
= $
("#globaldefault_<?php echo $j ?>").val();
644 $
("#form_<?php echo $j ?>").val(defaultGlobal
);